1 /* *****************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
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 "ocprovisioningmanager.h"
26 #include "secureresourceprovider.h"
28 #include "oic_malloc.h"
29 #include "aclresource.h"
30 #include "pstatresource.h"
31 #include "srmresourcestrings.h"
32 #include "credresource.h"
33 #include "doxmresource.h"
34 #include "credentialgenerator.h"
35 #include "cainterface.h"
38 #include "pmutility.h"
39 #include "provisioningdatabasemanager.h"
46 * Macro to verify argument is not equal to NULL.
47 * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR);
49 #define VERIFY_NON_NULL(tag, arg, logLevel, retValue) { if (NULL == (arg)) \
50 { OC_LOG((logLevel), tag, (#arg " is NULL")); return retValue; } }
53 * Macro to verify success of operation.
54 * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR);
56 #define VERIFY_SUCCESS(tag, op, logLevel, retValue) { if (!(op)) \
57 {OC_LOG((logLevel), tag, (#op " failed!!")); return retValue;} }
60 * Structure to carry credential data to callback.
62 typedef struct CredentialData CredentialData_t;
65 void *ctx; /**< Pointer to user context.**/
66 const OCProvisionDev_t *deviceInfo1; /**< Pointer to OCProvisionDev_t.**/
67 const OCProvisionDev_t *deviceInfo2; /**< Pointer to OCProvisionDev_t.**/
68 OicSecCred_t *credInfo; /**< Pointer to OicSecCred_t.**/
69 OicSecCred_t *credInfoFirst; /**< Pointer to OicSecCred_t.**/
70 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
71 OCProvisionResult_t *resArr; /**< Result array.**/
72 int numOfResults; /**< Number of results in result array.**/
76 * Structure to carry ACL provision API data to callback.
78 typedef struct ACLData ACLData_t;
81 void *ctx; /**< Pointer to user context.**/
82 const OCProvisionDev_t *deviceInfo; /**< Pointer to PMDevInfo_t.**/
83 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
84 OCProvisionResult_t *resArr; /**< Result array.**/
85 int numOfResults; /**< Number of results in result array.**/
88 // Enum type index for unlink callback.
90 IDX_FIRST_DEVICE_RES = 0, // index for resulf of the first device
91 IDX_SECOND_DEVICE_RES, // index for result of the second device
92 IDX_DB_UPDATE_RES // index for result of updating provisioning database.
95 // Structure to carry unlink APIs data to callback.
96 typedef struct UnlinkData UnlinkData_t;
99 OCProvisionDev_t* unlinkDev; /**< Pointer to OCProvisionDev_t to be unlinked.**/
100 OCProvisionResult_t* unlinkRes; /**< Result array.**/
101 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
102 int numOfResults; /**< Number of results in result array.**/
105 //Example of DELETE cred request -> coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
106 const char * SRP_FORM_DELETE_CREDENTIAL = "coaps://[%s]:%d%s?%s=%s";
108 // Structure to carry remove APIs data to callback.
109 typedef struct RemoveData RemoveData_t;
112 OCProvisionDev_t* revokeTargetDev; /**< Device which is going to be revoked..**/
113 OCProvisionDev_t* linkedDevList; /**< A list of devices which have invalid credential.**/
114 OCProvisionResult_t* removeRes; /**< Result array.**/
115 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
116 size_t numOfResults; /**< Number of results in result array.**/
117 size_t sizeOfResArray;
124 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
125 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
126 OCClientResponseHandler responseHandler);
130 * Internal function to update result in result array.
132 static void registerResultForCredProvisioning(CredentialData_t *credData,
133 OCStackResult stackresult, int cause)
136 OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
139 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
140 credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH);
144 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
145 credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH);
147 credData->resArr[(credData->numOfResults)].res = stackresult;
148 ++(credData->numOfResults);
152 * Callback handler for handling callback of provisioning device 2.
154 * @param[in] ctx ctx value passed to callback from calling function.
155 * @param[in] UNUSED handle to an invocation
156 * @param[in] clientResponse Response from queries to remote servers.
157 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
158 * and OC_STACK_KEEP_TRANSACTION to keep it.
160 static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNUSED,
161 OCClientResponse *clientResponse)
163 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
164 CredentialData_t *credData = (CredentialData_t *) ctx;
167 OCProvisionResultCB resultCallback = credData->resultCallback;
168 OC_LOG(INFO, TAG, "provisionCredentialCB2 called");
171 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
173 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED, 2);
174 OCStackResult res = PDMLinkDevices(&credData->deviceInfo1->doxm->deviceID,
175 &credData->deviceInfo2->doxm->deviceID);
176 if (OC_STACK_OK != res)
178 OC_LOG(ERROR, TAG, "Error occured on PDMLinkDevices");
179 return OC_STACK_DELETE_TRANSACTION;
181 OC_LOG(INFO, TAG, "Link created successfully");
183 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
186 OICFree(credData->resArr);
188 return OC_STACK_DELETE_TRANSACTION;
192 OC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
193 registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2);
194 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
197 OICFree(credData->resArr);
199 return OC_STACK_DELETE_TRANSACTION;
203 * Callback handler for handling callback of provisioning device 1.
205 * @param[in] ctx ctx value passed to callback from calling function.
206 * @param[in] UNUSED handle to an invocation
207 * @param[in] clientResponse Response from queries to remote servers.
208 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
209 * and OC_STACK_KEEP_TRANSACTION to keep it.
211 static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNUSED,
212 OCClientResponse *clientResponse)
214 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
216 CredentialData_t* credData = (CredentialData_t*) ctx;
217 OICFree(credData->credInfoFirst);
218 const OCProvisionDev_t *deviceInfo = credData->deviceInfo2;
219 OicSecCred_t *credInfo = credData->credInfo;
220 const OCProvisionResultCB resultCallback = credData->resultCallback;
223 if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
225 // send credentials to second device
226 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1);
227 OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
228 provisionCredentialCB2);
229 DeleteCredList(credInfo);
230 if (OC_STACK_OK != res)
232 registerResultForCredProvisioning(credData, res,2);
233 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
236 OICFree(credData->resArr);
243 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
244 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
247 OICFree(credData->resArr);
254 OC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
255 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
256 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
259 DeleteCredList(credInfo);
260 OICFree(credData->resArr);
264 return OC_STACK_DELETE_TRANSACTION;
270 * Internal function for handling credential generation and sending credential to resource server.
272 * @param[in] cred Instance of cred resource.
273 * @param[in] deviceInfo information about device to which credential is to be provisioned.
274 * @param[in] responseHandler callbak called by OC stack when request API receives response.
275 * @return OC_STACK_OK in case of success and other value otherwise.
277 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
278 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
279 OCClientResponseHandler responseHandler)
281 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
284 OC_LOG(ERROR, TAG, "Failed to memory allocation");
285 return OC_STACK_NO_MEMORY;
287 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
288 secPayload->securityData = BinToCredJSON(cred);
289 if(NULL == secPayload->securityData)
292 OC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
293 return OC_STACK_NO_MEMORY;
296 OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
297 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
298 if(!PMGenerateQuery(true,
299 deviceInfo->endpoint.addr,
300 deviceInfo->securePort,
301 deviceInfo->connType,
302 query, sizeof(query), OIC_RSRC_CRED_URI))
304 OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
305 return OC_STACK_ERROR;
307 OC_LOG_V(DEBUG, TAG, "Query=%s", query);
309 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
310 cbData.cb = responseHandler;
311 cbData.context = (void *) credData;
314 OCDoHandle handle = NULL;
315 OCMethod method = OC_REST_POST;
316 OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
317 deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
318 OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
319 if (ret != OC_STACK_OK)
321 OC_LOG(ERROR, TAG, "OCStack resource error");
327 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
328 const OCProvisionDev_t *pDev1,
329 const OCProvisionDev_t *pDev2,
330 OCProvisionResultCB resultCallback)
332 VERIFY_NON_NULL(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM);
333 VERIFY_NON_NULL(TAG, pDev2, ERROR, OC_STACK_INVALID_PARAM);
334 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
336 if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
338 OC_LOG(INFO, TAG, "Invalid key size");
339 return OC_STACK_INVALID_PARAM;
342 OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
344 OicUuid_t provTooldeviceID = {{0,}};
345 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
347 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
348 return OC_STACK_ERROR;
350 OC_LOG(INFO, TAG, "retrieved deviceid");
353 case SYMMETRIC_PAIR_WISE_KEY:
355 const OCProvisionDev_t *firstDevice = pDev1;
356 const OCProvisionDev_t *secondDevice = pDev2;
358 OicSecCred_t *firstCred = NULL;
359 OicSecCred_t *secondCred = NULL;
360 OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
361 &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
362 &firstCred, &secondCred);
363 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
364 OC_LOG(INFO, TAG, "Credentials generated successfully");
365 CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
366 if (NULL == credData)
368 OC_LOG(ERROR, TAG, "Memory allocation problem");
369 return OC_STACK_NO_MEMORY;
371 memset(credData, 0x00, sizeof(CredentialData_t));
372 credData->deviceInfo1 = firstDevice;
373 credData->deviceInfo2 = secondDevice;
374 credData->credInfo = secondCred;
376 credData->credInfoFirst = firstCred;
377 credData->numOfResults = 0;
378 credData->resultCallback = resultCallback;
379 // first call to provision creds to device1.
380 // second call to provision creds to device2.
383 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
384 if (NULL == credData->resArr)
386 OC_LOG(ERROR, TAG, "Memory allocation problem");
387 return OC_STACK_NO_MEMORY;
389 memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
390 res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
391 if (OC_STACK_OK != res)
393 DeleteCredList(firstCred);
394 DeleteCredList(secondCred);
395 OICFree(credData->resArr);
398 OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
399 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
404 OC_LOG(ERROR, TAG, "Invalid option.");
405 return OC_STACK_INVALID_PARAM;
408 return OC_STACK_ERROR;
412 * Internal Function to store results in result array during ACL provisioning.
414 static void registerResultForACLProvisioning(ACLData_t *aclData,
415 OCStackResult stackresult)
417 OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
418 aclData->numOfResults);
419 memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
420 aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
421 aclData->resArr[(aclData->numOfResults)].res = stackresult;
422 ++(aclData->numOfResults);
426 * Callback handler of SRPProvisionACL.
428 * @param[in] ctx ctx value passed to callback from calling function.
429 * @param[in] UNUSED handle to an invocation
430 * @param[in] clientResponse Response from queries to remote servers.
431 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
432 * and OC_STACK_KEEP_TRANSACTION to keep it.
434 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
435 OCClientResponse *clientResponse)
437 OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
439 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
440 ACLData_t *aclData = (ACLData_t*)ctx;
441 OCProvisionResultCB resultCallback = aclData->resultCallback;
445 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
447 registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
448 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
451 OICFree(aclData->resArr);
453 return OC_STACK_DELETE_TRANSACTION;
456 registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
457 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
460 OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
461 OICFree(aclData->resArr);
463 return OC_STACK_DELETE_TRANSACTION;
466 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
467 OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
469 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
470 VERIFY_NON_NULL(TAG, acl, ERROR, OC_STACK_INVALID_PARAM);
471 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
473 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
476 OC_LOG(ERROR, TAG, "Failed to memory allocation");
477 return OC_STACK_NO_MEMORY;
479 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
480 secPayload->securityData = BinToAclJSON(acl);
481 if(NULL == secPayload->securityData)
484 OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
485 return OC_STACK_NO_MEMORY;
487 OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
489 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
490 if(!PMGenerateQuery(true,
491 selectedDeviceInfo->endpoint.addr,
492 selectedDeviceInfo->securePort,
493 selectedDeviceInfo->connType,
494 query, sizeof(query), OIC_RSRC_ACL_URI))
496 OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
497 return OC_STACK_ERROR;
499 OC_LOG_V(DEBUG, TAG, "Query=%s", query);
501 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
502 cbData.cb = &SRPProvisionACLCB;
503 ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
507 OC_LOG(ERROR, TAG, "Unable to allocate memory");
508 return OC_STACK_NO_MEMORY;
510 memset(aclData, 0x00, sizeof(ACLData_t));
511 aclData->deviceInfo = selectedDeviceInfo;
512 aclData->resultCallback = resultCallback;
513 aclData->numOfResults=0;
515 // call to provision ACL to device1.
517 aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
518 if (aclData->resArr == NULL)
521 OC_LOG(ERROR, TAG, "Unable to allocate memory");
522 return OC_STACK_NO_MEMORY;
524 memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
525 cbData.context = (void *)aclData;
527 OCMethod method = OC_REST_POST;
528 OCDoHandle handle = NULL;
529 OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
530 OCStackResult ret = OCDoResource(&handle, method, query,
531 &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
532 selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
533 if (ret != OC_STACK_OK)
535 OICFree(aclData->resArr);
538 VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
542 static void DeleteUnlinkData_t(UnlinkData_t *unlinkData)
546 OICFree(unlinkData->unlinkDev);
547 OICFree(unlinkData->unlinkRes);
552 static void registerResultForUnlinkDevices(UnlinkData_t *unlinkData, OCStackResult stackresult,
555 if (NULL != unlinkData)
557 OC_LOG_V(INFO, TAG, "Inside registerResultForUnlinkDevices unlinkData->numOfResults is %d\n",
558 unlinkData->numOfResults);
559 OC_LOG_V(INFO, TAG, "Stack result :: %d", stackresult);
561 OicUuid_t *pUuid = &unlinkData->unlinkRes[(unlinkData->numOfResults)].deviceId;
563 // Set result in the result array according to the position (devNum).
564 if (idx != IDX_DB_UPDATE_RES)
566 memcpy(pUuid->id, unlinkData->unlinkDev[idx].doxm->deviceID.id, sizeof(pUuid->id));
569 { // When deivce ID is 000... this means it's the result of database update.
570 memset(pUuid->id, 0, sizeof(pUuid->id));
572 unlinkData->unlinkRes[(unlinkData->numOfResults)].res = stackresult;
573 ++(unlinkData->numOfResults);
574 OC_LOG (INFO, TAG, "Out registerResultForUnlinkDevices");
578 static OCStackResult SendDeleteCredentialRequest(void* ctx,
579 OCClientResponseHandler respHandler,
580 const OCProvisionDev_t* revokedDev,
581 const OCProvisionDev_t* destDev)
583 OC_LOG(DEBUG, TAG, "IN SendDeleteCredentialRequest");
585 if (NULL == ctx || NULL == respHandler || NULL == revokedDev || NULL == destDev)
587 return OC_STACK_INVALID_PARAM;
590 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(revokedDev->doxm->deviceID.id)) + 1] = {};
591 uint32_t base64Len = 0;
592 if (B64_OK != b64Encode(revokedDev->doxm->deviceID.id, sizeof(revokedDev->doxm->deviceID.id),
593 base64Buff, sizeof(base64Buff), &base64Len))
595 OC_LOG(ERROR, TAG, "SendDeleteCredentialRequest : Failed to base64 encoding");
596 return OC_STACK_ERROR;
599 char reqBuf[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
601 //coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
602 snRet = snprintf(reqBuf, sizeof(reqBuf), SRP_FORM_DELETE_CREDENTIAL, destDev->endpoint.addr,
603 destDev->securePort, OIC_RSRC_CRED_URI, OIC_JSON_SUBJECT_NAME, base64Buff);
606 OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error (snprintf) %d\n", snRet);
607 return OC_STACK_ERROR;
609 else if ((size_t)snRet >= sizeof(reqBuf))
611 OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Truncated (snprintf) %d\n", snRet);
612 return OC_STACK_ERROR;
615 OCCallbackData cbData;
616 memset(&cbData, 0, sizeof(cbData));
617 cbData.context = ctx;
618 cbData.cb = respHandler;
620 OC_LOG_V(INFO, TAG, "URI: %s",reqBuf);
622 OC_LOG(DEBUG, TAG, "Sending remove credential request to resource server");
624 OCStackResult ret = OCDoResource(NULL, OC_REST_DELETE, reqBuf,
625 &destDev->endpoint, NULL,
626 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
627 if (OC_STACK_OK != ret)
629 OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error in OCDoResource %d", ret);
631 OC_LOG(DEBUG, TAG, "OUT SendDeleteCredentialRequest");
637 * Callback handler of unlink second device.
639 * @param[in] ctx ctx value passed to callback from calling function.
640 * @param[in] handle handle to an invocation
641 * @param[in] clientResponse Response from queries to remote servers.
642 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction and
643 * OC_STACK_KEEP_TRANSACTION to keep it.
645 static OCStackApplicationResult SRPUnlinkDevice2CB(void *unlinkCtx, OCDoHandle handle,
646 OCClientResponse *clientResponse)
649 OC_LOG(DEBUG, TAG, "IN SRPUnlinkDevice2CB");
650 VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
651 UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
655 OC_LOG(DEBUG, TAG, "Valid client response for device 2");
656 registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_SECOND_DEVICE_RES);
658 if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
660 OC_LOG(DEBUG, TAG, "Credential of device2 revoked");
664 OC_LOG(ERROR, TAG, "Unable to delete credential information from device 2");
665 unlinkData->resultCallback(unlinkData->ctx,
666 unlinkData->numOfResults, unlinkData->unlinkRes, true);
672 registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
673 IDX_SECOND_DEVICE_RES);
674 unlinkData->resultCallback(unlinkData->ctx,
675 unlinkData->numOfResults, unlinkData->unlinkRes, true);
676 OC_LOG(ERROR, TAG, "SRPUnlinkDevice2CB received Null clientResponse");
680 //Update provisioning DB when succes case.
681 if (OC_STACK_OK != PDMUnlinkDevices(&unlinkData->unlinkDev[0].doxm->deviceID,
682 &unlinkData->unlinkDev[1].doxm->deviceID))
684 OC_LOG(FATAL, TAG, "All requests are successfully done but update provisioning DB FAILED.");
685 registerResultForUnlinkDevices(unlinkData, OC_STACK_INCONSISTENT_DB, IDX_DB_UPDATE_RES);
686 unlinkData->resultCallback(unlinkData->ctx,
687 unlinkData->numOfResults, unlinkData->unlinkRes, true);
690 unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults, unlinkData->unlinkRes,
694 DeleteUnlinkData_t(unlinkData);
695 OC_LOG(DEBUG, TAG, "OUT SRPUnlinkDevice2CB");
696 return OC_STACK_DELETE_TRANSACTION;
701 * Callback handler of unlink first device.
703 * @param[in] ctx ctx value passed to callback from calling function.
704 * @param[in] handle handle to an invocation
705 * @param[in] clientResponse Response from queries to remote servers.
706 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction and
707 * OC_STACK_KEEP_TRANSACTION to keep it.
709 static OCStackApplicationResult SRPUnlinkDevice1CB(void *unlinkCtx, OCDoHandle handle,
710 OCClientResponse *clientResponse)
712 OC_LOG_V(INFO, TAG, "Inside SRPUnlinkDevice1CB ");
713 VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
714 UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
719 OC_LOG(DEBUG, TAG, "Valid client response for device 1");
720 registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_FIRST_DEVICE_RES);
722 if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
724 OC_LOG(DEBUG, TAG, "Credential of device 1 is revoked");
726 // Second revocation request to second device.
727 OCStackResult res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice2CB,
728 &unlinkData->unlinkDev[0],
729 &unlinkData->unlinkDev[1] /*Dest*/);
730 OC_LOG_V(DEBUG, TAG, "Credential revocation request device 2, result :: %d",res);
731 if (OC_STACK_OK != res)
733 OC_LOG(ERROR, TAG, "Error while sending revocation request for device 2");
734 registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
735 IDX_SECOND_DEVICE_RES);
736 unlinkData->resultCallback(unlinkData->ctx,
737 unlinkData->numOfResults, unlinkData->unlinkRes, true);
742 OC_LOG(DEBUG, TAG, "Request for credential revocation successfully sent");
743 return OC_STACK_DELETE_TRANSACTION;
748 OC_LOG(ERROR, TAG, "Unable to delete credential information from device 1");
750 unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults,
751 unlinkData->unlinkRes, true);
757 OC_LOG(DEBUG, TAG, "Invalid response from server");
758 registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
759 IDX_FIRST_DEVICE_RES );
760 unlinkData->resultCallback(unlinkData->ctx,
761 unlinkData->numOfResults, unlinkData->unlinkRes,
763 OC_LOG(ERROR, TAG, "SRPUnlinkDevice1CB received Null clientResponse");
767 OC_LOG_V(INFO, TAG, "Out SRPUnlinkDevice1CB");
768 DeleteUnlinkData_t(unlinkData);
769 return OC_STACK_DELETE_TRANSACTION;
773 * Function to unlink devices.
774 * This function will remove the credential & relationship between the two devices.
776 * @param[in] ctx Application context would be returned in result callback
777 * @param[in] pTargetDev1 first device information to be unlinked.
778 * @param[in] pTargetDev2 second device information to be unlinked.
779 * @param[in] resultCallback callback provided by API user, callback will be called when
780 * device unlink is finished.
781 * @return OC_STACK_OK in case of success and other value otherwise.
783 OCStackResult SRPUnlinkDevices(void* ctx,
784 const OCProvisionDev_t* pTargetDev1,
785 const OCProvisionDev_t* pTargetDev2,
786 OCProvisionResultCB resultCallback)
788 OC_LOG(INFO, TAG, "IN SRPUnlinkDevices");
790 if (!pTargetDev1 || !pTargetDev2 || !resultCallback)
792 OC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL parameters");
793 return OC_STACK_INVALID_PARAM;
795 OC_LOG(INFO, TAG, "Unlinking following devices: ");
796 PMPrintOCProvisionDev(pTargetDev1);
797 PMPrintOCProvisionDev(pTargetDev2);
799 // Mark the link status stale
800 OCStackResult res = PDMSetLinkStale(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID);
801 if (OC_STACK_OK != res)
803 OC_LOG(FATAL, TAG, "unable to update DB. Try again.");
807 UnlinkData_t* unlinkData = (UnlinkData_t*)OICCalloc(1, sizeof(UnlinkData_t));
808 VERIFY_NON_NULL(TAG, unlinkData, ERROR, OC_STACK_NO_MEMORY);
810 //Initialize unlink data
811 unlinkData->ctx = ctx;
812 unlinkData->unlinkDev = (OCProvisionDev_t*)OICCalloc(2, sizeof(OCProvisionDev_t));
813 if (NULL == unlinkData->unlinkDev)
815 OC_LOG(ERROR, TAG, "Memory allocation failed");
816 res = OC_STACK_NO_MEMORY;
820 unlinkData->unlinkRes = (OCProvisionResult_t*)OICCalloc(3, sizeof(OCProvisionResult_t));
821 if (NULL == unlinkData->unlinkRes)
823 OC_LOG(ERROR, TAG, "Memory allocation failed");
824 res = OC_STACK_NO_MEMORY;
828 memcpy(&unlinkData->unlinkDev[0], pTargetDev1, sizeof(OCProvisionDev_t));
829 memcpy(&unlinkData->unlinkDev[1], pTargetDev2, sizeof(OCProvisionDev_t));
831 unlinkData->numOfResults = 0;
832 unlinkData->resultCallback = resultCallback;
834 res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice1CB,
835 &unlinkData->unlinkDev[1], &unlinkData->unlinkDev[0]);
836 if (OC_STACK_OK != res)
838 OC_LOG(ERROR, TAG, "SRPUnlinkDevices : SendDeleteCredentialRequest failed");
845 OC_LOG(INFO, TAG, "OUT SRPUnlinkDevices");
846 DeleteUnlinkData_t(unlinkData);
850 static void DeleteRemoveData_t(RemoveData_t* pRemoveData)
854 OICFree(pRemoveData->revokeTargetDev);
855 OCDeleteDiscoveredDevices(pRemoveData->linkedDevList);
856 OICFree(pRemoveData->removeRes);
857 OICFree(pRemoveData);
861 static void registerResultForRemoveDevice(RemoveData_t *removeData, OicUuid_t *pLinkedDevId,
862 OCStackResult stackresult, bool hasError)
864 OC_LOG_V(INFO, TAG, "Inside registerResultForRemoveDevice removeData->numOfResults is %d\n",
865 removeData->numOfResults + 1);
868 memcpy(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
869 &pLinkedDevId->id, sizeof(pLinkedDevId->id));
873 memset(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
874 0, sizeof(pLinkedDevId->id) );
876 removeData->removeRes[(removeData->numOfResults)].res = stackresult;
877 removeData->hasError = hasError;
878 ++(removeData->numOfResults);
880 // If we get suffcient result from linked devices, we have to call user callback and do free
881 if (removeData->sizeOfResArray == removeData->numOfResults)
883 removeData->resultCallback(removeData->ctx, removeData->numOfResults, removeData->removeRes,
884 removeData->hasError);
885 DeleteRemoveData_t(removeData);
890 * Callback handler of unlink first device.
892 * @param[in] ctx ctx value passed to callback from calling function.
893 * @param[in] handle handle to an invocation
894 * @param[in] clientResponse Response from queries to remote servers.
895 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
896 * and OC_STACK_KEEP_TRANSACTION to keep it.
898 static OCStackApplicationResult SRPRemoveDeviceCB(void *delDevCtx, OCDoHandle handle,
899 OCClientResponse *clientResponse)
901 //Update the delete credential into delete device context
902 //Save the deleted status in delDevCtx
904 OC_LOG_V(INFO, TAG, "Inside SRPRemoveDeviceCB.");
905 VERIFY_NON_NULL(TAG, delDevCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
906 OCStackResult res = OC_STACK_ERROR;
908 RemoveData_t* removeData = (RemoveData_t*)delDevCtx;
911 // If we can get device's UUID from OCClientResponse, it'd be good to use it in here
912 // but OCIdentity in OCClientResponse is emtpy now.
913 // It seems that we can set identity to CAData_t *cadata in CAPrepareSendData() API
914 // but CA doesn't have deviceID yet.
916 //TODO: Get OCIdentity from OCClientResponse and use it for 'registerResultForRemoveDevice'
917 // If we can't complete this task, Provisioning Database has always stale link status
918 // when Remove device is called.
920 if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
922 res = PDMUnlinkDevices(&removeData->revokeTargetDev->doxm->deviceID,
923 NULL /*TODO: Replace NULL to uuid from OCClientResponse*/);
924 if (OC_STACK_OK != res)
926 OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
927 registerResultForRemoveDevice(removeData,
928 NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
929 OC_STACK_INCONSISTENT_DB, true);
930 return OC_STACK_DELETE_TRANSACTION;
932 registerResultForRemoveDevice(removeData,
933 NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
934 OC_STACK_RESOURCE_DELETED, false);
938 registerResultForRemoveDevice(removeData,
939 NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
940 clientResponse->result, true);
941 OC_LOG(ERROR, TAG, "Unexpected result from DELETE credential request!");
946 registerResultForRemoveDevice(removeData, NULL, OC_STACK_ERROR, true);
947 OC_LOG(ERROR, TAG, "SRPRemoveDevices received Null clientResponse");
950 return OC_STACK_DELETE_TRANSACTION;
953 static OCStackResult GetListofDevToReqDeleteCred(const OCProvisionDev_t* pRevokeTargetDev,
954 OCProvisionDev_t* pOwnedDevList,
955 OCUuidList_t* pLinkedUuidList,
956 OCProvisionDev_t** ppLinkedDevList,
957 size_t *numOfLinkedDev)
959 // pOwnedDevList could be NULL. It means no alived and owned device now.
960 if (pRevokeTargetDev == NULL || pLinkedUuidList == NULL ||\
961 ppLinkedDevList == NULL || numOfLinkedDev == NULL)
963 return OC_STACK_INVALID_PARAM;
967 OCUuidList_t *curUuid = NULL, *tmpUuid = NULL;
968 LL_FOREACH_SAFE(pLinkedUuidList, curUuid, tmpUuid)
970 // Mark the link status stale.
971 OCStackResult res = PDMSetLinkStale(&curUuid->dev, &pRevokeTargetDev->doxm->deviceID);
972 if (OC_STACK_OK != res)
974 OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
975 return OC_STACK_INCONSISTENT_DB;
980 // If this linked device is alive (power-on), add the deivce to the list.
981 OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
982 LL_FOREACH_SAFE(pOwnedDevList, curDev, tmpDev)
984 if (memcmp(curDev->doxm->deviceID.id, curUuid->dev.id, sizeof(curUuid->dev.id)) == 0)
986 OCProvisionDev_t* targetDev = PMCloneOCProvisionDev(curDev);
987 if (NULL == targetDev)
989 OC_LOG(ERROR, TAG, "SRPRemoveDevice : Cloning OCProvisionDev_t Failed.");
990 return OC_STACK_NO_MEMORY;
993 LL_PREPEND(*ppLinkedDevList, targetDev);
1000 *numOfLinkedDev = cnt;
1005 * Function to device revocation
1006 * This function will remove credential of target device from all devices in subnet.
1008 * @param[in] ctx Application context would be returned in result callback
1009 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
1010 * @param[in] pTargetDev Device information to be revoked.
1011 * @param[in] resultCallback callback provided by API user, callback will be called when
1012 * credential revocation is finished.
1013 * @return OC_STACK_OK in case of success and other value otherwise.
1014 * If OC_STACK_OK is returned, the caller of this API should wait for callback.
1015 * OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
1017 OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
1018 const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback)
1020 OC_LOG(INFO, TAG, "IN SRPRemoveDevice");
1022 if (!pTargetDev || !resultCallback || 0 == waitTimeForOwnedDeviceDiscovery)
1024 OC_LOG(INFO, TAG, "SRPRemoveDevice : NULL parameters");
1025 return OC_STACK_INVALID_PARAM;
1028 // Declare variables in here to handle error cases with goto statement.
1029 OCProvisionDev_t* pOwnedDevList = NULL;
1030 OCProvisionDev_t* pLinkedDevList = NULL;
1031 RemoveData_t* removeData = NULL;
1033 //1. Find all devices that has a credential of the revoked device
1034 OCUuidList_t* pLinkedUuidList = NULL;
1035 size_t numOfDevices = 0;
1036 OCStackResult res = OC_STACK_ERROR;
1037 res = PDMGetLinkedDevices(&pTargetDev->doxm->deviceID, &pLinkedUuidList, &numOfDevices);
1038 if (OC_STACK_OK != res)
1040 OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to get linked devices information");
1043 // if there is no related device, we can skip further process.
1044 if (0 == numOfDevices)
1046 OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No linked device found.");
1047 res = OC_STACK_CONTINUE;
1051 //2. Find owned device from the network
1052 res = PMDeviceDiscovery(waitTimeForOwnedDeviceDiscovery, true, &pOwnedDevList);
1053 if (OC_STACK_OK != res)
1055 OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to PMDeviceDiscovery");
1059 //3. Make a list of devices to send DELETE credential request
1060 // by comparing owned devices from provisioning database with mutlicast discovery result.
1061 size_t numOfLinkedDev = 0;
1062 res = GetListofDevToReqDeleteCred(pTargetDev, pOwnedDevList, pLinkedUuidList,
1063 &pLinkedDevList, &numOfLinkedDev);
1064 if (OC_STACK_OK != res)
1066 OC_LOG(ERROR, TAG, "SRPRemoveDevice : GetListofDevToReqDeleteCred() failed");
1069 if (0 == numOfLinkedDev) // This case means, there is linked device but it's not alive now.
1070 { // So we don't have to send request message.
1071 OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No alived & linked device found.");
1072 res = OC_STACK_CONTINUE;
1076 // 4. Prepare RemoveData Context data.
1077 removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
1080 OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1081 res = OC_STACK_NO_MEMORY;
1085 removeData->revokeTargetDev = PMCloneOCProvisionDev(pTargetDev);
1086 if (!removeData->revokeTargetDev)
1088 OC_LOG(ERROR, TAG, "SRPRemoveDevices : PMCloneOCProvisionDev Failed");
1089 res = OC_STACK_NO_MEMORY;
1093 removeData->removeRes =
1094 (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t));
1095 if (!removeData->removeRes)
1097 OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1098 res = OC_STACK_NO_MEMORY;
1102 removeData->ctx = ctx;
1103 removeData->linkedDevList = pLinkedDevList;
1104 removeData->resultCallback = resultCallback;
1105 removeData->numOfResults = 0;
1106 removeData->sizeOfResArray = numOfLinkedDev;
1107 removeData->hasError = false;
1109 // 5. Send DELETE credential request to linked devices.
1110 OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
1111 OCStackResult totalRes = OC_STACK_ERROR; /* variable for checking request is sent or not */
1112 LL_FOREACH_SAFE(pLinkedDevList, curDev, tmpDev)
1114 res = SendDeleteCredentialRequest((void*)removeData, &SRPRemoveDeviceCB,
1115 removeData->revokeTargetDev, curDev);
1116 if (OC_STACK_OK != res)
1118 OC_LOG_V(ERROR, TAG, "SRPRemoveDevice : Fail to send the DELETE credential request to\
1119 %s:%u", curDev->endpoint.addr, curDev->endpoint.port);
1123 totalRes = OC_STACK_OK; // This means at least one request is successfully sent.
1127 PDMDestoryOicUuidLinkList(pLinkedUuidList); //TODO: Modify API name to have unified convention.
1128 PMDeleteDeviceList(pOwnedDevList);
1129 OC_LOG(INFO, TAG, "OUT SRPRemoveDevice");
1131 return totalRes; // Caller of this API should wait callback if totalRes == OC_STACK_OK.
1134 PDMDestoryOicUuidLinkList(pLinkedUuidList);
1135 PMDeleteDeviceList(pOwnedDevList);
1136 PMDeleteDeviceList(pLinkedDevList);
1139 OICFree(removeData->revokeTargetDev);
1140 OICFree(removeData->removeRes);
1141 OICFree(removeData);
1143 OC_LOG(INFO, TAG, "OUT ERROR case SRPRemoveDevice");