+/**
+ * Response handler for update owner information request.
+ *
+ * @param[in] ctx ctx value passed to callback from calling function.
+ * @param[in] UNUSED handle to an invocation
+ * @param[in] clientResponse Response from queries to remote servers.
+ * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
+ * and OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult OwnershipInformationHandler(void *ctx, OCDoHandle UNUSED,
+ OCClientResponse *clientResponse)
+{
+ VERIFY_NON_NULL(TAG, clientResponse, WARNING);
+ VERIFY_NON_NULL(TAG, ctx, WARNING);
+
+ OIC_LOG(DEBUG, TAG, "IN OwnershipInformationHandler");
+ (void)UNUSED;
+ OCStackResult res = OC_STACK_OK;
+ OTMContext_t* otmCtx = (OTMContext_t*)ctx;
+ otmCtx->ocDoHandle = NULL;
+
+ if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
+ {
+ if(otmCtx && otmCtx->selectedDeviceInfo)
+ {
+ OIC_LOG(INFO, TAG, "Ownership transfer was successfully completed.");
+ OIC_LOG(INFO, TAG, "Set Ready for provisioning state .");
+
+ res = PostProvisioningStatus(otmCtx);
+ if(OC_STACK_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to update pstat");
+ SetResult(otmCtx, res);
+ }
+ }
+ }
+ else
+ {
+ res = clientResponse->result;
+ OIC_LOG_V(ERROR, TAG, "OwnershipInformationHandler : Unexpected result %d", res);
+ SetResult(otmCtx, res);
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT OwnershipInformationHandler");
+
+exit:
+ return OC_STACK_DELETE_TRANSACTION;
+}
+
+/**
+ * Response handler of update provisioning status.
+ *
+ * @param[in] ctx ctx value passed to callback from calling function.
+ * @param[in] UNUSED handle to an invocation
+ * @param[in] clientResponse Response from queries to remote servers.
+ * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
+ * and OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult ProvisioningStatusHandler(void *ctx, OCDoHandle UNUSED,
+ OCClientResponse *clientResponse)
+{
+ OIC_LOG_V(INFO, TAG, "IN ProvisioningStatusHandler.");
+
+ VERIFY_NON_NULL(TAG, clientResponse, ERROR);
+ VERIFY_NON_NULL(TAG, ctx, ERROR);
+
+ OTMContext_t* otmCtx = (OTMContext_t*) ctx;
+ otmCtx->ocDoHandle = NULL;
+ (void)UNUSED;
+ OCStackResult res = OC_STACK_OK;
+
+ if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
+ {
+ if(otmCtx && otmCtx->selectedDeviceInfo)
+ {
+ OIC_LOG(INFO, TAG, "Device state is in Ready for Provisionig.");
+
+ res = PostNormalOperationStatus(otmCtx);
+ if(OC_STACK_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to update pstat");
+ SetResult(otmCtx, res);
+ }
+ }
+ }
+ else
+ {
+ OIC_LOG_V(INFO, TAG, "Error occured in provisionDefaultACLCB :: %d\n",
+ clientResponse->result);
+ SetResult(otmCtx, clientResponse->result);
+ }
+
+exit:
+ OIC_LOG_V(INFO, TAG, "OUT ProvisioningStatusHandler.");
+ return OC_STACK_DELETE_TRANSACTION;
+}
+
+/**
+ * Response handler of update provisioning status to Ready for Normal..
+ *
+ * @param[in] ctx ctx value passed to callback from calling function.
+ * @param[in] UNUSED handle to an invocation
+ * @param[in] clientResponse Response from queries to remote servers.
+ * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
+ * and OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult ReadyForNomalStatusHandler(void *ctx, OCDoHandle UNUSED,
+ OCClientResponse *clientResponse)
+{
+ OIC_LOG_V(INFO, TAG, "IN ReadyForNomalStatusHandler.");
+
+ VERIFY_NON_NULL(TAG, clientResponse, ERROR);
+ VERIFY_NON_NULL(TAG, ctx, ERROR);
+
+ OTMContext_t* otmCtx = (OTMContext_t*) ctx;
+ otmCtx->ocDoHandle = NULL;
+ (void)UNUSED;
+
+ if (OC_STACK_RESOURCE_CHANGED == clientResponse->result)
+ {
+ OIC_LOG(INFO, TAG, "Device state is in Ready for Normal Operation.");
+ OCStackResult res = PDMSetDeviceState(&otmCtx->selectedDeviceInfo->doxm->deviceID,
+ PDM_DEVICE_ACTIVE);
+ if (OC_STACK_OK == res)
+ {
+ OIC_LOG_V(INFO, TAG, "Add device's UUID in PDM_DB");
+ SetResult(otmCtx, OC_STACK_OK);
+ return OC_STACK_DELETE_TRANSACTION;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Ownership transfer is complete but adding information to DB is failed.");
+ }
+ }
+ else
+ {
+ OIC_LOG_V(INFO, TAG, "Error occured in provisionDefaultACLCB :: %d\n",
+ clientResponse->result);
+ SetResult(otmCtx, clientResponse->result);
+ }
+
+exit:
+ OIC_LOG_V(INFO, TAG, "OUT ReadyForNomalStatusHandler.");
+ return OC_STACK_DELETE_TRANSACTION;
+}
+
+static OCStackResult PostOwnerCredential(OTMContext_t* otmCtx)
+{
+ OIC_LOG(DEBUG, TAG, "IN PostOwnerCredential");
+
+ if(!otmCtx || !otmCtx->selectedDeviceInfo)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid parameters");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
+ char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+
+ if(!PMGenerateQuery(true,
+ deviceInfo->endpoint.addr, deviceInfo->securePort,
+ deviceInfo->connType,
+ query, sizeof(query), OIC_RSRC_CRED_URI))
+ {
+ OIC_LOG(ERROR, TAG, "PostOwnerCredential : Failed to generate query");
+ return OC_STACK_ERROR;
+ }
+ OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+ OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+ if(!secPayload)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+ return OC_STACK_NO_MEMORY;
+ }
+
+ //Generate owner credential for new device
+ secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+ const OicSecCred_t* ownerCredential = GetCredResourceData(&(deviceInfo->doxm->deviceID));
+ if(!ownerCredential)
+ {
+ OIC_LOG(ERROR, TAG, "Can not find OwnerPSK.");
+ return OC_STACK_NO_RESOURCE;
+ }
+
+ OicUuid_t credSubjectId = {.id={0}};
+ if(OC_STACK_OK == GetDoxmDeviceID(&credSubjectId))
+ {
+ OicSecCred_t newCredential;
+ memcpy(&newCredential, ownerCredential, sizeof(OicSecCred_t));
+ newCredential.next = NULL;
+
+ //Set subject ID as PT's ID
+ memcpy(&(newCredential.subject), &credSubjectId, sizeof(OicUuid_t));
+
+ //Fill private data as empty string
+ newCredential.privateData.data = (uint8_t*)"";
+ newCredential.privateData.len = 0;
+ newCredential.privateData.encoding = ownerCredential->privateData.encoding;
+
+ newCredential.publicData.data = NULL;
+ newCredential.publicData.len = 0;
+ newCredential.publicData.encoding = ownerCredential->publicData.encoding;
+
+ int secureFlag = 0;
+ //Send owner credential to new device : POST /oic/sec/cred [ owner credential ]
+ if (OC_STACK_OK != CredToCBORPayload(&newCredential, &secPayload->securityData,
+ &secPayload->payloadSize, secureFlag))
+ {
+ OICFree(secPayload);
+ OIC_LOG(ERROR, TAG, "Error while converting bin to cbor.");
+ return OC_STACK_ERROR;
+ }
+ OIC_LOG(DEBUG, TAG, "Cred Payload:");
+ OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+
+ OCCallbackData cbData;
+ cbData.cb = &OwnerCredentialHandler;
+ cbData.context = (void *)otmCtx;
+ cbData.cd = NULL;
+ OCStackResult res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query,
+ &deviceInfo->endpoint, (OCPayload*)secPayload,
+ deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG(ERROR, TAG, "OCStack resource error");
+ }
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Failed to read DOXM device ID.");
+ return OC_STACK_NO_RESOURCE;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT PostOwnerCredential");
+
+ return OC_STACK_OK;
+}
+
+static OicSecAcl_t* GenerateOwnerAcl(const OicUuid_t* owner)
+{
+ OicSecAcl_t* ownerAcl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
+ OicSecAce_t* ownerAce = (OicSecAce_t*)OICCalloc(1, sizeof(OicSecAce_t));
+ OicSecRsrc_t* wildcardRsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
+ if(NULL == ownerAcl || NULL == ownerAce || NULL == wildcardRsrc)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+ goto error;
+ }
+ LL_APPEND(ownerAcl->aces, ownerAce);
+ LL_APPEND(ownerAce->resources, wildcardRsrc);
+
+ //Set resource owner as PT
+ memcpy(ownerAcl->rownerID.id, owner->id, sizeof(owner->id));
+
+ //PT has full permission.
+ ownerAce->permission = PERMISSION_FULL_CONTROL;
+
+ //Set subject as PT's UUID
+ memcpy(ownerAce->subjectuuid.id, owner->id, sizeof(owner->id));
+
+ wildcardRsrc->href = OICStrdup(WILDCARD_RESOURCE_URI);
+ if(NULL == wildcardRsrc->href)
+ {
+ goto error;
+ }
+
+ wildcardRsrc->interfaceLen = 1;
+ wildcardRsrc->interfaces = (char**)OICMalloc(wildcardRsrc->interfaceLen * sizeof(char*));
+ if(NULL == wildcardRsrc->interfaces)
+ {
+ goto error;
+ }
+ wildcardRsrc->interfaces[0] = OICStrdup(WILDCARD_RESOURCE_URI);
+ if(NULL == wildcardRsrc->interfaces[0])
+ {
+ goto error;
+ }
+
+ wildcardRsrc->typeLen = 1;
+ wildcardRsrc->types = (char**)OICMalloc(wildcardRsrc->typeLen * sizeof(char*));
+ if(NULL == wildcardRsrc->types)
+ {
+ goto error;
+ }
+ wildcardRsrc->types[0] = OICStrdup(WILDCARD_RESOURCE_URI);
+ if(NULL == wildcardRsrc->types[0])
+ {
+ goto error;
+ }
+
+ return ownerAcl;
+
+error:
+ //in case of memory allocation failed, each resource should be removed individually.
+ if(NULL == ownerAcl || NULL == ownerAce || NULL == wildcardRsrc)
+ {
+ OICFree(ownerAcl);
+ OICFree(ownerAce);
+ OICFree(wildcardRsrc);
+ }
+ else
+ {
+ DeleteACLList(ownerAcl);
+ }
+ return NULL;
+}
+
+/**
+ * Function to update the owner ACL to new device.
+ *
+ * @param[in] otmCtx Context value of ownership transfer.
+ * @return OC_STACK_OK on success
+ */
+static OCStackResult PostOwnerAcl(OTMContext_t* otmCtx)
+{
+ OCStackResult res = OC_STACK_ERROR;
+
+ OIC_LOG(DEBUG, TAG, "IN PostOwnerAcl");
+
+ if(!otmCtx || !otmCtx->selectedDeviceInfo)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid parameters");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
+ char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+ OicSecAcl_t* ownerAcl = NULL;
+
+ if(!PMGenerateQuery(true,
+ deviceInfo->endpoint.addr, deviceInfo->securePort,
+ deviceInfo->connType,
+ query, sizeof(query), OIC_RSRC_ACL_URI))
+ {
+ OIC_LOG(ERROR, TAG, "Failed to generate query");
+ return OC_STACK_ERROR;
+ }
+ OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+ OicUuid_t ownerID;
+ res = GetDoxmDeviceID(&ownerID);
+ if(OC_STACK_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to generate owner ACL");
+ return res;
+ }
+
+ //Generate owner ACL for new device
+ ownerAcl = GenerateOwnerAcl(&ownerID);
+ if(NULL == ownerAcl)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to generate owner ACL");
+ return OC_STACK_NO_MEMORY;
+ }
+
+ //Generate ACL payload
+ OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+ if(!secPayload)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+ res = OC_STACK_NO_MEMORY;
+ goto error;
+ }
+
+ res = AclToCBORPayload(ownerAcl, &secPayload->securityData, &secPayload->payloadSize);
+ if (OC_STACK_OK != res)
+ {
+ OICFree(secPayload);
+ OIC_LOG(ERROR, TAG, "Error while converting bin to cbor.");
+ goto error;
+ }
+ secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+
+ OIC_LOG(DEBUG, TAG, "Owner ACL Payload:");
+ OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+
+ //Send owner ACL to new device : POST /oic/sec/cred [ owner credential ]
+ OCCallbackData cbData;
+ cbData.cb = &OwnerAclHandler;
+ cbData.context = (void *)otmCtx;
+ cbData.cd = NULL;
+ res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query,
+ &deviceInfo->endpoint, (OCPayload*)secPayload,
+ deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG(ERROR, TAG, "OCStack resource error");
+ goto error;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT PostOwnerAcl");
+
+error:
+ DeleteACLList(ownerAcl);
+
+ return OC_STACK_OK;
+}
+
+static OCStackResult PostOwnerTransferModeToResource(OTMContext_t* otmCtx)