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 "ocpayload.h"
42 #include "ocpayloadcbor.h"
43 #include "oic_malloc.h"
46 #include "ocpayload.h"
47 #include "cainterface.h"
48 #include "provisioningmanager.h"
49 #include "credentialgenerator.h"
52 #include "aclresource.h"
53 #include "doxmresource.h"
54 #include "pstatresource.h"
55 #include "srmresourcestrings.h"
56 #include "credresource.h"
61 SP_DISCOVERY_STARTED = (0x1 << 1),
62 SP_DISCOVERY_ERROR = (0x1 << 2),
63 SP_DISCOVERY_DONE = (0x1 << 3),
64 SP_UP_OWN_TR_METH_STARTED = (0x1 << 4),
65 SP_UP_OWN_TR_METH_ERROR = (0x1 << 5),
66 SP_UP_OWN_TR_METH_DONE = (0x1 << 6),
67 SP_LIST_METHODS_STARTED = (0x1 << 7),
68 SP_LIST_METHODS_ERROR = (0x1 << 8),
69 SP_LIST_METHODS_DONE = (0x1 << 9),
70 SP_UPDATE_OP_MODE_STARTED = (0x1 << 10),
71 SP_UPDATE_OP_MODE_ERROR = (0x1 << 11),
72 SP_UPDATE_OP_MODE_DONE = (0x1 << 12),
73 SP_UPDATE_OWNER_STARTED = (0x1 << 13),
74 SP_UPDATE_OWNER_ERROR = (0x1 << 14),
75 SP_UPDATE_OWNER_DONE = (0x1 << 15),
76 SP_PROV_ACL_STARTED = (0x1 << 16),
77 SP_PROV_ACL_ERROR = (0x1 << 17),
78 SP_PROV_ACL_DONE = (0x1 << 18),
79 SP_UP_HASH_STARTED = (0x1 << 19),
80 SP_UP_HASH_ERROR = (0x1 << 20),
81 SP_UP_HASH_DONE = (0x1 << 21),
82 SP_PROV_CRED_STARTED = (0x1 << 22),
83 SP_PROV_CRED_ERROR = (0x1 << 23),
84 SP_PROV_CRED_DONE = (0x1 << 24)
86 } SPProvisioningStates;
88 #define SP_MAX_BUF_LEN 1024
89 #define TAG "SPProvisionAPI"
90 #define COAP_QUERY "coap://%s:%d%s"
91 #define COAPS_QUERY "coaps://%s:%d%s"
92 #define CA_SECURE_PORT 5684
94 void (*handler)(const CAEndpoint_t *, const CAResponseInfo_t *);
97 * CA token to keep track of response.
99 static CAToken_t gToken = NULL;
102 * start pointer for discovered device linked list.
104 static SPTargetDeviceInfo_t *gStartOfDiscoveredDevices = NULL;
107 * current pointer of device linked list.
109 static SPTargetDeviceInfo_t *gCurrent = NULL;
112 * Variable to keep track of various request.
114 static uint32_t gStateManager = 0;
117 * Variable for storing provisioning tool's provisioning capabilities
118 * Must be in decreasing order of preference. More prefered method should
119 * have lower array index.
121 static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN };
124 * Number of supported provisioning methods
125 * current version supports only one.
127 static int gNumOfProvisioningMethodsPT = 1;
130 * Global variable to save pstat.
132 static OicSecPstat_t *gPstat = NULL;
135 * Secure String copy function
136 * @param[in] destination Pointer to destination string.
137 * @param[in] source Pointer to source string.
138 * @return pointer to destination string, NULL in case of error.
140 static inline char *SPStringCopy(char *destination, const char *source, size_t num)
142 if (strncpy(destination, source, num))
144 destination[num - 1] = '\0';
151 * Function to convert CA result code to SP result code.
153 * @return result code of SP corresponding to that of CA.
155 static SPResult convertCAResultToSPResult(CAResult_t caResult)
161 return SP_RESULT_SUCCESS;
163 case CA_STATUS_INVALID_PARAM:
165 return SP_RESULT_CONN_INVALID_PARAM;
167 case CA_ADAPTER_NOT_ENABLED:
169 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
171 case CA_SERVER_STARTED_ALREADY:
173 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
175 case CA_SERVER_NOT_STARTED:
177 return SP_RESULT_CONN_SERVER_NOT_STARTED;
179 case CA_DESTINATION_NOT_REACHABLE:
181 return SP_RESULT_CONN_DESTINATION_NOT_REACHABLE;
183 case CA_SOCKET_OPERATION_FAILED:
185 return SP_RESULT_CONN_SOCKET_OPERATION_FAILED;
189 return SP_RESULT_CONN_SEND_FAILED;
191 case CA_RECEIVE_FAILED:
193 return SP_RESULT_CONN_RECEIVE_FAILED;
195 case CA_MEMORY_ALLOC_FAILED:
197 return SP_RESULT_CONN_MEMORY_ALLOC_FAILED;
199 case CA_REQUEST_TIMEOUT:
201 return SP_RESULT_CONN_REQUEST_TIMEOUT;
203 case CA_DESTINATION_DISCONNECTED:
205 return SP_RESULT_CONN_DESTINATION_DISCONNECTED;
207 case CA_STATUS_FAILED:
209 return SP_RESULT_CONN_STATUS_FAILED;
211 case CA_NOT_SUPPORTED:
213 return SP_RESULT_CONN_NOT_SUPPORTED;
217 return SP_RESULT_INTERNAL_ERROR;
223 * Function to delete memory allocated to linked list.
226 static void deleteList()
228 SPTargetDeviceInfo_t *current = gStartOfDiscoveredDevices;
232 SPTargetDeviceInfo_t *next = current->next;
233 DeleteDoxmBinData(current->doxm);
234 DeletePstatBinData(current->pstat);
238 gStartOfDiscoveredDevices = NULL;
242 * Timeout implementation.
243 * @param[in] timeout Timeout in seconds. with 0 it will wait forever for success.
244 * @param[in] mask Mask of operation and 0 for no mask.
245 * @return SP_RESULT_SUCCESS on success otherwise error.
247 static SPResult SPTimeout(unsigned short timeout, uint32_t mask)
249 struct timespec startTime = {};
250 struct timespec currTime = {};
252 CAResult_t res = SP_RESULT_SUCCESS;
253 #ifdef _POSIX_MONOTONIC_CLOCK
254 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
256 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
260 return SP_RESULT_INTERNAL_ERROR;
262 while (CA_STATUS_OK == res)
264 res = CAHandleRequestResponse();
265 #ifdef _POSIX_MONOTONIC_CLOCK
266 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
268 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
272 return SP_RESULT_INTERNAL_ERROR;
274 long elapsed = (currTime.tv_sec - startTime.tv_sec);
275 if (SP_NO_MASK == mask)
277 if (elapsed > timeout)
279 return SP_RESULT_SUCCESS;
284 if (gStateManager & mask)
286 return SP_RESULT_SUCCESS;
288 if ((elapsed > timeout) && timeout)
290 return SP_RESULT_INTERNAL_ERROR;
294 return convertCAResultToSPResult(res);
298 * Function to send request to resource server.
299 * @param[in] method method to be used for sending rquest.
300 * @param[in] endpoint endpoint address
301 * @param[in] secure use secure connection
302 * @param[in] resourceUri resourceUri token.
303 * @param[in] payload Payload to be sent with data. NULL is case message
304 * doesn't have payload.
305 * @param[in] payloadLen Size of data to be sent.
306 * @return CA_STATUS_OK on success, otherwise error code.
308 static CAResult_t sendCARequest(CAMethod_t method,
309 const OCDevAddr *devAddr,
310 OCTransportFlags secure,
311 const char *resourceUri,
312 char *payload, int payloadLen)
314 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
316 OC_LOG(ERROR, TAG, "Error while generating token");
317 return CA_MEMORY_ALLOC_FAILED;
319 CAEndpoint_t *endpoint = NULL;
320 if (CA_STATUS_OK != CACreateEndpoint((CATransportFlags_t)secure,
321 devAddr->adapter, devAddr->addr,
322 devAddr->port, &endpoint))
324 OC_LOG(ERROR, TAG, "Failed to create remote endpoint");
325 CADestroyEndpoint(endpoint);
326 return CA_STATUS_FAILED;
328 CAMessageType_t msgType = CA_MSG_CONFIRM;
329 if (payload && '\0' != (*(payload + payloadLen)))
331 OC_LOG(ERROR, TAG, "Payload not properly terminated.");
332 CADestroyEndpoint(endpoint);
333 return CA_STATUS_INVALID_PARAM;
335 OCSecurityPayload secPayload;
336 secPayload.securityData = payload;
337 secPayload.base.type = PAYLOAD_TYPE_SECURITY;
338 CARequestInfo_t requestInfo = { 0 };
339 requestInfo.method = method;
340 requestInfo.isMulticast = false;
341 OCConvertPayload((OCPayload*)(&secPayload), &requestInfo.info.payload,
342 &requestInfo.info.payloadSize);
343 requestInfo.info.type = msgType;
344 requestInfo.info.token = gToken;
345 requestInfo.info.tokenLength = CA_MAX_TOKEN_LEN;
346 requestInfo.info.resourceUri = resourceUri;
348 requestInfo.isMulticast = false;
349 CAResult_t caResult = CA_STATUS_OK;
350 caResult = CASendRequest(endpoint, &requestInfo);
351 if (CA_STATUS_OK != caResult)
353 OC_LOG(ERROR, TAG, "Send Request Error !!");
355 CADestroyEndpoint(endpoint);
362 * @param[in] ip IP of target device.
363 * @param[in] port port of remote server.
364 * @param[in] adapter adapter type of endpoint.
365 * @param[in] doxm pointer to doxm instance.
366 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
368 static SPResult addDevice(const char *ip, int port, OCTransportAdapter adapter, OicSecDoxm_t *doxm)
370 if (NULL == ip || 0 >= port)
372 return SP_RESULT_INVALID_PARAM;
374 SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *)OICCalloc(1, sizeof (SPTargetDeviceInfo_t));
377 OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
378 return SP_RESULT_MEM_ALLOCATION_FAIL;
381 SPStringCopy(ptr->endpoint.addr, ip, MAX_ADDR_STR_SIZE);
382 ptr->endpoint.port = port;
383 ptr->endpoint.adapter = adapter;
389 if (NULL == gStartOfDiscoveredDevices)
391 gStartOfDiscoveredDevices = ptr;
396 gCurrent->next = ptr;
399 return SP_RESULT_SUCCESS;
403 * Function to provide timeframe in which response can be received.
405 * @param[in] timeout Timeout in seconds.
406 * @return SP_RESULT_SUCCESS on success , otherwise error code.
408 static SPResult SPWaitForResponse(unsigned short timeout)
410 return SPTimeout(timeout, SP_NO_MASK);
414 * Function to select appropriate provisioning method.
416 * @param[in] supportedMethodsList List of supported methods
417 * @param[out] selectedMethod Selected methods
418 * @return SP_SUCCESS on success
420 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
421 OicSecOxm_t *selectedMethod)
424 TODO Logic to find appropiate method and assign it to out param
425 for beachhead release method at index 0 will be returned.
427 *selectedMethod = supportedMethods[0];
428 return SP_RESULT_SUCCESS;
431 OCStackResult OCParsePayload(OCPayload** outPayload, const uint8_t* payload, size_t payloadSize);
433 * Response handler for discovery.
435 * @param[in] object Remote endpoint object
436 * @param[in] requestInfo Datastructure containing request information.
438 static void ProvisionDiscoveryHandler(const CAEndpoint_t *object,
439 const CAResponseInfo_t *responseInfo)
441 if ((gStateManager & SP_DISCOVERY_STARTED) && gToken)
443 // Response handler for discovery.
444 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
446 OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler.");
447 if (NULL == responseInfo->info.payload)
449 OC_LOG(INFO, TAG, "Skiping Null payload");
454 OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload,
455 responseInfo->info.payloadSize);
457 OicSecDoxm_t *ptrDoxm = NULL;
459 if(result == OC_STACK_OK && payload->type == PAYLOAD_TYPE_SECURITY)
461 ptrDoxm = JSONToDoxmBin(((OCSecurityPayload*)payload)->securityData);
466 OC_LOG(INFO, TAG, "Ignoring malformed JSON");
470 OC_LOG(DEBUG, TAG, "Successfully converted doxm json to bin.");
472 SPResult res = addDevice(object->addr, object->port, object->adapter, ptrDoxm);
473 if (SP_RESULT_SUCCESS != res)
475 OC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
476 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
477 DeleteDoxmBinData(ptrDoxm);
480 OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
481 gStateManager |= SP_DISCOVERY_DONE;
489 * Response handler ownership transfer.
491 * @param[in] object Remote endpoint object
492 * @param[in] requestInfo Datastructure containing request information.
494 static void OwnerShipTransferModeHandler(const CAEndpoint_t *object,
495 const CAResponseInfo_t *responseInfo)
497 if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken)
499 // response handler for ownership tranfer
500 OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler.");
501 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
503 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result);
504 if (CA_SUCCESS == responseInfo->result)
506 gStateManager |= SP_UP_OWN_TR_METH_DONE;
507 OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler.");
511 gStateManager |= SP_UP_OWN_TR_METH_ERROR;
512 OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler.");
519 * Response handler list methods.
521 * @param[in] object Remote endpoint object
522 * @param[in] requestInfo Datastructure containing request information.
524 static void ListMethodsHandler(const CAEndpoint_t *object,
525 const CAResponseInfo_t *responseInfo)
527 if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
529 OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
530 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
532 OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
533 if (CA_SUCCESS == responseInfo->result)
535 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
536 // Temp logic to trim oc attribute from json
537 // JSONToPstatBin should handle OC in JSON.
538 if (NULL == responseInfo->info.payload)
540 OC_LOG(ERROR, TAG, "response payload is null.");
541 gStateManager |= SP_LIST_METHODS_ERROR;
546 OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload,
547 responseInfo->info.payloadSize);
549 OicSecPstat_t *pstat = NULL;
551 if(result == OC_STACK_OK && payload->type == PAYLOAD_TYPE_SECURITY)
553 pstat = JSONToPstatBin(((OCSecurityPayload*)payload)->securityData);
558 OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
559 gStateManager |= SP_LIST_METHODS_ERROR;
562 DeletePstatBinData(gPstat);
565 gStateManager |= SP_LIST_METHODS_DONE;
567 OC_LOG(INFO, TAG, "Exiting ListMethodsHandler.");
574 * Response handler for update operation mode.
576 * @param[in] object Remote endpoint object
577 * @param[in] requestInfo Datastructure containing request information.
579 static void OperationModeUpdateHandler(const CAEndpoint_t *object,
580 const CAResponseInfo_t *responseInfo)
582 if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken)
584 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
586 OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler.");
587 OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result);
588 if (CA_SUCCESS == responseInfo->result)
590 gStateManager |= SP_UPDATE_OP_MODE_DONE;
591 OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler.");
595 gStateManager |= SP_UPDATE_OP_MODE_ERROR;
596 OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler.");
603 * Response handler for ownership transfer.
605 * @param[in] object Remote endpoint object
606 * @param[in] requestInfo Datastructure containing request information.
608 static void OwnerShipUpdateHandler(const CAEndpoint_t *object,
609 const CAResponseInfo_t *responseInfo)
611 if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken)
613 // response handler for ownership tranfer
614 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
616 OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler.");
617 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result);
618 if (CA_SUCCESS == responseInfo->result)
620 gStateManager |= SP_UPDATE_OWNER_DONE;
621 OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler.");
625 gStateManager |= SP_UPDATE_OWNER_ERROR;
626 OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler.");
633 * Response handler for ACL provisioning.
635 * @param[in] object Remote endpoint object
636 * @param[in] requestInfo Datastructure containing request information.
638 static void ACLProvisioningHandler(const CAEndpoint_t *object,
639 const CAResponseInfo_t *responseInfo)
641 if ((gStateManager & SP_PROV_ACL_STARTED) && gToken)
644 // response handler for ACL provisioning.
645 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
647 OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler.");
648 OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result);
649 if (CA_CREATED == responseInfo->result)
651 OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler.");
652 gStateManager |= SP_PROV_ACL_DONE;
656 OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler.");
657 gStateManager |= SP_PROV_ACL_ERROR;
664 * Response handler for provisioning finalization.
666 * @param[in] object Remote endpoint object
667 * @param[in] requestInfo Datastructure containing request information.
669 static void FinalizeProvisioningHandler(const CAEndpoint_t *object,
670 const CAResponseInfo_t *responseInfo)
672 if ((gStateManager & SP_UP_HASH_STARTED) && gToken)
674 // response handler for finalize provisioning.
675 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
677 OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler.");
678 OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result);
679 if (CA_SUCCESS == responseInfo->result)
681 gStateManager |= SP_UP_HASH_DONE;
682 OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler.");
686 gStateManager |= SP_UP_HASH_ERROR;
687 OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler.");
694 * Response handler for Credential provisioning.
696 * @param[in] object Remote endpoint object
697 * @param[in] requestInfo Datastructure containing request information.
699 static void CredProvisioningHandler(const CAEndpoint_t *object,
700 const CAResponseInfo_t *responseInfo)
702 if ((gStateManager & SP_PROV_CRED_STARTED) && gToken)
704 // response handler for CRED provisioning.
705 OC_LOG(INFO, TAG, "Inside CredProvisioningHandler.");
706 OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result);
707 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
709 if (CA_CREATED == responseInfo->result)
711 gStateManager |= SP_PROV_CRED_DONE;
712 OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler.");
716 gStateManager |= SP_PROV_CRED_ERROR;
717 OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler.");
726 * @param[in] object Remote endpoint object
727 * @param[in] responseInfo Datastructure containing response information.
729 static void SPResponseHandler(const CAEndpoint_t *object,
730 const CAResponseInfo_t *responseInfo)
732 if ((NULL != responseInfo) && (NULL != responseInfo->info.token))
734 handler(object, responseInfo);
741 * @param[in] object Remote endpoint object
742 * @param[in] errorInfo Datastructure containing error information.
744 static void SPErrorHandler(const CAEndpoint_t *object,
745 const CAErrorInfo_t *errorInfo)
747 OC_LOG(INFO, TAG, "Error Handler.");
753 * @param[in] object Remote endpoint object
754 * @param[in] requestInfo Datastructure containing request information.
756 static void SPRequestHandler(const CAEndpoint_t *object, const CARequestInfo_t *requestInfo)
758 OC_LOG(INFO, TAG, "Request Handler.");
762 * Function to find the resources using multicast discovery.
764 * @param[in] timeout timeout in secs
765 * @return SP_RESULT_SUCCESS normally otherwise error code.
767 static SPResult findResource(unsigned short timeout)
769 static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
770 CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
771 if (CA_STATUS_OK != res)
773 OC_LOG(ERROR, TAG, "Error while generating token.");
774 return SP_RESULT_INTERNAL_ERROR;
777 CAEndpoint_t endpoint = { CA_DEFAULT_FLAGS };
779 CAMessageType_t msgType = CA_MSG_NONCONFIRM;
780 CAInfo_t requestData = { 0 };
781 requestData.token = gToken;
782 requestData.tokenLength = CA_MAX_TOKEN_LEN;
783 requestData.payload = NULL;
784 requestData.payloadSize = 0;
785 requestData.type = msgType;
786 requestData.resourceUri = DOXM_OWNED_FALSE_MULTICAST_QUERY;
787 CARequestInfo_t requestInfo = { 0 };
788 requestInfo.method = CA_GET;
789 requestInfo.info = requestData;
790 requestInfo.isMulticast = true;
791 res = CASendRequest(&endpoint, &requestInfo);
793 handler = &ProvisionDiscoveryHandler;
794 gStateManager |= SP_DISCOVERY_STARTED;
795 if (CA_STATUS_OK != res)
797 OC_LOG(ERROR, TAG, "Error while finding resource.");
798 return convertCAResultToSPResult(res);
802 OC_LOG(INFO, TAG, "Discovery Request sent successfully");
804 return SPWaitForResponse(timeout);
808 * Function to update the operation mode. As per the spec. Operation mode in client driven
809 * single service provisioning it will be updated to 0x3
811 * @param[in] timeout timeout for operation.
812 * @param[in] deviceInfo Device Info.
813 * @return SP_SUCCESS on success
815 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
816 SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
818 SPResult res = SP_RESULT_INTERNAL_ERROR;
820 deviceInfo->doxm->oxmSel = selectedMethod;
821 char *payload = BinToDoxmJSON(deviceInfo->doxm);
824 OC_LOG(ERROR, TAG, "Error while converting bin to json");
825 return SP_RESULT_INTERNAL_ERROR;
827 OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
828 int payloadLen = strlen(payload);
830 handler = &OwnerShipTransferModeHandler;
831 gStateManager |= SP_UP_OWN_TR_METH_STARTED;
833 CAResult_t result = sendCARequest(CA_PUT,
834 &deviceInfo->endpoint,
837 payload, payloadLen);
839 if (CA_STATUS_OK != result)
841 OC_LOG(ERROR, TAG, "Error while sending request.");
842 CADestroyToken(gToken);
843 return convertCAResultToSPResult(result);
845 res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
846 if (SP_RESULT_SUCCESS != res)
848 OC_LOG(ERROR, TAG, "Internal Error occured");
849 CADestroyToken(gToken);
850 return SP_RESULT_TIMEOUT;
852 CADestroyToken(gToken);
853 return SP_RESULT_SUCCESS;
857 * Function to send request to resource to get its pstat resource information.
859 * @param[in] timeout timeout for operation.
860 * @param[in] deviceInfo Device Info.
861 * @return SP_SUCCESS on success
863 static SPResult getProvisioningStatusResource(unsigned short timeout,
864 SPTargetDeviceInfo_t *deviceInfo)
866 handler = &ListMethodsHandler;
867 gStateManager |= SP_LIST_METHODS_STARTED;
869 CAResult_t result = sendCARequest(CA_GET,
870 &deviceInfo->endpoint,
874 if (CA_STATUS_OK != result)
876 OC_LOG(ERROR, TAG, "Failure while sending request.");
877 CADestroyToken(gToken);
878 return convertCAResultToSPResult(result);
880 SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
881 if (SP_RESULT_SUCCESS != res)
883 OC_LOG(ERROR, TAG, "Timeout while getting method list.");
884 CADestroyToken(gToken);
885 return SP_RESULT_TIMEOUT;
887 if (gStateManager && SP_LIST_METHODS_DONE)
889 deviceInfo->pstat = gPstat;
890 CADestroyToken(gToken);
891 OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
892 return SP_RESULT_SUCCESS;
894 CADestroyToken(gToken);
895 return SP_RESULT_INTERNAL_ERROR;
899 * Function to update the operation mode. As per the spec. Operation mode in client driven
900 * single service provisioning it will be updated to 0x3
902 * @param[in] timeout timeout for operation.
903 * @param[in] deviceInfo Device Info.
904 * @return SP_SUCCESS on success
906 static SPResult updateOperationMode(unsigned short timeout,
907 SPTargetDeviceInfo_t *deviceInfo,
908 OicSecDpom_t selectedOperationMode)
911 SPResult res = SP_RESULT_INTERNAL_ERROR;
913 deviceInfo->pstat->om = selectedOperationMode;
915 char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
916 if (NULL == payloadBuffer)
918 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
919 return SP_RESULT_INTERNAL_ERROR;
922 size_t payloadLen = strlen(payloadBuffer);
923 handler = &OperationModeUpdateHandler;
924 gStateManager |= SP_UPDATE_OP_MODE_STARTED;
926 CAResult_t result = sendCARequest(CA_PUT,
927 &deviceInfo->endpoint,
930 payloadBuffer, payloadLen);
931 if (CA_STATUS_OK != result)
933 OC_LOG(ERROR, TAG, "Error while sending request.");
934 CADestroyToken(gToken);
935 OICFree(payloadBuffer);
936 return convertCAResultToSPResult(result);
938 res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
939 if (SP_RESULT_SUCCESS != res)
941 OC_LOG(ERROR, TAG, "Internal Error occured");
942 CADestroyToken(gToken);
943 OICFree(payloadBuffer);
944 return SP_RESULT_TIMEOUT;
946 CADestroyToken(gToken);
947 OICFree(payloadBuffer);
949 if (gStateManager & SP_UPDATE_OP_MODE_DONE)
951 return SP_RESULT_SUCCESS;
953 return SP_RESULT_INTERNAL_ERROR;
957 * Function to initiate DTLS handshake.
959 * @param[in] deviceInfo Provisioning context
960 * @return SP_SUCCESS on success
962 static SPResult initiateDtlsHandshake(SPTargetDeviceInfo_t *deviceInfo)
964 CAResult_t caresult = CASelectCipherSuite(TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
966 if (CA_STATUS_OK != caresult)
968 OC_LOG(ERROR, TAG, "Unable to select cipher suite");
969 return SP_RESULT_INTERNAL_ERROR;
971 OC_LOG(INFO, TAG, "Anonymous cipher suite selected. ");
972 caresult = CAEnableAnonECDHCipherSuite(true);
973 if (CA_STATUS_OK != caresult)
975 OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
976 return SP_RESULT_INTERNAL_ERROR;
978 OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
980 //TODO: It is a temporary fix. Revisit it.
981 deviceInfo->endpoint.port = CA_SECURE_PORT;
982 caresult = CAInitiateHandshake((CAEndpoint_t *)&deviceInfo->endpoint);
983 if (CA_STATUS_OK != caresult)
985 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
988 return SP_RESULT_SUCCESS;
992 * Function to send ownerShip info. This function would update Owned as true and
993 * owner as UUID for provisioning tool
995 * @param[in] timeout timeout value for the operation.
996 * @param[in] deviceInfo provisioning context.
997 * @return SP_SUCCESS on success
999 static SPResult sendOwnershipInfo(unsigned short timeout,
1000 SPTargetDeviceInfo_t *selectedDeviceInfo)
1002 OicUuid_t provTooldeviceID = {};
1004 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1006 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1007 return SP_RESULT_INTERNAL_ERROR;
1009 memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
1011 selectedDeviceInfo->doxm->owned = true;
1013 char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm);
1014 if (NULL == payloadBuffer)
1016 OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1017 return SP_RESULT_INTERNAL_ERROR;
1019 int payloadLen = strlen(payloadBuffer);
1021 handler = &OwnerShipUpdateHandler;
1022 gStateManager |= SP_UPDATE_OWNER_STARTED;
1024 CAResult_t result = sendCARequest(CA_PUT,
1025 &selectedDeviceInfo->endpoint,
1028 payloadBuffer, payloadLen);
1029 if (CA_STATUS_OK != result)
1031 OC_LOG(ERROR, TAG, "Error while sending request.");
1032 CADestroyToken(gToken);
1033 OICFree(payloadBuffer);
1034 return convertCAResultToSPResult(result);
1036 SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1037 if (SP_RESULT_SUCCESS != res)
1039 OC_LOG(ERROR, TAG, "Internal Error occured");
1040 CADestroyToken(gToken);
1041 OICFree(payloadBuffer);
1042 return SP_RESULT_TIMEOUT;
1044 CADestroyToken(gToken);
1045 OICFree(payloadBuffer);
1046 return SP_RESULT_SUCCESS;
1050 * Function to save ownerPSK at provisioning tool end.
1052 * @return SP_SUCCESS on success
1054 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1056 SPResult result = SP_RESULT_INTERNAL_ERROR;
1058 CAEndpoint_t endpoint = {0};
1059 strncpy(endpoint.addr, selectedDeviceInfo->endpoint.addr, MAX_ADDR_STR_SIZE_CA);
1060 endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';
1061 endpoint.port = CA_SECURE_PORT;
1063 OicUuid_t provTooldeviceID = {};
1064 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1066 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1070 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1072 //Generating OwnerPSK
1073 CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
1074 (uint8_t *)OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1075 sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1076 sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1077 OWNER_PSK_LENGTH_128);
1079 if (CA_STATUS_OK == pskRet)
1081 OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1082 OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1083 //Generating new credential for provisioning tool
1085 uint32_t outLen = 0;
1087 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1088 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1090 if (B64_OK == b64Ret)
1092 OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1093 SYMMETRIC_PAIR_WISE_KEY, NULL,
1094 base64Buff, ownLen, &provTooldeviceID);
1097 //Update the SVR database.
1098 if (OC_STACK_OK == AddCredential(cred))
1100 result = SP_RESULT_SUCCESS;
1104 OC_LOG(ERROR, TAG, "AddCredential failed");
1109 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1114 OC_LOG(ERROR, TAG, "b64Encode failed");
1119 OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1125 * Function to select operation mode.This function will return most secure common operation mode.
1127 * @param[out] selectedMode selected operation mode
1128 * @return SP_SUCCESS on success
1130 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1131 OicSecDpom_t **selectedMode)
1135 while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1137 if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1141 else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1145 else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1147 *selectedMode = &(gProvisioningToolCapability[j]);
1154 * Function to perform onwership tranfer based to ownership transfer mode.
1156 * @param[in] timeout timeout in secs to perform operation. 0 timeout means
1157 function will wait forever.
1158 * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1159 * @return SP_SUCCESS on success
1161 static SPResult doOwnerShipTransfer(unsigned short timeout,
1162 SPTargetDeviceInfo_t *selectedDeviceInfo)
1164 OicSecDpom_t *selectedOperationMode = NULL;
1165 selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1167 SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1168 if (SP_RESULT_SUCCESS != res)
1170 OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1171 return SP_RESULT_INTERNAL_ERROR;
1173 if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1175 res = initiateDtlsHandshake(selectedDeviceInfo);
1176 if (SP_RESULT_SUCCESS != res)
1178 OC_LOG(ERROR, TAG, "Error while DTLS handshake.");
1179 return SP_RESULT_INTERNAL_ERROR;
1182 res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1183 if (SP_RESULT_SUCCESS != res)
1185 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1186 return SP_RESULT_INTERNAL_ERROR;
1189 saveOwnerPSK(selectedDeviceInfo);
1191 return SP_RESULT_SUCCESS;
1196 * Function to provision credentials to specific device.
1198 * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will
1200 * @param[in] cred credential to be provisioned.
1201 * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for
1203 * @return SP_SUCCESS on success
1205 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1206 const SPDevInfo_t *deviceInfo)
1208 char *credJson = NULL;
1209 credJson = BinToCredJSON(cred);
1210 if (NULL == credJson)
1212 OC_LOG(ERROR, TAG, "Memory allocation problem");
1213 return SP_RESULT_MEM_ALLOCATION_FAIL;
1216 int payloadLen = strlen(credJson);
1217 handler = &CredProvisioningHandler;
1218 gStateManager |= SP_PROV_CRED_STARTED;
1220 CAResult_t result = sendCARequest(CA_POST,
1221 &deviceInfo->endpoint,
1224 credJson, payloadLen);
1226 if (CA_STATUS_OK != result)
1228 OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1229 CADestroyToken(gToken);
1230 return convertCAResultToSPResult(result);
1233 SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1234 if (SP_RESULT_SUCCESS != res)
1236 OC_LOG(ERROR, TAG, "Internal Error occured");
1237 CADestroyToken(gToken);
1238 return SP_RESULT_TIMEOUT;
1240 CADestroyToken(gToken);
1244 SPResult SPProvisioningDiscovery(unsigned short timeout,
1245 SPTargetDeviceInfo_t **list)
1249 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1250 return SP_RESULT_INVALID_PARAM;
1253 CARegisterHandler(SPRequestHandler, SPResponseHandler, SPErrorHandler);
1254 SPResult smResponse = SP_RESULT_SUCCESS;
1255 smResponse = findResource(timeout);
1256 if (SP_RESULT_SUCCESS != smResponse)
1258 return SP_RESULT_INTERNAL_ERROR;
1260 if (gStateManager & SP_DISCOVERY_DONE)
1262 if (gStateManager & SP_DISCOVERY_ERROR)
1264 return SP_RESULT_INTERNAL_ERROR;
1266 *list = gStartOfDiscoveredDevices;
1267 return SP_RESULT_SUCCESS;
1269 return SP_RESULT_INTERNAL_ERROR;
1272 SPResult SPInitProvisionContext(unsigned short timeout,
1273 SPTargetDeviceInfo_t *selectedDeviceInfo)
1275 if (NULL == selectedDeviceInfo )
1277 return SP_RESULT_INVALID_PARAM;
1280 SPResult res = SP_RESULT_SUCCESS;
1281 OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1283 selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1285 OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1286 res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1288 if (SP_RESULT_SUCCESS != res)
1290 OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1291 return SP_RESULT_INTERNAL_ERROR;
1294 res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1295 if (SP_RESULT_SUCCESS != res)
1297 OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1298 return SP_RESULT_INTERNAL_ERROR;
1300 OC_LOG(INFO, TAG, "Starting ownership transfer");
1301 return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1305 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1308 if (NULL == selectedDeviceInfo || NULL == acl)
1310 return SP_RESULT_INVALID_PARAM;
1312 char *aclString = NULL;
1313 aclString = BinToAclJSON(acl);
1315 if (NULL == aclString)
1317 OC_LOG(ERROR, TAG, "Memory allocation problem");
1318 return SP_RESULT_MEM_ALLOCATION_FAIL;
1321 int payloadLen = strlen(aclString);
1322 handler = &ACLProvisioningHandler;
1323 gStateManager |= SP_PROV_ACL_STARTED;
1325 CAResult_t result = sendCARequest(CA_POST,
1326 &selectedDeviceInfo->endpoint,
1329 aclString, payloadLen);
1331 if (CA_STATUS_OK != result)
1333 OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1334 CADestroyToken(gToken);
1335 return convertCAResultToSPResult(result);
1338 SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1339 if (SP_RESULT_SUCCESS != res)
1341 OC_LOG(ERROR, TAG, "Internal Error occured");
1342 CADestroyToken(gToken);
1343 return SP_RESULT_TIMEOUT;
1345 CADestroyToken(gToken);
1349 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1350 const SPDevInfo_t *pDevList)
1352 if (NULL == pDevList)
1354 return SP_RESULT_INVALID_PARAM;
1356 const SPDevInfo_t *curr = pDevList;
1357 OicUuid_t provTooldeviceID = {};
1358 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1360 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1361 return SP_RESULT_INTERNAL_ERROR;
1363 //TODO Need to support other key types in future.
1366 case SYMMETRIC_PAIR_WISE_KEY:
1368 if (NULL == curr->next)
1370 return SP_RESULT_INVALID_PARAM;
1372 // Devices if present after second node will not be considered.
1373 // in scenario-2. 2 devices are provisioned with credentials.
1374 const SPDevInfo_t *firstDevice = curr;
1375 const SPDevInfo_t *secondDevice = curr->next;
1377 OicSecCred_t *firstCred = NULL;
1378 OicSecCred_t *secondCred = NULL;
1380 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1381 &firstDevice->deviceId, &secondDevice->deviceId,
1382 &firstCred, &secondCred);
1383 if (res != SP_RESULT_SUCCESS)
1385 OC_LOG(ERROR, TAG, "error while generating credentials");
1386 return SP_RESULT_INTERNAL_ERROR;
1388 res = provisionCredentials(timeout, firstCred, firstDevice);
1389 if (SP_RESULT_SUCCESS != res)
1391 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1392 DeleteCredList(firstCred);
1393 DeleteCredList(secondCred);
1394 return SP_RESULT_INTERNAL_ERROR;
1396 res = provisionCredentials(timeout, secondCred, secondDevice);
1397 if (SP_RESULT_SUCCESS != res)
1399 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1400 DeleteCredList(firstCred);
1401 DeleteCredList(secondCred);
1402 return SP_RESULT_INTERNAL_ERROR;
1404 DeleteCredList(firstCred);
1405 DeleteCredList(secondCred);
1406 return SP_RESULT_SUCCESS;
1410 OC_LOG(ERROR, TAG, "Invalid option.");
1411 return SP_RESULT_INVALID_PARAM;
1413 return SP_RESULT_INTERNAL_ERROR;
1417 SPResult SPFinalizeProvisioning(unsigned short timeout,
1418 SPTargetDeviceInfo_t *selectedDeviceInfo)
1421 if (NULL == selectedDeviceInfo)
1423 OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1424 return SP_RESULT_INVALID_PARAM;
1427 uint16_t aclHash = 0; // value for beachhead version.
1428 selectedDeviceInfo->pstat->commitHash = aclHash;
1429 selectedDeviceInfo->pstat->tm = NORMAL;
1430 char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1431 if (NULL == payloadBuffer)
1433 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1434 return SP_RESULT_INTERNAL_ERROR;
1436 int payloadLen = strlen(payloadBuffer);
1438 handler = &FinalizeProvisioningHandler;
1439 gStateManager |= SP_UP_HASH_STARTED;
1441 CAResult_t result = sendCARequest(CA_PUT,
1442 &selectedDeviceInfo->endpoint,
1445 payloadBuffer, payloadLen);
1446 OICFree(payloadBuffer);
1447 if (CA_STATUS_OK != result)
1449 OC_LOG(ERROR, TAG, "Internal Error occured");
1450 CADestroyToken(gToken);
1451 return convertCAResultToSPResult(result);
1454 SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1455 if (SP_RESULT_SUCCESS != res)
1457 OC_LOG(ERROR, TAG, "Internal Error occured");
1458 CADestroyToken(gToken);
1459 return SP_RESULT_TIMEOUT;
1462 CAEndpoint_t endpoint = {0};
1463 strncpy(endpoint.addr, selectedDeviceInfo->endpoint.addr, MAX_ADDR_STR_SIZE_CA);
1464 endpoint.addr[DEV_ADDR_SIZE_MAX - 1] = '\0';
1465 endpoint.port = CA_SECURE_PORT;
1467 result = CACloseDtlsSession(&endpoint);
1468 if (CA_STATUS_OK != result)
1470 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
1473 CADestroyToken(gToken);
1479 SPResult SPTerminateProvisioning()
1482 return SP_RESULT_SUCCESS;;