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 * *****************************************************************/
21 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1b, Real-time extensions
24 // (IEEE Std 1003.1b-1993) specification
26 // For this specific file, see use of clock_gettime,
27 // Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
28 // and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
30 #ifndef _POSIX_C_SOURCE
31 #define _POSIX_C_SOURCE 200809L
41 #include "oic_malloc.h"
44 #include "cainterface.h"
45 #include "provisioningmanager.h"
46 #include "credentialgenerator.h"
49 #include "aclresource.h"
50 #include "doxmresource.h"
51 #include "pstatresource.h"
52 #include "srmresourcestrings.h"
53 #include "credresource.h"
58 SP_DISCOVERY_STARTED = (0x1 << 1),
59 SP_DISCOVERY_ERROR = (0x1 << 2),
60 SP_DISCOVERY_DONE = (0x1 << 3),
61 SP_UP_OWN_TR_METH_STARTED = (0x1 << 4),
62 SP_UP_OWN_TR_METH_ERROR = (0x1 << 5),
63 SP_UP_OWN_TR_METH_DONE = (0x1 << 6),
64 SP_LIST_METHODS_STARTED = (0x1 << 7),
65 SP_LIST_METHODS_ERROR = (0x1 << 8),
66 SP_LIST_METHODS_DONE = (0x1 << 9),
67 SP_UPDATE_OP_MODE_STARTED = (0x1 << 10),
68 SP_UPDATE_OP_MODE_ERROR = (0x1 << 11),
69 SP_UPDATE_OP_MODE_DONE = (0x1 << 12),
70 SP_UPDATE_OWNER_STARTED = (0x1 << 13),
71 SP_UPDATE_OWNER_ERROR = (0x1 << 14),
72 SP_UPDATE_OWNER_DONE = (0x1 << 15),
73 SP_PROV_ACL_STARTED = (0x1 << 16),
74 SP_PROV_ACL_ERROR = (0x1 << 17),
75 SP_PROV_ACL_DONE = (0x1 << 18),
76 SP_UP_HASH_STARTED = (0x1 << 19),
77 SP_UP_HASH_ERROR = (0x1 << 20),
78 SP_UP_HASH_DONE = (0x1 << 21),
79 SP_PROV_CRED_STARTED = (0x1 << 22),
80 SP_PROV_CRED_ERROR = (0x1 << 23),
81 SP_PROV_CRED_DONE = (0x1 << 24)
83 } SPProvisioningStates;
85 #define SP_MAX_BUF_LEN 1024
86 #define TAG "SPProvisionAPI"
87 #define COAP_QUERY "coap://%s:%d%s"
88 #define COAPS_QUERY "coaps://%s:%d%s"
89 #define CA_SECURE_PORT 5684
91 void (*handler)(const CARemoteEndpoint_t *, const CAResponseInfo_t *);
94 * CA token to keep track of response.
96 static CAToken_t gToken = NULL;
99 * start pointer for discovered device linked list.
101 static SPTargetDeviceInfo_t *gStartOfDiscoveredDevices = NULL;
104 * current pointer of device linked list.
106 static SPTargetDeviceInfo_t *gCurrent = NULL;
109 * Variable to keep track of various request.
111 static uint32_t gStateManager = 0;
114 * Variable for storing provisioning tool's provisioning capabilities
115 * Must be in decreasing order of preference. More prefered method should
116 * have lower array index.
118 static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN };
121 * Number of supported provisioning methods
122 * current version supports only one.
124 static int gNumOfProvisioningMethodsPT = 1;
127 * Global variable to save pstat.
129 static OicSecPstat_t *gPstat = NULL;
132 * Secure String copy function
133 * @param[in] destination Pointer to destination string.
134 * @param[in] source Pointer to source string.
135 * @return pointer to destination string, NULL in case of error.
137 static inline char *SPStringCopy(char *destination, const char *source, size_t num)
139 if (strncpy(destination, source, num))
141 destination[num - 1] = '\0';
148 * Function to convert CA result code to SP result code.
150 * @return result code of SP corresponding to that of CA.
152 static SPResult convertCAResultToSPResult(CAResult_t caResult)
158 return SP_RESULT_SUCCESS;
160 case CA_STATUS_INVALID_PARAM:
162 return SP_RESULT_CONN_INVALID_PARAM;
164 case CA_ADAPTER_NOT_ENABLED:
166 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
168 case CA_SERVER_STARTED_ALREADY:
170 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
172 case CA_SERVER_NOT_STARTED:
174 return SP_RESULT_CONN_SERVER_NOT_STARTED;
176 case CA_DESTINATION_NOT_REACHABLE:
178 return SP_RESULT_CONN_DESTINATION_NOT_REACHABLE;
180 case CA_SOCKET_OPERATION_FAILED:
182 return SP_RESULT_CONN_SOCKET_OPERATION_FAILED;
186 return SP_RESULT_CONN_SEND_FAILED;
188 case CA_RECEIVE_FAILED:
190 return SP_RESULT_CONN_RECEIVE_FAILED;
192 case CA_MEMORY_ALLOC_FAILED:
194 return SP_RESULT_CONN_MEMORY_ALLOC_FAILED;
196 case CA_REQUEST_TIMEOUT:
198 return SP_RESULT_CONN_REQUEST_TIMEOUT;
200 case CA_DESTINATION_DISCONNECTED:
202 return SP_RESULT_CONN_DESTINATION_DISCONNECTED;
204 case CA_STATUS_FAILED:
206 return SP_RESULT_CONN_STATUS_FAILED;
208 case CA_NOT_SUPPORTED:
210 return SP_RESULT_CONN_NOT_SUPPORTED;
214 return SP_RESULT_INTERNAL_ERROR;
220 * Convert SP network types to CA network types,
222 * @param[in] connType connection type.
223 * @return CA connectivity type corresponding to SP connectivity type.
225 static CATransportType_t getConnectivity(SPConnectivityType connType)
254 * Convert CA network types to SP network types,
256 * @param[in] connType connection type.
257 * @return SPConnectitivty type corresponding to CATransportType_t.
259 static SPConnectivityType getConnectivitySP(CATransportType_t connType)
288 * Function to delete memory allocated to linked list.
291 static void deleteList()
293 SPTargetDeviceInfo_t *current = gStartOfDiscoveredDevices;
297 SPTargetDeviceInfo_t *next = current->next;
298 DeleteDoxmBinData(current->doxm);
299 DeletePstatBinData(current->pstat);
303 gStartOfDiscoveredDevices = NULL;
307 * Timeout implementation.
308 * @param[in] timeout Timeout in seconds. with 0 it will wait forever for success.
309 * @param[in] mask Mask of operation and 0 for no mask.
310 * @return SP_RESULT_SUCCESS on success otherwise error.
312 static SPResult SPTimeout(unsigned short timeout, uint32_t mask)
314 struct timespec startTime = {};
315 struct timespec currTime = {};
317 CAResult_t res = SP_RESULT_SUCCESS;
318 #ifdef _POSIX_MONOTONIC_CLOCK
319 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
321 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
325 return SP_RESULT_INTERNAL_ERROR;
327 while (CA_STATUS_OK == res)
329 res = CAHandleRequestResponse();
330 #ifdef _POSIX_MONOTONIC_CLOCK
331 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
333 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
337 return SP_RESULT_INTERNAL_ERROR;
339 long elapsed = (currTime.tv_sec - startTime.tv_sec);
340 if (SP_NO_MASK == mask)
342 if (elapsed > timeout)
344 return SP_RESULT_SUCCESS;
349 if (gStateManager & mask)
351 return SP_RESULT_SUCCESS;
353 if ((elapsed > timeout) && timeout)
355 return SP_RESULT_INTERNAL_ERROR;
359 return convertCAResultToSPResult(res);
363 * Function to send request to resource server.
364 * @param[in] uri Request URI.
365 * @param[in] payload Payload to be sent with data. NULL is case message
366 * doesn't have payload.
367 * @param[in] payloadLen Size of data to be sent.
368 * @param[in] token CA token.
369 * @param[in] method method to be used for sending rquest.
370 * @param[in] conntype Connectivity type.
371 * @return CA_STATUS_OK on success, otherwise error code.
373 static CAResult_t sendCARequest(CAURI_t uri, char *payload, int payloadLen,
374 CAToken_t token, CAMethod_t method, SPConnectivityType conntype)
376 CARemoteEndpoint_t *endpoint = NULL;
377 CATransportType_t caConnType = getConnectivity(conntype);
378 if (CA_STATUS_OK != CACreateRemoteEndpoint(uri, caConnType, &endpoint) || !endpoint)
380 OC_LOG(ERROR, TAG, "Failed to create remote endpoint");
381 CADestroyRemoteEndpoint(endpoint);
382 return CA_STATUS_FAILED;
384 CAMessageType_t msgType = CA_MSG_CONFIRM;
385 CAInfo_t requestData = { 0 };
386 requestData.token = token;
387 requestData.tokenLength = CA_MAX_TOKEN_LEN;
388 if (payload && '\0' != (*(payload + payloadLen)))
390 OC_LOG(ERROR, TAG, "Payload not properly terminated.");
391 CADestroyRemoteEndpoint(endpoint);
392 return CA_STATUS_INVALID_PARAM;
394 requestData.payload = payload;
395 requestData.type = msgType;
396 CARequestInfo_t requestInfo = { 0 };
397 requestInfo.method = method;
398 requestInfo.info = requestData;
399 CAResult_t caResult = CA_STATUS_OK;
400 caResult = CASendRequest(endpoint, &requestInfo);
401 if (CA_STATUS_OK != caResult)
403 OC_LOG(ERROR, TAG, "Send Request Error !!");
405 CADestroyRemoteEndpoint(endpoint);
412 * @param[in] ip IP of target device.
413 * @param[in] port port of remote server.
414 * @param[in] connType connectivity type of endpoint.
415 * @param[in] doxm pointer to doxm instance.
416 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
418 static SPResult addDevice(const char *ip, int port, SPConnectivityType connType, OicSecDoxm_t *doxm)
420 if (NULL == ip || 0 >= port)
422 return SP_RESULT_INVALID_PARAM;
424 SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *) OICCalloc(1, sizeof(SPTargetDeviceInfo_t));
427 OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
428 return SP_RESULT_MEM_ALLOCATION_FAIL;
431 SPStringCopy(ptr->ip, ip, sizeof(ptr->ip));
433 ptr->connType = connType;
439 if (NULL == gStartOfDiscoveredDevices)
441 gStartOfDiscoveredDevices = ptr;
446 gCurrent->next = ptr;
449 return SP_RESULT_SUCCESS;
453 * Function to provide timeframe in which response can be received.
455 * @param[in] timeout Timeout in seconds.
456 * @return SP_RESULT_SUCCESS on success , otherwise error code.
458 static SPResult SPWaitForResponse(unsigned short timeout)
460 return SPTimeout(timeout, SP_NO_MASK);
464 * Function to select appropriate provisioning method.
466 * @param[in] supportedMethodsList List of supported methods
467 * @param[out] selectedMethod Selected methods
468 * @return SP_SUCCESS on success
470 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
471 OicSecOxm_t *selectedMethod)
474 TODO Logic to find appropiate method and assign it to out param
475 for beachhead release method at index 0 will be returned.
477 *selectedMethod = supportedMethods[0];
478 return SP_RESULT_SUCCESS;
482 * Response handler for discovery.
484 * @param[in] object Remote endpoint object
485 * @param[in] requestInfo Datastructure containing request information.
487 static void ProvisionDiscoveryHandler(const CARemoteEndpoint_t *object,
488 const CAResponseInfo_t *responseInfo)
490 if ((gStateManager & SP_DISCOVERY_STARTED) && gToken)
492 // Response handler for discovery.
493 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
495 OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler.");
496 if (NULL == responseInfo->info.payload)
498 OC_LOG(INFO, TAG, "Skiping Null payload");
501 // temp logic for trimming oc attribute from the json.
502 // JSONToBin should handle oc attribute.
503 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
504 if (NULL == pTempPayload)
506 OC_LOG(ERROR, TAG, "Error while Memory allocation.");
507 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
511 strcpy(pTempPayload, responseInfo->info.payload + 8);
512 pTempPayload[strlen(pTempPayload) - 2] = '\0';
513 OC_LOG_V(DEBUG, TAG, "Trimmed payload: %s", pTempPayload);
514 OicSecDoxm_t *ptrDoxm = JSONToDoxmBin(pTempPayload);
518 OC_LOG(ERROR, TAG, "Error while converting doxm json to binary");
519 OICFree(pTempPayload);
520 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
523 OC_LOG(DEBUG, TAG, "Successfully converted pstat json to bin.");
524 OICFree(pTempPayload);
526 SPConnectivityType connType = getConnectivitySP(object->transportType);
527 SPResult res = addDevice(object->addressInfo.IP.ipAddress, object->addressInfo.IP.port,
529 if (SP_RESULT_SUCCESS != res)
531 OC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
532 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
533 DeleteDoxmBinData(ptrDoxm);
536 OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
537 gStateManager |= SP_DISCOVERY_DONE;
543 * Response handler ownership transfer.
545 * @param[in] object Remote endpoint object
546 * @param[in] requestInfo Datastructure containing request information.
548 static void OwnerShipTransferModeHandler(const CARemoteEndpoint_t *object,
549 const CAResponseInfo_t *responseInfo)
551 if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken)
553 // response handler for ownership tranfer
554 OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler.");
555 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
557 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result);
558 if (CA_SUCCESS == responseInfo->result)
560 gStateManager |= SP_UP_OWN_TR_METH_DONE;
561 OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler.");
565 gStateManager |= SP_UP_OWN_TR_METH_ERROR;
566 OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler.");
573 * Response handler list methods.
575 * @param[in] object Remote endpoint object
576 * @param[in] requestInfo Datastructure containing request information.
578 static void ListMethodsHandler(const CARemoteEndpoint_t *object,
579 const CAResponseInfo_t *responseInfo)
581 if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
583 OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
584 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
586 OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
587 if (CA_SUCCESS == responseInfo->result)
589 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
590 // Temp logic to trim oc attribute from json
591 // JSONToPstatBin should handle OC in JSON.
592 if (NULL == responseInfo->info.payload)
594 OC_LOG(ERROR, TAG, "response payload is null.");
595 gStateManager |= SP_LIST_METHODS_ERROR;
599 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
600 if (NULL == pTempPayload)
602 OC_LOG(ERROR, TAG, "Error in memory allocation.");
603 gStateManager |= SP_LIST_METHODS_ERROR;
607 strcpy(pTempPayload, responseInfo->info.payload + 8);
608 pTempPayload[strlen(pTempPayload) - 2] = '\0';
610 OicSecPstat_t *pstat = JSONToPstatBin(pTempPayload);
613 OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
614 OICFree(pTempPayload);
615 gStateManager |= SP_LIST_METHODS_ERROR;
618 OICFree(pTempPayload);
619 DeletePstatBinData(gPstat);
622 gStateManager |= SP_LIST_METHODS_DONE;
624 OC_LOG(INFO, TAG, "Exiting ListMethodsHandler.");
631 * Response handler for update operation mode.
633 * @param[in] object Remote endpoint object
634 * @param[in] requestInfo Datastructure containing request information.
636 static void OperationModeUpdateHandler(const CARemoteEndpoint_t *object,
637 const CAResponseInfo_t *responseInfo)
639 if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken)
641 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
643 OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler.");
644 OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result);
645 if (CA_SUCCESS == responseInfo->result)
647 gStateManager |= SP_UPDATE_OP_MODE_DONE;
648 OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler.");
652 gStateManager |= SP_UPDATE_OP_MODE_ERROR;
653 OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler.");
660 * Response handler for ownership transfer.
662 * @param[in] object Remote endpoint object
663 * @param[in] requestInfo Datastructure containing request information.
665 static void OwnerShipUpdateHandler(const CARemoteEndpoint_t *object,
666 const CAResponseInfo_t *responseInfo)
668 if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken)
670 // response handler for ownership tranfer
671 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
673 OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler.");
674 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result);
675 if (CA_SUCCESS == responseInfo->result)
677 gStateManager |= SP_UPDATE_OWNER_DONE;
678 OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler.");
682 gStateManager |= SP_UPDATE_OWNER_ERROR;
683 OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler.");
690 * Response handler for ACL provisioning.
692 * @param[in] object Remote endpoint object
693 * @param[in] requestInfo Datastructure containing request information.
695 static void ACLProvisioningHandler(const CARemoteEndpoint_t *object,
696 const CAResponseInfo_t *responseInfo)
698 if ((gStateManager & SP_PROV_ACL_STARTED) && gToken)
701 // response handler for ACL provisioning.
702 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
704 OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler.");
705 OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result);
706 if (CA_CREATED == responseInfo->result)
708 OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler.");
709 gStateManager |= SP_PROV_ACL_DONE;
713 OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler.");
714 gStateManager |= SP_PROV_ACL_ERROR;
721 * Response handler for provisioning finalization.
723 * @param[in] object Remote endpoint object
724 * @param[in] requestInfo Datastructure containing request information.
726 static void FinalizeProvisioningHandler(const CARemoteEndpoint_t *object,
727 const CAResponseInfo_t *responseInfo)
729 if ((gStateManager & SP_UP_HASH_STARTED) && gToken)
731 // response handler for finalize provisioning.
732 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
734 OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler.");
735 OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result);
736 if (CA_SUCCESS == responseInfo->result)
738 gStateManager |= SP_UP_HASH_DONE;
739 OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler.");
743 gStateManager |= SP_UP_HASH_ERROR;
744 OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler.");
751 * Response handler for Credential provisioning.
753 * @param[in] object Remote endpoint object
754 * @param[in] requestInfo Datastructure containing request information.
756 static void CredProvisioningHandler(const CARemoteEndpoint_t *object,
757 const CAResponseInfo_t *responseInfo)
759 if ((gStateManager & SP_PROV_CRED_STARTED) && gToken)
761 // response handler for CRED provisioning.
762 OC_LOG(INFO, TAG, "Inside CredProvisioningHandler.");
763 OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result);
764 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
766 if (CA_CREATED == responseInfo->result)
768 gStateManager |= SP_PROV_CRED_DONE;
769 OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler.");
773 gStateManager |= SP_PROV_CRED_ERROR;
774 OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler.");
783 * @param[in] object Remote endpoint object
784 * @param[in] responseInfo Datastructure containing response information.
786 static void SPResponseHandler(const CARemoteEndpoint_t *object,
787 const CAResponseInfo_t *responseInfo)
789 if ((NULL != responseInfo) && (NULL != responseInfo->info.token))
791 handler(object, responseInfo);
798 * @param[in] object Remote endpoint object
799 * @param[in] errorInfo Datastructure containing error information.
801 static void SPErrorHandler(const CARemoteEndpoint_t *object,
802 const CAErrorInfo_t *errorInfo)
804 OC_LOG(INFO, TAG, "Error Handler.");
810 * @param[in] object Remote endpoint object
811 * @param[in] requestInfo Datastructure containing request information.
813 static void SPRequestHandler(const CARemoteEndpoint_t *object, const CARequestInfo_t *requestInfo)
815 OC_LOG(INFO, TAG, "Request Handler.");
819 * Function to find the resources using multicast discovery.
821 * @param[in] timeout timeout in secs
822 * @return SP_RESULT_SUCCESS normally otherwise error code.
824 static SPResult findResource(unsigned short timeout)
826 static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=\"FALSE\"";
827 CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
828 if (CA_STATUS_OK != res)
830 OC_LOG(ERROR, TAG, "Error while generating token.");
831 return SP_RESULT_INTERNAL_ERROR;
833 res = CAFindResource(DOXM_OWNED_FALSE_MULTICAST_QUERY, gToken, CA_MAX_TOKEN_LEN);
834 handler = &ProvisionDiscoveryHandler;
835 gStateManager |= SP_DISCOVERY_STARTED;
836 if (CA_STATUS_OK != res)
838 OC_LOG(ERROR, TAG, "Error while finding resource.");
839 return convertCAResultToSPResult(res);
843 OC_LOG(INFO, TAG, "Discovery Request sent successfully");
845 return SPWaitForResponse(timeout);
849 * Function to update the operation mode. As per the spec. Operation mode in client driven
850 * single service provisioning it will be updated to 0x3
852 * @param[in] timeout timeout for operation.
853 * @param[in] deviceInfo Device Info.
854 * @return SP_SUCCESS on success
856 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
857 SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
859 SPResult res = SP_RESULT_INTERNAL_ERROR;
860 char uri[CA_MAX_URI_LENGTH] = {0};
861 size_t uriLen = sizeof(uri);
862 snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip,
863 deviceInfo->port, OIC_RSRC_DOXM_URI);
864 uri[uriLen - 1] = '\0';
866 deviceInfo->doxm->oxmSel = selectedMethod;
867 char *payload = BinToDoxmJSON(deviceInfo->doxm);
870 OC_LOG(ERROR, TAG, "Error while converting bin to json");
871 return SP_RESULT_INTERNAL_ERROR;
873 OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
874 int payloadLen = strlen(payload);
876 CAMethod_t method = CA_PUT;
877 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
879 OC_LOG(ERROR, TAG, "Error while generating token");
881 return SP_RESULT_INTERNAL_ERROR;
883 handler = &OwnerShipTransferModeHandler;
884 gStateManager |= SP_UP_OWN_TR_METH_STARTED;
886 CAResult_t result = sendCARequest(uri, payload, payloadLen, gToken, method,
887 deviceInfo->connType);
889 if (CA_STATUS_OK != result)
891 OC_LOG(ERROR, TAG, "Error while sending request.");
892 CADestroyToken(gToken);
893 return convertCAResultToSPResult(result);
895 res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
896 if (SP_RESULT_SUCCESS != res)
898 OC_LOG(ERROR, TAG, "Internal Error occured");
899 CADestroyToken(gToken);
900 return SP_RESULT_TIMEOUT;
902 CADestroyToken(gToken);
903 return SP_RESULT_SUCCESS;
907 * Function to send request to resource to get its pstat resource information.
909 * @param[in] timeout timeout for operation.
910 * @param[in] deviceInfo Device Info.
911 * @return SP_SUCCESS on success
913 static SPResult getProvisioningStatusResource(unsigned short timeout,
914 SPTargetDeviceInfo_t *deviceInfo)
916 char uri[CA_MAX_URI_LENGTH] = {0};
917 size_t uriLen = sizeof(uri);
918 snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip,
919 deviceInfo->port, OIC_RSRC_PSTAT_URI);
920 uri[uriLen - 1] = '\0';
921 CAMethod_t method = CA_GET;
922 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
924 OC_LOG(ERROR, TAG, "Error while generating token");
925 return SP_RESULT_INTERNAL_ERROR;
927 handler = &ListMethodsHandler;
928 gStateManager |= SP_LIST_METHODS_STARTED;
929 CAResult_t result = sendCARequest(uri, NULL, 0, gToken, method, deviceInfo->connType);
930 if (CA_STATUS_OK != result)
932 OC_LOG(ERROR, TAG, "Failure while sending request.");
933 CADestroyToken(gToken);
934 return convertCAResultToSPResult(result);
936 SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
937 if (SP_RESULT_SUCCESS != res)
939 OC_LOG(ERROR, TAG, "Timeout while getting method list.");
940 CADestroyToken(gToken);
941 return SP_RESULT_TIMEOUT;
943 if (gStateManager && SP_LIST_METHODS_DONE)
945 deviceInfo->pstat = gPstat;
946 CADestroyToken(gToken);
947 OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
948 return SP_RESULT_SUCCESS;
950 CADestroyToken(gToken);
951 return SP_RESULT_INTERNAL_ERROR;
955 * Function to update the operation mode. As per the spec. Operation mode in client driven
956 * single service provisioning it will be updated to 0x3
958 * @param[in] timeout timeout for operation.
959 * @param[in] deviceInfo Device Info.
960 * @return SP_SUCCESS on success
962 static SPResult updateOperationMode(unsigned short timeout, SPTargetDeviceInfo_t *deviceInfo,
963 OicSecDpom_t selectedOperationMode)
966 SPResult res = SP_RESULT_INTERNAL_ERROR;
968 char uri[CA_MAX_URI_LENGTH] = {0};
969 size_t uriLen = sizeof(uri);
970 snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip,
971 deviceInfo->port , OIC_RSRC_PSTAT_URI);
972 uri[uriLen - 1] = '\0';
975 deviceInfo->pstat->om = selectedOperationMode;
977 char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
978 if (NULL == payloadBuffer)
980 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
981 return SP_RESULT_INTERNAL_ERROR;
984 size_t payloadLen = strlen(payloadBuffer);
986 CAMethod_t method = CA_PUT;
987 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
989 OC_LOG(ERROR, TAG, "Error while generating token");
992 OICFree(payloadBuffer);
994 return SP_RESULT_INTERNAL_ERROR;
996 handler = &OperationModeUpdateHandler;
997 gStateManager |= SP_UPDATE_OP_MODE_STARTED;
998 CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method,
999 deviceInfo->connType);
1000 if (CA_STATUS_OK != result)
1002 OC_LOG(ERROR, TAG, "Error while sending request.");
1003 CADestroyToken(gToken);
1004 OICFree(payloadBuffer);
1005 return convertCAResultToSPResult(result);
1007 res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
1008 if (SP_RESULT_SUCCESS != res)
1010 OC_LOG(ERROR, TAG, "Internal Error occured");
1011 CADestroyToken(gToken);
1012 OICFree(payloadBuffer);
1013 return SP_RESULT_TIMEOUT;
1015 CADestroyToken(gToken);
1016 OICFree(payloadBuffer);
1018 if (gStateManager & SP_UPDATE_OP_MODE_DONE)
1020 return SP_RESULT_SUCCESS;
1022 return SP_RESULT_INTERNAL_ERROR;
1026 * Function to initiate DTLS handshake.
1028 * @param[in] deviceInfo Provisioning context
1029 * @return SP_SUCCESS on success
1031 static SPResult initiateDtlsHandshake(const SPTargetDeviceInfo_t *deviceInfo)
1033 CAResult_t caresult = CASelectCipherSuite(TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
1035 if (CA_STATUS_OK != caresult)
1037 OC_LOG(ERROR, TAG, "Unable to select cipher suite");
1038 return SP_RESULT_INTERNAL_ERROR;
1040 OC_LOG(INFO, TAG, "Anonymous cipher suite selected. ");
1041 caresult = CAEnableAnonECDHCipherSuite(true);
1042 if (CA_STATUS_OK != caresult)
1044 OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
1045 return SP_RESULT_INTERNAL_ERROR;
1047 OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
1049 CAAddress_t address = {};
1050 strncpy(address.IP.ipAddress, deviceInfo->ip, DEV_ADDR_SIZE_MAX);
1051 address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0';
1052 address.IP.port = CA_SECURE_PORT;
1054 caresult = CAInitiateHandshake(&address, deviceInfo->connType);
1055 if (CA_STATUS_OK != caresult)
1057 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
1060 return SP_RESULT_SUCCESS;
1064 * Function to send ownerShip info. This function would update Owned as true and
1065 * owner as UUID for provisioning tool
1067 * @param[in] timeout timeout value for the operation.
1068 * @param[in] deviceInfo provisioning context.
1069 * @return SP_SUCCESS on success
1071 static SPResult sendOwnershipInfo(unsigned short timeout,
1072 SPTargetDeviceInfo_t *selectedDeviceInfo)
1074 char uri[CA_MAX_URI_LENGTH] = {0};
1075 size_t uriLen = sizeof(uri);
1076 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip,
1077 CA_SECURE_PORT, OIC_RSRC_DOXM_URI);
1078 uri[uriLen - 1] = '\0';
1080 OicUuid_t provTooldeviceID = {};
1081 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1083 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1084 return SP_RESULT_INTERNAL_ERROR;
1086 memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
1089 selectedDeviceInfo->doxm->owned = true;
1091 char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm);
1092 if (NULL == payloadBuffer)
1094 OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1095 return SP_RESULT_INTERNAL_ERROR;
1097 int payloadLen = strlen(payloadBuffer);
1099 CAMethod_t method = CA_PUT;
1100 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1102 OC_LOG(ERROR, TAG, "Error while generating token");
1103 OICFree(payloadBuffer);
1104 return SP_RESULT_INTERNAL_ERROR;
1107 handler = &OwnerShipUpdateHandler;
1108 gStateManager |= SP_UPDATE_OWNER_STARTED;
1110 CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method,
1111 selectedDeviceInfo->connType);
1112 if (CA_STATUS_OK != result)
1114 OC_LOG(ERROR, TAG, "Error while sending request.");
1115 CADestroyToken(gToken);
1116 OICFree(payloadBuffer);
1117 return convertCAResultToSPResult(result);
1119 SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1120 if (SP_RESULT_SUCCESS != res)
1122 OC_LOG(ERROR, TAG, "Internal Error occured");
1123 CADestroyToken(gToken);
1124 OICFree(payloadBuffer);
1125 return SP_RESULT_TIMEOUT;
1127 CADestroyToken(gToken);
1128 OICFree(payloadBuffer);
1129 return SP_RESULT_SUCCESS;
1133 * Function to save ownerPSK at provisioning tool end.
1135 * @return SP_SUCCESS on success
1137 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1139 SPResult result = SP_RESULT_INTERNAL_ERROR;
1140 CAAddress_t address = {};
1141 strncpy(address.IP.ipAddress, selectedDeviceInfo->ip, DEV_ADDR_SIZE_MAX);
1142 address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0';
1143 address.IP.port = CA_SECURE_PORT;
1145 OicUuid_t provTooldeviceID = {};
1146 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1148 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1152 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1154 //Generating OwnerPSK
1155 CAResult_t pskRet = CAGenerateOwnerPSK(&address, selectedDeviceInfo->connType,
1156 (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1157 sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1158 sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1159 OWNER_PSK_LENGTH_128);
1161 if (CA_STATUS_OK == pskRet)
1163 OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1164 OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1165 //Generating new credential for provisioning tool
1167 uint32_t outLen = 0;
1169 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1170 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1172 if (B64_OK == b64Ret)
1174 OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1175 SYMMETRIC_PAIR_WISE_KEY, NULL,
1176 base64Buff, ownLen, &provTooldeviceID);
1179 //Update the SVR database.
1180 if (OC_STACK_OK == AddCredential(cred))
1182 result = SP_RESULT_SUCCESS;
1186 OC_LOG(ERROR, TAG, "AddCredential failed");
1191 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1196 OC_LOG(ERROR, TAG, "b64Encode failed");
1201 OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1207 * Function to select operation mode.This function will return most secure common operation mode.
1209 * @param[out] selectedMode selected operation mode
1210 * @return SP_SUCCESS on success
1212 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1213 OicSecDpom_t **selectedMode)
1217 while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1219 if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1223 else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1227 else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1229 *selectedMode = &(gProvisioningToolCapability[j]);
1236 * Function to perform onwership tranfer based to ownership transfer mode.
1238 * @param[in] timeout timeout in secs to perform operation. 0 timeout means
1239 function will wait forever.
1240 * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1241 * @return SP_SUCCESS on success
1243 static SPResult doOwnerShipTransfer(unsigned short timeout,
1244 SPTargetDeviceInfo_t *selectedDeviceInfo)
1246 OicSecDpom_t *selectedOperationMode = NULL;
1247 selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1249 SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1250 if (SP_RESULT_SUCCESS != res)
1252 OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1253 return SP_RESULT_INTERNAL_ERROR;
1255 if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1257 res = initiateDtlsHandshake(selectedDeviceInfo);
1258 if (SP_RESULT_SUCCESS != res)
1260 OC_LOG(ERROR, TAG, "Error while DTLS handshake.");
1261 return SP_RESULT_INTERNAL_ERROR;
1264 res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1265 if (SP_RESULT_SUCCESS != res)
1267 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1268 return SP_RESULT_INTERNAL_ERROR;
1271 saveOwnerPSK(selectedDeviceInfo);
1273 return SP_RESULT_SUCCESS;
1278 * Function to provision credentials to specific device.
1280 * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will
1282 * @param[in] cred credential to be provisioned.
1283 * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for
1285 * @return SP_SUCCESS on success
1287 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1288 const SPDevInfo_t *deviceInfo)
1290 char *credJson = NULL;
1291 credJson = BinToCredJSON(cred);
1292 if (NULL == credJson)
1294 OC_LOG(ERROR, TAG, "Memory allocation problem");
1295 return SP_RESULT_MEM_ALLOCATION_FAIL;
1298 char uri[CA_MAX_URI_LENGTH] = {0};
1299 size_t uriLen = sizeof(uri);
1300 snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->ip,
1301 CA_SECURE_PORT, OIC_RSRC_CRED_URI);
1302 uri[uriLen - 1] = '\0';
1304 int payloadLen = strlen(credJson);
1305 CAMethod_t method = CA_POST;
1306 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1308 OC_LOG(ERROR, TAG, "Error while generating token");
1309 return SP_RESULT_INTERNAL_ERROR;
1311 handler = &CredProvisioningHandler;
1312 gStateManager |= SP_PROV_CRED_STARTED;
1313 CAResult_t result = sendCARequest(uri, credJson, payloadLen, gToken, method,
1314 deviceInfo->connType);
1316 if (CA_STATUS_OK != result)
1318 OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1319 CADestroyToken(gToken);
1320 return convertCAResultToSPResult(result);
1323 SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1324 if (SP_RESULT_SUCCESS != res)
1326 OC_LOG(ERROR, TAG, "Internal Error occured");
1327 CADestroyToken(gToken);
1328 return SP_RESULT_TIMEOUT;
1330 CADestroyToken(gToken);
1334 SPResult SPProvisioningDiscovery(unsigned short timeout,
1335 SPTargetDeviceInfo_t **list)
1339 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1340 return SP_RESULT_INVALID_PARAM;
1343 CARegisterHandler(SPRequestHandler, SPResponseHandler, SPErrorHandler);
1344 SPResult smResponse = SP_RESULT_SUCCESS;
1345 smResponse = findResource(timeout);
1346 if (SP_RESULT_SUCCESS != smResponse)
1348 return SP_RESULT_INTERNAL_ERROR;
1350 if (gStateManager & SP_DISCOVERY_DONE)
1352 if (gStateManager & SP_DISCOVERY_ERROR)
1354 return SP_RESULT_INTERNAL_ERROR;
1356 *list = gStartOfDiscoveredDevices;
1357 return SP_RESULT_SUCCESS;
1359 return SP_RESULT_INTERNAL_ERROR;
1362 SPResult SPInitProvisionContext(unsigned short timeout,
1363 SPTargetDeviceInfo_t *selectedDeviceInfo)
1365 if (NULL == selectedDeviceInfo )
1367 return SP_RESULT_INVALID_PARAM;
1370 SPResult res = SP_RESULT_SUCCESS;
1371 OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1373 selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1375 OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1376 res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1378 if (SP_RESULT_SUCCESS != res)
1380 OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1381 return SP_RESULT_INTERNAL_ERROR;
1384 res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1385 if (SP_RESULT_SUCCESS != res)
1387 OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1388 return SP_RESULT_INTERNAL_ERROR;
1390 OC_LOG(INFO, TAG, "Starting ownership transfer");
1391 return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1395 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1398 if (NULL == selectedDeviceInfo || NULL == acl)
1400 return SP_RESULT_INVALID_PARAM;
1402 char *aclString = NULL;
1403 aclString = BinToAclJSON(acl);
1405 if (NULL == aclString)
1407 OC_LOG(ERROR, TAG, "Memory allocation problem");
1408 return SP_RESULT_MEM_ALLOCATION_FAIL;
1411 char uri[CA_MAX_URI_LENGTH] = {0};
1412 size_t uriLen = sizeof(uri);
1413 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip,
1414 CA_SECURE_PORT, OIC_RSRC_ACL_URI);
1415 uri[uriLen - 1] = '\0';
1417 int payloadLen = strlen(aclString);
1418 CAMethod_t method = CA_POST;
1419 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1421 OC_LOG(ERROR, TAG, "Error while generating token");
1423 return SP_RESULT_INTERNAL_ERROR;
1426 handler = &ACLProvisioningHandler;
1427 gStateManager |= SP_PROV_ACL_STARTED;
1429 CAResult_t result = sendCARequest(uri, aclString, payloadLen, gToken, method,
1430 selectedDeviceInfo->connType);
1432 if (CA_STATUS_OK != result)
1434 OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1435 CADestroyToken(gToken);
1436 return convertCAResultToSPResult(result);
1439 SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1440 if (SP_RESULT_SUCCESS != res)
1442 OC_LOG(ERROR, TAG, "Internal Error occured");
1443 CADestroyToken(gToken);
1444 return SP_RESULT_TIMEOUT;
1446 CADestroyToken(gToken);
1450 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1451 const SPDevInfo_t *pDevList)
1453 if (NULL == pDevList)
1455 return SP_RESULT_INVALID_PARAM;
1457 const SPDevInfo_t *curr = pDevList;
1458 OicUuid_t provTooldeviceID = {};
1459 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1461 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1462 return SP_RESULT_INTERNAL_ERROR;
1464 //TODO Need to support other key types in future.
1467 case SYMMETRIC_PAIR_WISE_KEY:
1469 if (NULL == curr->next)
1471 return SP_RESULT_INVALID_PARAM;
1473 // Devices if present after second node will not be considered.
1474 // in scenario-2. 2 devices are provisioned with credentials.
1475 const SPDevInfo_t *firstDevice = curr;
1476 const SPDevInfo_t *secondDevice = curr->next;
1478 OicSecCred_t *firstCred = NULL;
1479 OicSecCred_t *secondCred = NULL;
1481 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1482 &firstDevice->deviceId, &secondDevice->deviceId,
1483 &firstCred, &secondCred);
1484 if (res != SP_RESULT_SUCCESS)
1486 OC_LOG(ERROR, TAG, "error while generating credentials");
1487 return SP_RESULT_INTERNAL_ERROR;
1489 res = provisionCredentials(timeout, firstCred, firstDevice);
1490 if (SP_RESULT_SUCCESS != res)
1492 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1493 DeleteCredList(firstCred);
1494 DeleteCredList(secondCred);
1495 return SP_RESULT_INTERNAL_ERROR;
1497 res = provisionCredentials(timeout, secondCred, secondDevice);
1498 if (SP_RESULT_SUCCESS != res)
1500 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1501 DeleteCredList(firstCred);
1502 DeleteCredList(secondCred);
1503 return SP_RESULT_INTERNAL_ERROR;
1505 DeleteCredList(firstCred);
1506 DeleteCredList(secondCred);
1507 return SP_RESULT_SUCCESS;
1511 OC_LOG(ERROR, TAG, "Invalid option.");
1512 return SP_RESULT_INVALID_PARAM;
1514 return SP_RESULT_INTERNAL_ERROR;
1518 SPResult SPFinalizeProvisioning(unsigned short timeout,
1519 SPTargetDeviceInfo_t *selectedDeviceInfo)
1522 if (NULL == selectedDeviceInfo)
1524 OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1525 return SP_RESULT_INVALID_PARAM;
1527 char uri[CA_MAX_URI_LENGTH] = {0};
1528 size_t uriLen = sizeof(uri);
1529 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip,
1530 CA_SECURE_PORT, OIC_RSRC_PSTAT_URI);
1531 uri[uriLen - 1] = '\0';
1533 uint16_t aclHash = 0; // value for beachhead version.
1534 selectedDeviceInfo->pstat->commitHash = aclHash;
1535 selectedDeviceInfo->pstat->tm = NORMAL;
1536 char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1537 if (NULL == payloadBuffer)
1539 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1540 return SP_RESULT_INTERNAL_ERROR;
1542 int payloadLen = strlen(payloadBuffer);
1544 CAMethod_t method = CA_PUT;
1545 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1547 OC_LOG(ERROR, TAG, "Error while generating token");
1548 OICFree(payloadBuffer);
1549 return SP_RESULT_INTERNAL_ERROR;
1551 handler = &FinalizeProvisioningHandler;
1552 gStateManager |= SP_UP_HASH_STARTED;
1553 CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method,
1554 selectedDeviceInfo->connType);
1555 OICFree(payloadBuffer);
1556 if (CA_STATUS_OK != result)
1558 OC_LOG(ERROR, TAG, "Internal Error occured");
1559 CADestroyToken(gToken);
1560 return convertCAResultToSPResult(result);
1563 SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1564 if (SP_RESULT_SUCCESS != res)
1566 OC_LOG(ERROR, TAG, "Internal Error occured");
1567 CADestroyToken(gToken);
1568 return SP_RESULT_TIMEOUT;
1571 CAAddress_t address = {};
1572 strncpy(address.IP.ipAddress, selectedDeviceInfo->ip, DEV_ADDR_SIZE_MAX);
1573 address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0';
1574 address.IP.port = CA_SECURE_PORT;
1576 result = CACloseDtlsSession(&address, selectedDeviceInfo->connType);
1577 if (CA_STATUS_OK != result)
1579 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
1582 CADestroyToken(gToken);
1588 SPResult SPTerminateProvisioning()
1591 return SP_RESULT_SUCCESS;;