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 // TODO: it can be CA_MSG_NONCONFIRM or CA_MSG_CONFIRM. Pass it as a parameter.
385 CAMessageType_t msgType = CA_MSG_NONCONFIRM;
386 CAInfo_t requestData = { 0 };
387 requestData.token = token;
388 requestData.tokenLength = CA_MAX_TOKEN_LEN;
389 if (payload && '\0' != (*(payload + payloadLen)))
391 OC_LOG(ERROR, TAG, "Payload not properly terminated.");
392 CADestroyRemoteEndpoint(endpoint);
393 return CA_STATUS_INVALID_PARAM;
395 requestData.payload = payload;
396 requestData.type = msgType;
397 CARequestInfo_t requestInfo = { 0 };
398 requestInfo.method = method;
399 requestInfo.info = requestData;
400 CAResult_t caResult = CA_STATUS_OK;
401 caResult = CASendRequest(endpoint, &requestInfo);
402 if (CA_STATUS_OK != caResult)
404 OC_LOG(ERROR, TAG, "Send Request Error !!");
406 CADestroyRemoteEndpoint(endpoint);
413 * @param[in] ip IP of target device.
414 * @param[in] port port of remote server.
415 * @param[in] connType connectivity type of endpoint.
416 * @param[in] doxm pointer to doxm instance.
417 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
419 static SPResult addDevice(const char *ip, int port, SPConnectivityType connType, OicSecDoxm_t *doxm)
421 if (NULL == ip || 0 >= port)
423 return SP_RESULT_INVALID_PARAM;
425 SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *) OICCalloc(1, sizeof(SPTargetDeviceInfo_t));
428 OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
429 return SP_RESULT_MEM_ALLOCATION_FAIL;
432 SPStringCopy(ptr->ip, ip, sizeof(ptr->ip));
434 ptr->connType = connType;
440 if (NULL == gStartOfDiscoveredDevices)
442 gStartOfDiscoveredDevices = ptr;
447 gCurrent->next = ptr;
450 return SP_RESULT_SUCCESS;
454 * Function to provide timeframe in which response can be received.
456 * @param[in] timeout Timeout in seconds.
457 * @return SP_RESULT_SUCCESS on success , otherwise error code.
459 static SPResult SPWaitForResponse(unsigned short timeout)
461 return SPTimeout(timeout, SP_NO_MASK);
465 * Function to select appropriate provisioning method.
467 * @param[in] supportedMethodsList List of supported methods
468 * @param[out] selectedMethod Selected methods
469 * @return SP_SUCCESS on success
471 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
472 OicSecOxm_t *selectedMethod)
475 TODO Logic to find appropiate method and assign it to out param
476 for beachhead release method at index 0 will be returned.
478 *selectedMethod = supportedMethods[0];
479 return SP_RESULT_SUCCESS;
483 * Response handler for discovery.
485 * @param[in] object Remote endpoint object
486 * @param[in] requestInfo Datastructure containing request information.
488 static void ProvisionDiscoveryHandler(const CARemoteEndpoint_t *object,
489 const CAResponseInfo_t *responseInfo)
491 if ((gStateManager & SP_DISCOVERY_STARTED) && gToken)
493 // Response handler for discovery.
494 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
496 OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler.");
497 if (NULL == responseInfo->info.payload)
499 OC_LOG(INFO, TAG, "Skiping Null payload");
502 // temp logic for trimming oc attribute from the json.
503 // JSONToBin should handle oc attribute.
504 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
505 if (NULL == pTempPayload)
507 OC_LOG(ERROR, TAG, "Error while Memory allocation.");
508 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
512 strcpy(pTempPayload, responseInfo->info.payload + 8);
513 pTempPayload[strlen(pTempPayload) - 2] = '\0';
514 OC_LOG_V(DEBUG, TAG, "Trimmed payload: %s", pTempPayload);
515 OicSecDoxm_t *ptrDoxm = JSONToDoxmBin(pTempPayload);
519 OC_LOG(ERROR, TAG, "Error while converting doxm json to binary");
520 OICFree(pTempPayload);
521 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
524 OC_LOG(DEBUG, TAG, "Successfully converted pstat json to bin.");
525 OICFree(pTempPayload);
527 SPConnectivityType connType = getConnectivitySP(object->transportType);
528 SPResult res = addDevice(object->addressInfo.IP.ipAddress, object->addressInfo.IP.port,
530 if (SP_RESULT_SUCCESS != res)
532 OC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
533 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
534 DeleteDoxmBinData(ptrDoxm);
537 OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
538 gStateManager |= SP_DISCOVERY_DONE;
544 * Response handler ownership transfer.
546 * @param[in] object Remote endpoint object
547 * @param[in] requestInfo Datastructure containing request information.
549 static void OwnerShipTransferModeHandler(const CARemoteEndpoint_t *object,
550 const CAResponseInfo_t *responseInfo)
552 if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken)
554 // response handler for ownership tranfer
555 OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler.");
556 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
558 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result);
559 if (CA_SUCCESS == responseInfo->result)
561 gStateManager |= SP_UP_OWN_TR_METH_DONE;
562 OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler.");
566 gStateManager |= SP_UP_OWN_TR_METH_ERROR;
567 OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler.");
574 * Response handler list methods.
576 * @param[in] object Remote endpoint object
577 * @param[in] requestInfo Datastructure containing request information.
579 static void ListMethodsHandler(const CARemoteEndpoint_t *object,
580 const CAResponseInfo_t *responseInfo)
582 if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
584 OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
585 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
587 OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
588 if (CA_SUCCESS == responseInfo->result)
590 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
591 // Temp logic to trim oc attribute from json
592 // JSONToPstatBin should handle OC in JSON.
593 if (NULL == responseInfo->info.payload)
595 OC_LOG(ERROR, TAG, "response payload is null.");
596 gStateManager |= SP_LIST_METHODS_ERROR;
600 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
601 if (NULL == pTempPayload)
603 OC_LOG(ERROR, TAG, "Error in memory allocation.");
604 gStateManager |= SP_LIST_METHODS_ERROR;
608 strcpy(pTempPayload, responseInfo->info.payload + 8);
609 pTempPayload[strlen(pTempPayload) - 2] = '\0';
611 OicSecPstat_t *pstat = JSONToPstatBin(pTempPayload);
614 OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
615 OICFree(pTempPayload);
616 gStateManager |= SP_LIST_METHODS_ERROR;
619 OICFree(pTempPayload);
620 DeletePstatBinData(gPstat);
623 gStateManager |= SP_LIST_METHODS_DONE;
625 OC_LOG(INFO, TAG, "Exiting ListMethodsHandler.");
632 * Response handler for update operation mode.
634 * @param[in] object Remote endpoint object
635 * @param[in] requestInfo Datastructure containing request information.
637 static void OperationModeUpdateHandler(const CARemoteEndpoint_t *object,
638 const CAResponseInfo_t *responseInfo)
640 if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken)
642 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
644 OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler.");
645 OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result);
646 if (CA_SUCCESS == responseInfo->result)
648 gStateManager |= SP_UPDATE_OP_MODE_DONE;
649 OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler.");
653 gStateManager |= SP_UPDATE_OP_MODE_ERROR;
654 OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler.");
661 * Response handler for ownership transfer.
663 * @param[in] object Remote endpoint object
664 * @param[in] requestInfo Datastructure containing request information.
666 static void OwnerShipUpdateHandler(const CARemoteEndpoint_t *object,
667 const CAResponseInfo_t *responseInfo)
669 if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken)
671 // response handler for ownership tranfer
672 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
674 OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler.");
675 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result);
676 if (CA_SUCCESS == responseInfo->result)
678 gStateManager |= SP_UPDATE_OWNER_DONE;
679 OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler.");
683 gStateManager |= SP_UPDATE_OWNER_ERROR;
684 OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler.");
691 * Response handler for ACL provisioning.
693 * @param[in] object Remote endpoint object
694 * @param[in] requestInfo Datastructure containing request information.
696 static void ACLProvisioningHandler(const CARemoteEndpoint_t *object,
697 const CAResponseInfo_t *responseInfo)
699 if ((gStateManager & SP_PROV_ACL_STARTED) && gToken)
702 // response handler for ACL provisioning.
703 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
705 OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler.");
706 OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result);
707 if (CA_CREATED == responseInfo->result)
709 OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler.");
710 gStateManager |= SP_PROV_ACL_DONE;
714 OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler.");
715 gStateManager |= SP_PROV_ACL_ERROR;
722 * Response handler for provisioning finalization.
724 * @param[in] object Remote endpoint object
725 * @param[in] requestInfo Datastructure containing request information.
727 static void FinalizeProvisioningHandler(const CARemoteEndpoint_t *object,
728 const CAResponseInfo_t *responseInfo)
730 if ((gStateManager & SP_UP_HASH_STARTED) && gToken)
732 // response handler for finalize provisioning.
733 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
735 OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler.");
736 OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result);
737 if (CA_SUCCESS == responseInfo->result)
739 gStateManager |= SP_UP_HASH_DONE;
740 OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler.");
744 gStateManager |= SP_UP_HASH_ERROR;
745 OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler.");
752 * Response handler for Credential provisioning.
754 * @param[in] object Remote endpoint object
755 * @param[in] requestInfo Datastructure containing request information.
757 static void CredProvisioningHandler(const CARemoteEndpoint_t *object,
758 const CAResponseInfo_t *responseInfo)
760 if ((gStateManager & SP_PROV_CRED_STARTED) && gToken)
762 // response handler for CRED provisioning.
763 OC_LOG(INFO, TAG, "Inside CredProvisioningHandler.");
764 OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result);
765 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
767 if (CA_CREATED == responseInfo->result)
769 gStateManager |= SP_PROV_CRED_DONE;
770 OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler.");
774 gStateManager |= SP_PROV_CRED_ERROR;
775 OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler.");
784 * @param[in] object Remote endpoint object
785 * @param[in] responseInfo Datastructure containing response information.
787 static void SPResponseHandler(const CARemoteEndpoint_t *object,
788 const CAResponseInfo_t *responseInfo)
790 if ((NULL != responseInfo) && (NULL != responseInfo->info.token))
792 handler(object, responseInfo);
799 * @param[in] object Remote endpoint object
800 * @param[in] errorInfo Datastructure containing error information.
802 static void SPErrorHandler(const CARemoteEndpoint_t *object,
803 const CAErrorInfo_t *errorInfo)
805 OC_LOG(INFO, TAG, "Error Handler.");
811 * @param[in] object Remote endpoint object
812 * @param[in] requestInfo Datastructure containing request information.
814 static void SPRequestHandler(const CARemoteEndpoint_t *object, const CARequestInfo_t *requestInfo)
816 OC_LOG(INFO, TAG, "Request Handler.");
820 * Function to find the resources using multicast discovery.
822 * @param[in] timeout timeout in secs
823 * @return SP_RESULT_SUCCESS normally otherwise error code.
825 static SPResult findResource(unsigned short timeout)
827 static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=\"FALSE\"";
828 CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
829 if (CA_STATUS_OK != res)
831 OC_LOG(ERROR, TAG, "Error while generating token.");
832 return SP_RESULT_INTERNAL_ERROR;
834 res = CAFindResource(DOXM_OWNED_FALSE_MULTICAST_QUERY, gToken, CA_MAX_TOKEN_LEN);
835 handler = &ProvisionDiscoveryHandler;
836 gStateManager |= SP_DISCOVERY_STARTED;
837 if (CA_STATUS_OK != res)
839 OC_LOG(ERROR, TAG, "Error while finding resource.");
840 return convertCAResultToSPResult(res);
844 OC_LOG(INFO, TAG, "Discovery Request sent successfully");
846 return SPWaitForResponse(timeout);
850 * Function to update the operation mode. As per the spec. Operation mode in client driven
851 * single service provisioning it will be updated to 0x3
853 * @param[in] timeout timeout for operation.
854 * @param[in] deviceInfo Device Info.
855 * @return SP_SUCCESS on success
857 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
858 SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
860 SPResult res = SP_RESULT_INTERNAL_ERROR;
861 char uri[CA_MAX_URI_LENGTH] = {0};
862 size_t uriLen = sizeof(uri);
863 snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip,
864 deviceInfo->port, OIC_RSRC_DOXM_URI);
865 uri[uriLen - 1] = '\0';
867 deviceInfo->doxm->oxmSel = selectedMethod;
868 char *payload = BinToDoxmJSON(deviceInfo->doxm);
871 OC_LOG(ERROR, TAG, "Error while converting bin to json");
872 return SP_RESULT_INTERNAL_ERROR;
874 OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
875 int payloadLen = strlen(payload);
877 CAMethod_t method = CA_PUT;
878 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
880 OC_LOG(ERROR, TAG, "Error while generating token");
882 return SP_RESULT_INTERNAL_ERROR;
884 handler = &OwnerShipTransferModeHandler;
885 gStateManager |= SP_UP_OWN_TR_METH_STARTED;
887 CAResult_t result = sendCARequest(uri, payload, payloadLen, gToken, method,
888 deviceInfo->connType);
890 if (CA_STATUS_OK != result)
892 OC_LOG(ERROR, TAG, "Error while sending request.");
893 CADestroyToken(gToken);
894 return convertCAResultToSPResult(result);
896 res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
897 if (SP_RESULT_SUCCESS != res)
899 OC_LOG(ERROR, TAG, "Internal Error occured");
900 CADestroyToken(gToken);
901 return SP_RESULT_TIMEOUT;
903 CADestroyToken(gToken);
904 return SP_RESULT_SUCCESS;
908 * Function to send request to resource to get its pstat resource information.
910 * @param[in] timeout timeout for operation.
911 * @param[in] deviceInfo Device Info.
912 * @return SP_SUCCESS on success
914 static SPResult getProvisioningStatusResource(unsigned short timeout,
915 SPTargetDeviceInfo_t *deviceInfo)
917 char uri[CA_MAX_URI_LENGTH] = {0};
918 size_t uriLen = sizeof(uri);
919 snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip,
920 deviceInfo->port, OIC_RSRC_PSTAT_URI);
921 uri[uriLen - 1] = '\0';
922 CAMethod_t method = CA_GET;
923 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
925 OC_LOG(ERROR, TAG, "Error while generating token");
926 return SP_RESULT_INTERNAL_ERROR;
928 handler = &ListMethodsHandler;
929 gStateManager |= SP_LIST_METHODS_STARTED;
930 CAResult_t result = sendCARequest(uri, NULL, 0, gToken, method, deviceInfo->connType);
931 if (CA_STATUS_OK != result)
933 OC_LOG(ERROR, TAG, "Failure while sending request.");
934 CADestroyToken(gToken);
935 return convertCAResultToSPResult(result);
937 SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
938 if (SP_RESULT_SUCCESS != res)
940 OC_LOG(ERROR, TAG, "Timeout while getting method list.");
941 CADestroyToken(gToken);
942 return SP_RESULT_TIMEOUT;
944 if (gStateManager && SP_LIST_METHODS_DONE)
946 deviceInfo->pstat = gPstat;
947 CADestroyToken(gToken);
948 OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
949 return SP_RESULT_SUCCESS;
951 CADestroyToken(gToken);
952 return SP_RESULT_INTERNAL_ERROR;
956 * Function to update the operation mode. As per the spec. Operation mode in client driven
957 * single service provisioning it will be updated to 0x3
959 * @param[in] timeout timeout for operation.
960 * @param[in] deviceInfo Device Info.
961 * @return SP_SUCCESS on success
963 static SPResult updateOperationMode(unsigned short timeout, SPTargetDeviceInfo_t *deviceInfo,
964 OicSecDpom_t selectedOperationMode)
967 SPResult res = SP_RESULT_INTERNAL_ERROR;
969 char uri[CA_MAX_URI_LENGTH] = {0};
970 size_t uriLen = sizeof(uri);
971 snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip,
972 deviceInfo->port , OIC_RSRC_PSTAT_URI);
973 uri[uriLen - 1] = '\0';
976 deviceInfo->pstat->om = selectedOperationMode;
978 char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
979 if (NULL == payloadBuffer)
981 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
982 return SP_RESULT_INTERNAL_ERROR;
985 size_t payloadLen = strlen(payloadBuffer);
987 CAMethod_t method = CA_PUT;
988 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
990 OC_LOG(ERROR, TAG, "Error while generating token");
993 OICFree(payloadBuffer);
995 return SP_RESULT_INTERNAL_ERROR;
997 handler = &OperationModeUpdateHandler;
998 gStateManager |= SP_UPDATE_OP_MODE_STARTED;
999 CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method,
1000 deviceInfo->connType);
1001 if (CA_STATUS_OK != result)
1003 OC_LOG(ERROR, TAG, "Error while sending request.");
1004 CADestroyToken(gToken);
1005 OICFree(payloadBuffer);
1006 return convertCAResultToSPResult(result);
1008 res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
1009 if (SP_RESULT_SUCCESS != res)
1011 OC_LOG(ERROR, TAG, "Internal Error occured");
1012 CADestroyToken(gToken);
1013 OICFree(payloadBuffer);
1014 return SP_RESULT_TIMEOUT;
1016 CADestroyToken(gToken);
1017 OICFree(payloadBuffer);
1019 if (gStateManager & SP_UPDATE_OP_MODE_DONE)
1021 return SP_RESULT_SUCCESS;
1023 return SP_RESULT_INTERNAL_ERROR;
1027 * Function to initiate DTLS handshake.
1029 * @param[in] deviceInfo Provisioning context
1030 * @return SP_SUCCESS on success
1032 static SPResult initiateDtlsHandshake(const SPTargetDeviceInfo_t *deviceInfo)
1034 CAResult_t caresult = CASelectCipherSuite(TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
1036 if (CA_STATUS_OK != caresult)
1038 OC_LOG(ERROR, TAG, "Unable to select cipher suite");
1039 return SP_RESULT_INTERNAL_ERROR;
1041 OC_LOG(INFO, TAG, "Anonymous cipher suite selected. ");
1042 caresult = CAEnableAnonECDHCipherSuite(true);
1043 if (CA_STATUS_OK != caresult)
1045 OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
1046 return SP_RESULT_INTERNAL_ERROR;
1048 OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
1050 CAAddress_t address = {};
1051 strncpy(address.IP.ipAddress, deviceInfo->ip, DEV_ADDR_SIZE_MAX);
1052 address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0';
1053 address.IP.port = CA_SECURE_PORT;
1055 caresult = CAInitiateHandshake(&address, deviceInfo->connType);
1056 if (CA_STATUS_OK != caresult)
1058 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
1061 return SP_RESULT_SUCCESS;
1065 * Function to send ownerShip info. This function would update Owned as true and
1066 * owner as UUID for provisioning tool
1068 * @param[in] timeout timeout value for the operation.
1069 * @param[in] deviceInfo provisioning context.
1070 * @return SP_SUCCESS on success
1072 static SPResult sendOwnershipInfo(unsigned short timeout,
1073 SPTargetDeviceInfo_t *selectedDeviceInfo)
1075 char uri[CA_MAX_URI_LENGTH] = {0};
1076 size_t uriLen = sizeof(uri);
1077 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip,
1078 CA_SECURE_PORT, OIC_RSRC_DOXM_URI);
1079 uri[uriLen - 1] = '\0';
1081 OicUuid_t provTooldeviceID = {};
1082 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1084 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1085 return SP_RESULT_INTERNAL_ERROR;
1087 memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
1090 selectedDeviceInfo->doxm->owned = true;
1092 char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm);
1093 if (NULL == payloadBuffer)
1095 OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1096 return SP_RESULT_INTERNAL_ERROR;
1098 int payloadLen = strlen(payloadBuffer);
1100 CAMethod_t method = CA_PUT;
1101 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1103 OC_LOG(ERROR, TAG, "Error while generating token");
1104 OICFree(payloadBuffer);
1105 return SP_RESULT_INTERNAL_ERROR;
1108 handler = &OwnerShipUpdateHandler;
1109 gStateManager |= SP_UPDATE_OWNER_STARTED;
1111 CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method,
1112 selectedDeviceInfo->connType);
1113 if (CA_STATUS_OK != result)
1115 OC_LOG(ERROR, TAG, "Error while sending request.");
1116 CADestroyToken(gToken);
1117 OICFree(payloadBuffer);
1118 return convertCAResultToSPResult(result);
1120 SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1121 if (SP_RESULT_SUCCESS != res)
1123 OC_LOG(ERROR, TAG, "Internal Error occured");
1124 CADestroyToken(gToken);
1125 OICFree(payloadBuffer);
1126 return SP_RESULT_TIMEOUT;
1128 CADestroyToken(gToken);
1129 OICFree(payloadBuffer);
1130 return SP_RESULT_SUCCESS;
1134 * Function to save ownerPSK at provisioning tool end.
1136 * @return SP_SUCCESS on success
1138 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1140 SPResult result = SP_RESULT_INTERNAL_ERROR;
1141 CAAddress_t address = {};
1142 strncpy(address.IP.ipAddress, selectedDeviceInfo->ip, DEV_ADDR_SIZE_MAX);
1143 address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0';
1144 address.IP.port = CA_SECURE_PORT;
1146 OicUuid_t provTooldeviceID = {};
1147 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1149 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1153 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1155 //Generating OwnerPSK
1156 CAResult_t pskRet = CAGenerateOwnerPSK(&address, selectedDeviceInfo->connType,
1157 (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1158 sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1159 sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1160 OWNER_PSK_LENGTH_128);
1162 if (CA_STATUS_OK == pskRet)
1164 OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1165 OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1166 //Generating new credential for provisioning tool
1168 uint32_t outLen = 0;
1170 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1171 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1173 if (B64_OK == b64Ret)
1175 OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1176 SYMMETRIC_PAIR_WISE_KEY, NULL,
1177 base64Buff, ownLen, &provTooldeviceID);
1180 //Update the SVR database.
1181 if (OC_STACK_OK == AddCredential(cred))
1183 result = SP_RESULT_SUCCESS;
1187 OC_LOG(ERROR, TAG, "AddCredential failed");
1192 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1197 OC_LOG(ERROR, TAG, "b64Encode failed");
1202 OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1208 * Function to select operation mode.This function will return most secure common operation mode.
1210 * @param[out] selectedMode selected operation mode
1211 * @return SP_SUCCESS on success
1213 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1214 OicSecDpom_t **selectedMode)
1218 while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1220 if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1224 else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1228 else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1230 *selectedMode = &(gProvisioningToolCapability[j]);
1237 * Function to perform onwership tranfer based to ownership transfer mode.
1239 * @param[in] timeout timeout in secs to perform operation. 0 timeout means
1240 function will wait forever.
1241 * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1242 * @return SP_SUCCESS on success
1244 static SPResult doOwnerShipTransfer(unsigned short timeout,
1245 SPTargetDeviceInfo_t *selectedDeviceInfo)
1247 OicSecDpom_t *selectedOperationMode = NULL;
1248 selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1250 SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1251 if (SP_RESULT_SUCCESS != res)
1253 OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1254 return SP_RESULT_INTERNAL_ERROR;
1256 if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1258 res = initiateDtlsHandshake(selectedDeviceInfo);
1259 if (SP_RESULT_SUCCESS != res)
1261 OC_LOG(ERROR, TAG, "Error while DTLS handshake.");
1262 return SP_RESULT_INTERNAL_ERROR;
1265 res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1266 if (SP_RESULT_SUCCESS != res)
1268 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1269 return SP_RESULT_INTERNAL_ERROR;
1272 saveOwnerPSK(selectedDeviceInfo);
1274 return SP_RESULT_SUCCESS;
1279 * Function to provision credentials to specific device.
1281 * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will
1283 * @param[in] cred credential to be provisioned.
1284 * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for
1286 * @return SP_SUCCESS on success
1288 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1289 const SPDevInfo_t *deviceInfo)
1291 char *credJson = NULL;
1292 credJson = BinToCredJSON(cred);
1293 if (NULL == credJson)
1295 OC_LOG(ERROR, TAG, "Memory allocation problem");
1296 return SP_RESULT_MEM_ALLOCATION_FAIL;
1299 char uri[CA_MAX_URI_LENGTH] = {0};
1300 size_t uriLen = sizeof(uri);
1301 snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->ip,
1302 CA_SECURE_PORT, OIC_RSRC_CRED_URI);
1303 uri[uriLen - 1] = '\0';
1305 int payloadLen = strlen(credJson);
1306 CAMethod_t method = CA_POST;
1307 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1309 OC_LOG(ERROR, TAG, "Error while generating token");
1310 return SP_RESULT_INTERNAL_ERROR;
1312 handler = &CredProvisioningHandler;
1313 gStateManager |= SP_PROV_CRED_STARTED;
1314 CAResult_t result = sendCARequest(uri, credJson, payloadLen, gToken, method,
1315 deviceInfo->connType);
1317 if (CA_STATUS_OK != result)
1319 OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1320 CADestroyToken(gToken);
1321 return convertCAResultToSPResult(result);
1324 SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1325 if (SP_RESULT_SUCCESS != res)
1327 OC_LOG(ERROR, TAG, "Internal Error occured");
1328 CADestroyToken(gToken);
1329 return SP_RESULT_TIMEOUT;
1331 CADestroyToken(gToken);
1335 SPResult SPProvisioningDiscovery(unsigned short timeout,
1336 SPTargetDeviceInfo_t **list)
1340 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1341 return SP_RESULT_INVALID_PARAM;
1344 CARegisterHandler(SPRequestHandler, SPResponseHandler, SPErrorHandler);
1345 SPResult smResponse = SP_RESULT_SUCCESS;
1346 smResponse = findResource(timeout);
1347 if (SP_RESULT_SUCCESS != smResponse)
1349 return SP_RESULT_INTERNAL_ERROR;
1351 if (gStateManager & SP_DISCOVERY_DONE)
1353 if (gStateManager & SP_DISCOVERY_ERROR)
1355 return SP_RESULT_INTERNAL_ERROR;
1357 *list = gStartOfDiscoveredDevices;
1358 return SP_RESULT_SUCCESS;
1360 return SP_RESULT_INTERNAL_ERROR;
1363 SPResult SPInitProvisionContext(unsigned short timeout,
1364 SPTargetDeviceInfo_t *selectedDeviceInfo)
1366 if (NULL == selectedDeviceInfo )
1368 return SP_RESULT_INVALID_PARAM;
1371 SPResult res = SP_RESULT_SUCCESS;
1372 OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1374 selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1376 OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1377 res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1379 if (SP_RESULT_SUCCESS != res)
1381 OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1382 return SP_RESULT_INTERNAL_ERROR;
1385 res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1386 if (SP_RESULT_SUCCESS != res)
1388 OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1389 return SP_RESULT_INTERNAL_ERROR;
1391 OC_LOG(INFO, TAG, "Starting ownership transfer");
1392 return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1396 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1399 if (NULL == selectedDeviceInfo || NULL == acl)
1401 return SP_RESULT_INVALID_PARAM;
1403 char *aclString = NULL;
1404 aclString = BinToAclJSON(acl);
1406 if (NULL == aclString)
1408 OC_LOG(ERROR, TAG, "Memory allocation problem");
1409 return SP_RESULT_MEM_ALLOCATION_FAIL;
1412 char uri[CA_MAX_URI_LENGTH] = {0};
1413 size_t uriLen = sizeof(uri);
1414 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip,
1415 CA_SECURE_PORT, OIC_RSRC_ACL_URI);
1416 uri[uriLen - 1] = '\0';
1418 int payloadLen = strlen(aclString);
1419 CAMethod_t method = CA_POST;
1420 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1422 OC_LOG(ERROR, TAG, "Error while generating token");
1424 return SP_RESULT_INTERNAL_ERROR;
1427 handler = &ACLProvisioningHandler;
1428 gStateManager |= SP_PROV_ACL_STARTED;
1430 CAResult_t result = sendCARequest(uri, aclString, payloadLen, gToken, method,
1431 selectedDeviceInfo->connType);
1433 if (CA_STATUS_OK != result)
1435 OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1436 CADestroyToken(gToken);
1437 return convertCAResultToSPResult(result);
1440 SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1441 if (SP_RESULT_SUCCESS != res)
1443 OC_LOG(ERROR, TAG, "Internal Error occured");
1444 CADestroyToken(gToken);
1445 return SP_RESULT_TIMEOUT;
1447 CADestroyToken(gToken);
1451 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1452 const SPDevInfo_t *pDevList)
1454 if (NULL == pDevList)
1456 return SP_RESULT_INVALID_PARAM;
1458 const SPDevInfo_t *curr = pDevList;
1459 OicUuid_t provTooldeviceID = {};
1460 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1462 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1463 return SP_RESULT_INTERNAL_ERROR;
1465 //TODO Need to support other key types in future.
1468 case SYMMETRIC_PAIR_WISE_KEY:
1470 if (NULL == curr->next)
1472 return SP_RESULT_INVALID_PARAM;
1474 // Devices if present after second node will not be considered.
1475 // in scenario-2. 2 devices are provisioned with credentials.
1476 const SPDevInfo_t *firstDevice = curr;
1477 const SPDevInfo_t *secondDevice = curr->next;
1479 OicSecCred_t *firstCred = NULL;
1480 OicSecCred_t *secondCred = NULL;
1482 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1483 &firstDevice->deviceId, &secondDevice->deviceId,
1484 &firstCred, &secondCred);
1485 if (res != SP_RESULT_SUCCESS)
1487 OC_LOG(ERROR, TAG, "error while generating credentials");
1488 return SP_RESULT_INTERNAL_ERROR;
1490 res = provisionCredentials(timeout, firstCred, firstDevice);
1491 if (SP_RESULT_SUCCESS != res)
1493 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1494 DeleteCredList(firstCred);
1495 DeleteCredList(secondCred);
1496 return SP_RESULT_INTERNAL_ERROR;
1498 res = provisionCredentials(timeout, secondCred, secondDevice);
1499 if (SP_RESULT_SUCCESS != res)
1501 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1502 DeleteCredList(firstCred);
1503 DeleteCredList(secondCred);
1504 return SP_RESULT_INTERNAL_ERROR;
1506 DeleteCredList(firstCred);
1507 DeleteCredList(secondCred);
1508 return SP_RESULT_SUCCESS;
1512 OC_LOG(ERROR, TAG, "Invalid option.");
1513 return SP_RESULT_INVALID_PARAM;
1515 return SP_RESULT_INTERNAL_ERROR;
1519 SPResult SPFinalizeProvisioning(unsigned short timeout,
1520 SPTargetDeviceInfo_t *selectedDeviceInfo)
1523 if (NULL == selectedDeviceInfo)
1525 OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1526 return SP_RESULT_INVALID_PARAM;
1528 char uri[CA_MAX_URI_LENGTH] = {0};
1529 size_t uriLen = sizeof(uri);
1530 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip,
1531 CA_SECURE_PORT, OIC_RSRC_PSTAT_URI);
1532 uri[uriLen - 1] = '\0';
1534 uint16_t aclHash = 0; // value for beachhead version.
1535 selectedDeviceInfo->pstat->commitHash = aclHash;
1536 selectedDeviceInfo->pstat->tm = NORMAL;
1537 char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1538 if (NULL == payloadBuffer)
1540 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1541 return SP_RESULT_INTERNAL_ERROR;
1543 int payloadLen = strlen(payloadBuffer);
1545 CAMethod_t method = CA_PUT;
1546 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
1548 OC_LOG(ERROR, TAG, "Error while generating token");
1549 OICFree(payloadBuffer);
1550 return SP_RESULT_INTERNAL_ERROR;
1552 handler = &FinalizeProvisioningHandler;
1553 gStateManager |= SP_UP_HASH_STARTED;
1554 CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method,
1555 selectedDeviceInfo->connType);
1556 OICFree(payloadBuffer);
1557 if (CA_STATUS_OK != result)
1559 OC_LOG(ERROR, TAG, "Internal Error occured");
1560 CADestroyToken(gToken);
1561 return convertCAResultToSPResult(result);
1564 SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1565 if (SP_RESULT_SUCCESS != res)
1567 OC_LOG(ERROR, TAG, "Internal Error occured");
1568 CADestroyToken(gToken);
1569 return SP_RESULT_TIMEOUT;
1572 CAAddress_t address = {};
1573 strncpy(address.IP.ipAddress, selectedDeviceInfo->ip, DEV_ADDR_SIZE_MAX);
1574 address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0';
1575 address.IP.port = CA_SECURE_PORT;
1577 result = CACloseDtlsSession(&address, selectedDeviceInfo->connType);
1578 if (CA_STATUS_OK != result)
1580 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
1583 CADestroyToken(gToken);
1589 SPResult SPTerminateProvisioning()
1592 return SP_RESULT_SUCCESS;;