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"
54 #include "oic_string.h"
55 #include "secureresourcemanager.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 bool (*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;
320 CAEndpoint_t *endpoint = NULL;
321 if (CA_STATUS_OK != CACreateEndpoint((CATransportFlags_t)secure,
322 devAddr->adapter, devAddr->addr,
323 devAddr->port, &endpoint))
325 OC_LOG(ERROR, TAG, "Failed to create remote endpoint");
326 CADestroyEndpoint(endpoint);
327 return CA_STATUS_FAILED;
329 CAMessageType_t msgType = CA_MSG_CONFIRM;
330 CAInfo_t requestData = { 0 };
331 requestData.token = gToken;
332 requestData.tokenLength = CA_MAX_TOKEN_LEN;
333 if (payload && '\0' != (*(payload + payloadLen)))
335 OC_LOG(ERROR, TAG, "Payload not properly terminated.");
336 CADestroyEndpoint(endpoint);
337 return CA_STATUS_INVALID_PARAM;
339 requestData.payload = payload;
340 requestData.type = msgType;
341 requestData.resourceUri = (CAURI_t)resourceUri;
343 CARequestInfo_t requestInfo = { 0 };
344 requestInfo.method = method;
345 requestInfo.info = requestData;
346 requestInfo.isMulticast = false;
347 CAResult_t caResult = CA_STATUS_OK;
348 caResult = CASendRequest(endpoint, &requestInfo);
349 if (CA_STATUS_OK != caResult)
351 OC_LOG(ERROR, TAG, "Send Request Error !!");
353 CADestroyEndpoint(endpoint);
360 * @param[in] endpoint Endpoint information
361 * @param[in] doxm pointer to doxm instance.
362 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
364 static SPResult addDevice(const CAEndpoint_t *endpoint, OicSecDoxm_t* doxm)
366 if (NULL == endpoint)
368 return SP_RESULT_INVALID_PARAM;
370 SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *)OICCalloc(1, sizeof (SPTargetDeviceInfo_t));
373 OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
374 return SP_RESULT_MEM_ALLOCATION_FAIL;
377 memcpy(&(ptr->endpoint), endpoint, sizeof(CAEndpoint_t));
381 if (NULL == gStartOfDiscoveredDevices)
383 gStartOfDiscoveredDevices = ptr;
388 gCurrent->next = ptr;
391 return SP_RESULT_SUCCESS;
395 * Function to provide timeframe in which response can be received.
397 * @param[in] timeout Timeout in seconds.
398 * @return SP_RESULT_SUCCESS on success , otherwise error code.
400 static SPResult SPWaitForResponse(unsigned short timeout)
402 return SPTimeout(timeout, SP_NO_MASK);
406 * Function to select appropriate provisioning method.
408 * @param[in] supportedMethodsList List of supported methods
409 * @param[out] selectedMethod Selected methods
410 * @return SP_SUCCESS on success
412 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
413 OicSecOxm_t *selectedMethod)
416 TODO Logic to find appropiate method and assign it to out param
417 for beachhead release method at index 0 will be returned.
419 *selectedMethod = supportedMethods[0];
420 return SP_RESULT_SUCCESS;
424 * Response handler for discovery.
426 * @param[in] object Remote endpoint object
427 * @param[in] requestInfo Datastructure containing request information.
428 * @return true is CA token matches request token, false otherwise.
430 static bool ProvisionDiscoveryHandler(const CAEndpoint_t *object,
431 const CAResponseInfo_t *responseInfo)
433 if ((gStateManager & SP_DISCOVERY_STARTED) && gToken)
435 // Response handler for discovery.
436 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
438 OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler.");
439 if (NULL == responseInfo->info.payload)
441 OC_LOG(INFO, TAG, "Skiping Null payload");
445 // temp logic for trimming oc attribute from the json.
446 // JSONToBin should handle oc attribute.
447 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
448 if (NULL == pTempPayload)
450 OC_LOG(ERROR, TAG, "Error while Memory allocation.");
451 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
455 strcpy(pTempPayload, responseInfo->info.payload + 8);
456 pTempPayload[strlen(pTempPayload) - 2] = '\0';
457 OC_LOG_V(DEBUG, TAG, "Trimmed payload: %s", pTempPayload);
458 OicSecDoxm_t *ptrDoxm = JSONToDoxmBin(pTempPayload);
459 OICFree(pTempPayload);
463 OC_LOG(INFO, TAG, "Ignoring malformed JSON");
467 OC_LOG(DEBUG, TAG, "Successfully converted doxm json to bin.");
469 SPResult res = addDevice(object, ptrDoxm);
470 if (SP_RESULT_SUCCESS != res)
472 OC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
473 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
474 DeleteDoxmBinData(ptrDoxm);
477 OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
478 gStateManager |= SP_DISCOVERY_DONE;
488 * Response handler ownership transfer.
490 * @param[in] object Remote endpoint object
491 * @param[in] requestInfo Datastructure containing request information.
492 * @return true is CA token matches request token, false otherwise.
494 static bool 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.");
521 * Response handler list methods.
523 * @param[in] object Remote endpoint object
524 * @param[in] requestInfo Datastructure containing request information.
525 * @return true is CA token matches request token, false otherwise.
527 static bool ListMethodsHandler(const CAEndpoint_t *object,
528 const CAResponseInfo_t *responseInfo)
530 if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
532 OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
533 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
535 OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
536 if (CA_SUCCESS == responseInfo->result)
538 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
539 // Temp logic to trim oc attribute from json
540 // JSONToPstatBin should handle OC in JSON.
541 if (NULL == responseInfo->info.payload)
543 OC_LOG(ERROR, TAG, "response payload is null.");
544 gStateManager |= SP_LIST_METHODS_ERROR;
548 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
549 if (NULL == pTempPayload)
551 OC_LOG(ERROR, TAG, "Error in memory allocation.");
552 gStateManager |= SP_LIST_METHODS_ERROR;
556 strcpy(pTempPayload, responseInfo->info.payload + 8);
557 pTempPayload[strlen(pTempPayload) - 2] = '\0';
559 OicSecPstat_t *pstat = JSONToPstatBin(pTempPayload);
562 OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
563 OICFree(pTempPayload);
564 gStateManager |= SP_LIST_METHODS_ERROR;
567 OICFree(pTempPayload);
568 DeletePstatBinData(gPstat);
571 gStateManager |= SP_LIST_METHODS_DONE;
573 OC_LOG(INFO, TAG, "Exiting ListMethodsHandler.");
582 * Response handler for update operation mode.
584 * @param[in] object Remote endpoint object
585 * @param[in] requestInfo Datastructure containing request information.
586 * @return true is CA token matches request token, false otherwise.
588 static bool OperationModeUpdateHandler(const CAEndpoint_t *object,
589 const CAResponseInfo_t *responseInfo)
591 if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken)
593 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
595 OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler.");
596 OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result);
597 if (CA_SUCCESS == responseInfo->result)
599 gStateManager |= SP_UPDATE_OP_MODE_DONE;
600 OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler.");
604 gStateManager |= SP_UPDATE_OP_MODE_ERROR;
605 OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler.");
614 * Response handler for ownership transfer.
616 * @param[in] object Remote endpoint object
617 * @param[in] requestInfo Datastructure containing request information.
618 * @return true is CA token matches request token, false otherwise.
620 static bool OwnerShipUpdateHandler(const CAEndpoint_t *object,
621 const CAResponseInfo_t *responseInfo)
623 if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken)
625 // response handler for ownership tranfer
626 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
628 OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler.");
629 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result);
630 if (CA_SUCCESS == responseInfo->result)
632 gStateManager |= SP_UPDATE_OWNER_DONE;
633 OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler.");
637 gStateManager |= SP_UPDATE_OWNER_ERROR;
638 OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler.");
647 * Response handler for ACL provisioning.
649 * @param[in] object Remote endpoint object
650 * @param[in] requestInfo Datastructure containing request information.
651 * @return true is CA token matches request token, false otherwise.
653 static bool ACLProvisioningHandler(const CAEndpoint_t *object,
654 const CAResponseInfo_t *responseInfo)
656 if ((gStateManager & SP_PROV_ACL_STARTED) && gToken)
659 // response handler for ACL provisioning.
660 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
662 OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler.");
663 OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result);
664 if (CA_CREATED == responseInfo->result)
666 OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler.");
667 gStateManager |= SP_PROV_ACL_DONE;
671 OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler.");
672 gStateManager |= SP_PROV_ACL_ERROR;
681 * Response handler for provisioning finalization.
683 * @param[in] object Remote endpoint object
684 * @param[in] requestInfo Datastructure containing request information.
685 * @return true is CA token matches request token, false otherwise.
687 static bool FinalizeProvisioningHandler(const CAEndpoint_t *object,
688 const CAResponseInfo_t *responseInfo)
690 if ((gStateManager & SP_UP_HASH_STARTED) && gToken)
692 // response handler for finalize provisioning.
693 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
695 OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler.");
696 OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result);
697 if (CA_SUCCESS == responseInfo->result)
699 gStateManager |= SP_UP_HASH_DONE;
700 OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler.");
704 gStateManager |= SP_UP_HASH_ERROR;
705 OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler.");
714 * Response handler for Credential provisioning.
716 * @param[in] object Remote endpoint object
717 * @param[in] requestInfo Datastructure containing request information.
718 * @return true is CA token matches request token, false otherwise.
720 static bool CredProvisioningHandler(const CAEndpoint_t *object,
721 const CAResponseInfo_t *responseInfo)
723 if ((gStateManager & SP_PROV_CRED_STARTED) && gToken)
725 // response handler for CRED provisioning.
726 OC_LOG(INFO, TAG, "Inside CredProvisioningHandler.");
727 OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result);
728 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
730 if (CA_CREATED == responseInfo->result)
732 gStateManager |= SP_PROV_CRED_DONE;
733 OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler.");
737 gStateManager |= SP_PROV_CRED_ERROR;
738 OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler.");
749 * @param[in] object Remote endpoint object
750 * @param[in] responseInfo Datastructure containing response information.
751 * @return true if received response is for provisioning API false otherwise.
753 static bool SPResponseHandler(const CAEndpoint_t *object,
754 const CAResponseInfo_t *responseInfo)
756 bool isProvResponse = false;
757 if ((NULL != responseInfo) && (NULL != responseInfo->info.token))
759 isProvResponse = handler(object, responseInfo);
761 return isProvResponse;
765 * Function to find the resources using multicast discovery.
767 * @param[in] timeout timeout in secs
768 * @return SP_RESULT_SUCCESS normally otherwise error code.
770 static SPResult findResource(unsigned short timeout)
772 static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
773 CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
774 if (CA_STATUS_OK != res)
776 OC_LOG(ERROR, TAG, "Error while generating token.");
777 return SP_RESULT_INTERNAL_ERROR;
780 CAEndpoint_t endpoint = { CA_DEFAULT_FLAGS };
782 CAMessageType_t msgType = CA_MSG_NONCONFIRM;
783 CAInfo_t requestData = { 0 };
784 requestData.token = gToken;
785 requestData.tokenLength = CA_MAX_TOKEN_LEN;
786 requestData.payload = NULL;
787 requestData.type = msgType;
788 requestData.resourceUri = DOXM_OWNED_FALSE_MULTICAST_QUERY;
789 CARequestInfo_t requestInfo = { 0 };
790 requestInfo.method = CA_GET;
791 requestInfo.info = requestData;
792 requestInfo.isMulticast = true;
793 res = CASendRequest(&endpoint, &requestInfo);
795 handler = &ProvisionDiscoveryHandler;
796 gStateManager |= SP_DISCOVERY_STARTED;
797 if (CA_STATUS_OK != res)
799 OC_LOG(ERROR, TAG, "Error while finding resource.");
800 return convertCAResultToSPResult(res);
804 OC_LOG(INFO, TAG, "Discovery Request sent successfully");
806 return SPWaitForResponse(timeout);
810 * Function to update the operation mode. As per the spec. Operation mode in client driven
811 * single service provisioning it will be updated to 0x3
813 * @param[in] timeout timeout for operation.
814 * @param[in] deviceInfo Device Info.
815 * @return SP_SUCCESS on success
817 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
818 SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
820 SPResult res = SP_RESULT_INTERNAL_ERROR;
822 deviceInfo->doxm->oxmSel = selectedMethod;
823 char *payload = BinToDoxmJSON(deviceInfo->doxm);
826 OC_LOG(ERROR, TAG, "Error while converting bin to json");
827 return SP_RESULT_INTERNAL_ERROR;
829 OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
830 int payloadLen = strlen(payload);
832 handler = &OwnerShipTransferModeHandler;
833 gStateManager |= SP_UP_OWN_TR_METH_STARTED;
835 CAResult_t result = sendCARequest(CA_PUT,
836 &deviceInfo->endpoint,
839 payload, payloadLen);
841 if (CA_STATUS_OK != result)
843 OC_LOG(ERROR, TAG, "Error while sending request.");
844 CADestroyToken(gToken);
845 return convertCAResultToSPResult(result);
847 res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
848 if (SP_RESULT_SUCCESS != res)
850 OC_LOG(ERROR, TAG, "Internal Error occured");
851 CADestroyToken(gToken);
852 return SP_RESULT_TIMEOUT;
854 CADestroyToken(gToken);
855 return SP_RESULT_SUCCESS;
859 * Function to send request to resource to get its pstat resource information.
861 * @param[in] timeout timeout for operation.
862 * @param[in] deviceInfo Device Info.
863 * @return SP_SUCCESS on success
865 static SPResult getProvisioningStatusResource(unsigned short timeout,
866 SPTargetDeviceInfo_t *deviceInfo)
868 handler = &ListMethodsHandler;
869 gStateManager |= SP_LIST_METHODS_STARTED;
871 CAResult_t result = sendCARequest(CA_GET,
872 &deviceInfo->endpoint,
876 if (CA_STATUS_OK != result)
878 OC_LOG(ERROR, TAG, "Failure while sending request.");
879 CADestroyToken(gToken);
880 return convertCAResultToSPResult(result);
882 SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
883 if (SP_RESULT_SUCCESS != res)
885 OC_LOG(ERROR, TAG, "Timeout while getting method list.");
886 CADestroyToken(gToken);
887 return SP_RESULT_TIMEOUT;
889 if (gStateManager && SP_LIST_METHODS_DONE)
891 deviceInfo->pstat = gPstat;
892 CADestroyToken(gToken);
893 OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
894 return SP_RESULT_SUCCESS;
896 CADestroyToken(gToken);
897 return SP_RESULT_INTERNAL_ERROR;
901 * Function to update the operation mode. As per the spec. Operation mode in client driven
902 * single service provisioning it will be updated to 0x3
904 * @param[in] timeout timeout for operation.
905 * @param[in] deviceInfo Device Info.
906 * @return SP_SUCCESS on success
908 static SPResult updateOperationMode(unsigned short timeout,
909 SPTargetDeviceInfo_t *deviceInfo,
910 OicSecDpom_t selectedOperationMode)
913 SPResult res = SP_RESULT_INTERNAL_ERROR;
915 deviceInfo->pstat->om = selectedOperationMode;
917 char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
918 if (NULL == payloadBuffer)
920 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
921 return SP_RESULT_INTERNAL_ERROR;
924 size_t payloadLen = strlen(payloadBuffer);
925 handler = &OperationModeUpdateHandler;
926 gStateManager |= SP_UPDATE_OP_MODE_STARTED;
928 CAResult_t result = sendCARequest(CA_PUT,
929 &deviceInfo->endpoint,
932 payloadBuffer, payloadLen);
933 if (CA_STATUS_OK != result)
935 OC_LOG(ERROR, TAG, "Error while sending request.");
936 CADestroyToken(gToken);
937 OICFree(payloadBuffer);
938 return convertCAResultToSPResult(result);
940 res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
941 if (SP_RESULT_SUCCESS != res)
943 OC_LOG(ERROR, TAG, "Internal Error occured");
944 CADestroyToken(gToken);
945 OICFree(payloadBuffer);
946 return SP_RESULT_TIMEOUT;
948 CADestroyToken(gToken);
949 OICFree(payloadBuffer);
951 if (gStateManager & SP_UPDATE_OP_MODE_DONE)
953 return SP_RESULT_SUCCESS;
955 return SP_RESULT_INTERNAL_ERROR;
959 * Function to initiate DTLS handshake.
961 * @param[in] deviceInfo Provisioning context
962 * @return SP_SUCCESS on success
964 static SPResult initiateDtlsHandshake(const CAEndpoint_t *endpoint)
966 CAResult_t caresult = CAEnableAnonECDHCipherSuite(true);
967 if (CA_STATUS_OK != caresult)
969 OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
970 return SP_RESULT_INTERNAL_ERROR;
972 OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
974 caresult = CAInitiateHandshake(endpoint);
975 if (CA_STATUS_OK != caresult)
977 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
980 return SP_RESULT_SUCCESS;
984 * Function to send ownerShip info. This function would update Owned as true and
985 * owner as UUID for provisioning tool
987 * @param[in] timeout timeout value for the operation.
988 * @param[in] deviceInfo provisioning context.
989 * @return SP_SUCCESS on success
991 static SPResult sendOwnershipInfo(unsigned short timeout,
992 SPTargetDeviceInfo_t *selectedDeviceInfo)
994 OicUuid_t provTooldeviceID = {};
996 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
998 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
999 return SP_RESULT_INTERNAL_ERROR;
1001 memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
1003 selectedDeviceInfo->doxm->owned = true;
1005 char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm);
1006 if (NULL == payloadBuffer)
1008 OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1009 return SP_RESULT_INTERNAL_ERROR;
1011 int payloadLen = strlen(payloadBuffer);
1013 handler = &OwnerShipUpdateHandler;
1014 gStateManager |= SP_UPDATE_OWNER_STARTED;
1016 CAResult_t result = sendCARequest(CA_PUT,
1017 &selectedDeviceInfo->endpoint,
1020 payloadBuffer, payloadLen);
1021 if (CA_STATUS_OK != result)
1023 OC_LOG(ERROR, TAG, "Error while sending request.");
1024 CADestroyToken(gToken);
1025 OICFree(payloadBuffer);
1026 return convertCAResultToSPResult(result);
1028 SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1029 if (SP_RESULT_SUCCESS != res)
1031 OC_LOG(ERROR, TAG, "Internal Error occured");
1032 CADestroyToken(gToken);
1033 OICFree(payloadBuffer);
1034 return SP_RESULT_TIMEOUT;
1036 CADestroyToken(gToken);
1037 OICFree(payloadBuffer);
1038 return SP_RESULT_SUCCESS;
1042 * Function to save ownerPSK at provisioning tool end.
1044 * @return SP_SUCCESS on success
1046 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1048 SPResult result = SP_RESULT_INTERNAL_ERROR;
1050 CAEndpoint_t endpoint = {};
1051 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1052 endpoint.port = CA_SECURE_PORT;
1054 OicUuid_t provTooldeviceID = {};
1055 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1057 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1061 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1063 //Generating OwnerPSK
1064 CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
1065 (uint8_t *)OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1066 sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1067 sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1068 OWNER_PSK_LENGTH_128);
1070 if (CA_STATUS_OK == pskRet)
1072 OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1073 OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1074 //Generating new credential for provisioning tool
1076 uint32_t outLen = 0;
1078 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1079 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1081 if (B64_OK == b64Ret)
1083 OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1084 SYMMETRIC_PAIR_WISE_KEY, NULL,
1085 base64Buff, ownLen, &provTooldeviceID);
1088 //Update the SVR database.
1089 if (OC_STACK_OK == AddCredential(cred))
1091 result = SP_RESULT_SUCCESS;
1095 OC_LOG(ERROR, TAG, "AddCredential failed");
1100 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1105 OC_LOG(ERROR, TAG, "b64Encode failed");
1110 OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1116 * Function to select operation mode.This function will return most secure common operation mode.
1118 * @param[out] selectedMode selected operation mode
1119 * @return SP_SUCCESS on success
1121 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1122 OicSecDpom_t **selectedMode)
1126 while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1128 if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1132 else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1136 else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1138 *selectedMode = &(gProvisioningToolCapability[j]);
1145 * Function to perform onwership tranfer based to ownership transfer mode.
1147 * @param[in] timeout timeout in secs to perform operation. 0 timeout means
1148 function will wait forever.
1149 * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1150 * @return SP_SUCCESS on success
1152 static SPResult doOwnerShipTransfer(unsigned short timeout,
1153 SPTargetDeviceInfo_t *selectedDeviceInfo)
1155 OicSecDpom_t *selectedOperationMode = NULL;
1156 selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1158 SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1159 if (SP_RESULT_SUCCESS != res)
1161 OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1162 return SP_RESULT_INTERNAL_ERROR;
1164 if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1166 CAEndpoint_t endpoint = {0};
1167 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1168 endpoint.port = CA_SECURE_PORT;
1170 res = initiateDtlsHandshake(&endpoint);
1171 if (SP_RESULT_SUCCESS == res)
1173 selectedDeviceInfo->endpoint.port = CA_SECURE_PORT;
1174 res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1175 if (SP_RESULT_SUCCESS != res)
1177 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1179 res = saveOwnerPSK(selectedDeviceInfo);
1181 //Close temporal DTLS session
1182 if(CA_STATUS_OK != CACloseDtlsSession(&endpoint))
1184 OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to close the dtls session");
1189 OC_LOG(ERROR, TAG, "Error during initiating DTLS handshake.");
1192 //Disable Anonymous ECDH cipher suite before leaving this method
1193 if(CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false))
1195 OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to disable Anon ECDH cipher suite");
1198 return (res != SP_RESULT_SUCCESS) ? SP_RESULT_INTERNAL_ERROR : SP_RESULT_SUCCESS;
1203 * Function to provision credentials to specific device.
1205 * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will
1207 * @param[in] cred credential to be provisioned.
1208 * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for
1210 * @return SP_SUCCESS on success
1212 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1213 const SPDevInfo_t *deviceInfo)
1215 char *credJson = NULL;
1216 credJson = BinToCredJSON(cred);
1217 if (NULL == credJson)
1219 OC_LOG(ERROR, TAG, "Memory allocation problem");
1220 return SP_RESULT_MEM_ALLOCATION_FAIL;
1223 int payloadLen = strlen(credJson);
1224 handler = &CredProvisioningHandler;
1225 gStateManager |= SP_PROV_CRED_STARTED;
1227 CAResult_t result = sendCARequest(CA_POST,
1228 &deviceInfo->endpoint,
1231 credJson, payloadLen);
1233 if (CA_STATUS_OK != result)
1235 OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1236 CADestroyToken(gToken);
1237 return convertCAResultToSPResult(result);
1240 SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1241 if (SP_RESULT_SUCCESS != res)
1243 OC_LOG(ERROR, TAG, "Internal Error occured");
1244 CADestroyToken(gToken);
1245 return SP_RESULT_TIMEOUT;
1247 CADestroyToken(gToken);
1252 SPResult SPProvisioningDiscovery(unsigned short timeout,
1253 SPTargetDeviceInfo_t **list)
1257 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1258 return SP_RESULT_INVALID_PARAM;
1260 SRMRegisterProvisioningResponseHandler(SPResponseHandler);
1261 SPResult smResponse = SP_RESULT_SUCCESS;
1262 smResponse = findResource(timeout);
1263 if (SP_RESULT_SUCCESS != smResponse)
1265 return SP_RESULT_INTERNAL_ERROR;
1267 if (gStateManager & SP_DISCOVERY_DONE)
1269 if (gStateManager & SP_DISCOVERY_ERROR)
1271 return SP_RESULT_INTERNAL_ERROR;
1273 *list = gStartOfDiscoveredDevices;
1274 return SP_RESULT_SUCCESS;
1276 return SP_RESULT_INTERNAL_ERROR;
1279 SPResult SPInitProvisionContext(unsigned short timeout,
1280 SPTargetDeviceInfo_t *selectedDeviceInfo)
1282 if (NULL == selectedDeviceInfo )
1284 return SP_RESULT_INVALID_PARAM;
1287 SPResult res = SP_RESULT_SUCCESS;
1288 OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1290 selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1292 OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1293 res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1295 if (SP_RESULT_SUCCESS != res)
1297 OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1298 return SP_RESULT_INTERNAL_ERROR;
1301 res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1302 if (SP_RESULT_SUCCESS != res)
1304 OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1305 return SP_RESULT_INTERNAL_ERROR;
1307 OC_LOG(INFO, TAG, "Starting ownership transfer");
1308 return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1312 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1315 if (NULL == selectedDeviceInfo || NULL == acl)
1317 return SP_RESULT_INVALID_PARAM;
1319 char *aclString = NULL;
1320 aclString = BinToAclJSON(acl);
1322 if (NULL == aclString)
1324 OC_LOG(ERROR, TAG, "Memory allocation problem");
1325 return SP_RESULT_MEM_ALLOCATION_FAIL;
1328 int payloadLen = strlen(aclString);
1329 handler = &ACLProvisioningHandler;
1330 gStateManager |= SP_PROV_ACL_STARTED;
1332 CAResult_t result = sendCARequest(CA_POST,
1333 &selectedDeviceInfo->endpoint,
1336 aclString, payloadLen);
1338 if (CA_STATUS_OK != result)
1340 OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1341 CADestroyToken(gToken);
1342 return convertCAResultToSPResult(result);
1345 SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1346 if (SP_RESULT_SUCCESS != res)
1348 OC_LOG(ERROR, TAG, "Internal Error occured");
1349 CADestroyToken(gToken);
1350 return SP_RESULT_TIMEOUT;
1352 CADestroyToken(gToken);
1356 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1357 const SPDevInfo_t *pDevList)
1359 if (NULL == pDevList)
1361 return SP_RESULT_INVALID_PARAM;
1363 const SPDevInfo_t *curr = pDevList;
1364 OicUuid_t provTooldeviceID = {};
1365 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1367 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1368 return SP_RESULT_INTERNAL_ERROR;
1370 //TODO Need to support other key types in future.
1373 case SYMMETRIC_PAIR_WISE_KEY:
1375 if (NULL == curr->next)
1377 return SP_RESULT_INVALID_PARAM;
1379 // Devices if present after second node will not be considered.
1380 // in scenario-2. 2 devices are provisioned with credentials.
1381 const SPDevInfo_t *firstDevice = curr;
1382 const SPDevInfo_t *secondDevice = curr->next;
1384 OicSecCred_t *firstCred = NULL;
1385 OicSecCred_t *secondCred = NULL;
1387 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1388 &firstDevice->deviceId, &secondDevice->deviceId,
1389 &firstCred, &secondCred);
1390 if (res != SP_RESULT_SUCCESS)
1392 OC_LOG(ERROR, TAG, "error while generating credentials");
1393 return SP_RESULT_INTERNAL_ERROR;
1395 res = provisionCredentials(timeout, firstCred, firstDevice);
1396 if (SP_RESULT_SUCCESS != res)
1398 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1399 DeleteCredList(firstCred);
1400 DeleteCredList(secondCred);
1401 return SP_RESULT_INTERNAL_ERROR;
1403 res = provisionCredentials(timeout, secondCred, secondDevice);
1404 if (SP_RESULT_SUCCESS != res)
1406 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1407 DeleteCredList(firstCred);
1408 DeleteCredList(secondCred);
1409 return SP_RESULT_INTERNAL_ERROR;
1411 DeleteCredList(firstCred);
1412 DeleteCredList(secondCred);
1413 return SP_RESULT_SUCCESS;
1417 OC_LOG(ERROR, TAG, "Invalid option.");
1418 return SP_RESULT_INVALID_PARAM;
1420 return SP_RESULT_INTERNAL_ERROR;
1424 SPResult SPFinalizeProvisioning(unsigned short timeout,
1425 SPTargetDeviceInfo_t *selectedDeviceInfo)
1428 if (NULL == selectedDeviceInfo)
1430 OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1431 return SP_RESULT_INVALID_PARAM;
1434 uint16_t aclHash = 0; // value for beachhead version.
1435 selectedDeviceInfo->pstat->commitHash = aclHash;
1436 selectedDeviceInfo->pstat->tm = NORMAL;
1437 char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1438 if (NULL == payloadBuffer)
1440 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1441 return SP_RESULT_INTERNAL_ERROR;
1443 int payloadLen = strlen(payloadBuffer);
1445 handler = &FinalizeProvisioningHandler;
1446 gStateManager |= SP_UP_HASH_STARTED;
1448 CAResult_t result = sendCARequest(CA_PUT,
1449 &selectedDeviceInfo->endpoint,
1452 payloadBuffer, payloadLen);
1453 OICFree(payloadBuffer);
1454 if (CA_STATUS_OK != result)
1456 OC_LOG(ERROR, TAG, "Internal Error occured");
1457 CADestroyToken(gToken);
1458 return convertCAResultToSPResult(result);
1461 SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1462 if (SP_RESULT_SUCCESS != res)
1464 OC_LOG(ERROR, TAG, "Internal Error occured");
1465 CADestroyToken(gToken);
1466 return SP_RESULT_TIMEOUT;
1469 CAEndpoint_t endpoint = {};
1470 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1471 endpoint.port = CA_SECURE_PORT;
1473 result = CACloseDtlsSession(&endpoint);
1474 if (CA_STATUS_OK != result)
1476 OC_LOG(WARNING, TAG, "Failed to close the DTLS session.");
1479 CADestroyToken(gToken);
1485 SPResult SPTerminateProvisioning()
1488 return SP_RESULT_SUCCESS;;