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"
59 SP_DISCOVERY_STARTED = (0x1 << 1),
60 SP_DISCOVERY_ERROR = (0x1 << 2),
61 SP_DISCOVERY_DONE = (0x1 << 3),
62 SP_UP_OWN_TR_METH_STARTED = (0x1 << 4),
63 SP_UP_OWN_TR_METH_ERROR = (0x1 << 5),
64 SP_UP_OWN_TR_METH_DONE = (0x1 << 6),
65 SP_LIST_METHODS_STARTED = (0x1 << 7),
66 SP_LIST_METHODS_ERROR = (0x1 << 8),
67 SP_LIST_METHODS_DONE = (0x1 << 9),
68 SP_UPDATE_OP_MODE_STARTED = (0x1 << 10),
69 SP_UPDATE_OP_MODE_ERROR = (0x1 << 11),
70 SP_UPDATE_OP_MODE_DONE = (0x1 << 12),
71 SP_UPDATE_OWNER_STARTED = (0x1 << 13),
72 SP_UPDATE_OWNER_ERROR = (0x1 << 14),
73 SP_UPDATE_OWNER_DONE = (0x1 << 15),
74 SP_PROV_ACL_STARTED = (0x1 << 16),
75 SP_PROV_ACL_ERROR = (0x1 << 17),
76 SP_PROV_ACL_DONE = (0x1 << 18),
77 SP_UP_HASH_STARTED = (0x1 << 19),
78 SP_UP_HASH_ERROR = (0x1 << 20),
79 SP_UP_HASH_DONE = (0x1 << 21),
80 SP_PROV_CRED_STARTED = (0x1 << 22),
81 SP_PROV_CRED_ERROR = (0x1 << 23),
82 SP_PROV_CRED_DONE = (0x1 << 24)
84 } SPProvisioningStates;
86 #define SP_MAX_BUF_LEN 1024
87 #define TAG "SPProvisionAPI"
88 #define COAP_QUERY "coap://%s:%d%s"
89 #define COAPS_QUERY "coaps://%s:%d%s"
90 #define CA_SECURE_PORT 5684
92 void (*handler)(const CAEndpoint_t *, const CAResponseInfo_t *);
95 * CA token to keep track of response.
97 static CAToken_t gToken = NULL;
100 * start pointer for discovered device linked list.
102 static SPTargetDeviceInfo_t *gStartOfDiscoveredDevices = NULL;
105 * current pointer of device linked list.
107 static SPTargetDeviceInfo_t *gCurrent = NULL;
110 * Variable to keep track of various request.
112 static uint32_t gStateManager = 0;
115 * Variable for storing provisioning tool's provisioning capabilities
116 * Must be in decreasing order of preference. More prefered method should
117 * have lower array index.
119 static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN };
122 * Number of supported provisioning methods
123 * current version supports only one.
125 static int gNumOfProvisioningMethodsPT = 1;
128 * Global variable to save pstat.
130 static OicSecPstat_t *gPstat = NULL;
133 * Secure String copy function
134 * @param[in] destination Pointer to destination string.
135 * @param[in] source Pointer to source string.
136 * @return pointer to destination string, NULL in case of error.
138 static inline char *SPStringCopy(char *destination, const char *source, size_t num)
140 if (strncpy(destination, source, num))
142 destination[num - 1] = '\0';
149 * Function to convert CA result code to SP result code.
151 * @return result code of SP corresponding to that of CA.
153 static SPResult convertCAResultToSPResult(CAResult_t caResult)
159 return SP_RESULT_SUCCESS;
161 case CA_STATUS_INVALID_PARAM:
163 return SP_RESULT_CONN_INVALID_PARAM;
165 case CA_ADAPTER_NOT_ENABLED:
167 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
169 case CA_SERVER_STARTED_ALREADY:
171 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
173 case CA_SERVER_NOT_STARTED:
175 return SP_RESULT_CONN_SERVER_NOT_STARTED;
177 case CA_DESTINATION_NOT_REACHABLE:
179 return SP_RESULT_CONN_DESTINATION_NOT_REACHABLE;
181 case CA_SOCKET_OPERATION_FAILED:
183 return SP_RESULT_CONN_SOCKET_OPERATION_FAILED;
187 return SP_RESULT_CONN_SEND_FAILED;
189 case CA_RECEIVE_FAILED:
191 return SP_RESULT_CONN_RECEIVE_FAILED;
193 case CA_MEMORY_ALLOC_FAILED:
195 return SP_RESULT_CONN_MEMORY_ALLOC_FAILED;
197 case CA_REQUEST_TIMEOUT:
199 return SP_RESULT_CONN_REQUEST_TIMEOUT;
201 case CA_DESTINATION_DISCONNECTED:
203 return SP_RESULT_CONN_DESTINATION_DISCONNECTED;
205 case CA_STATUS_FAILED:
207 return SP_RESULT_CONN_STATUS_FAILED;
209 case CA_NOT_SUPPORTED:
211 return SP_RESULT_CONN_NOT_SUPPORTED;
215 return SP_RESULT_INTERNAL_ERROR;
221 * Function to delete memory allocated to linked list.
224 static void deleteList()
226 SPTargetDeviceInfo_t *current = gStartOfDiscoveredDevices;
230 SPTargetDeviceInfo_t *next = current->next;
231 DeleteDoxmBinData(current->doxm);
232 DeletePstatBinData(current->pstat);
236 gStartOfDiscoveredDevices = NULL;
240 * Timeout implementation.
241 * @param[in] timeout Timeout in seconds. with 0 it will wait forever for success.
242 * @param[in] mask Mask of operation and 0 for no mask.
243 * @return SP_RESULT_SUCCESS on success otherwise error.
245 static SPResult SPTimeout(unsigned short timeout, uint32_t mask)
247 struct timespec startTime = {};
248 struct timespec currTime = {};
250 CAResult_t res = SP_RESULT_SUCCESS;
251 #ifdef _POSIX_MONOTONIC_CLOCK
252 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
254 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
258 return SP_RESULT_INTERNAL_ERROR;
260 while (CA_STATUS_OK == res)
262 res = CAHandleRequestResponse();
263 #ifdef _POSIX_MONOTONIC_CLOCK
264 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
266 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
270 return SP_RESULT_INTERNAL_ERROR;
272 long elapsed = (currTime.tv_sec - startTime.tv_sec);
273 if (SP_NO_MASK == mask)
275 if (elapsed > timeout)
277 return SP_RESULT_SUCCESS;
282 if (gStateManager & mask)
284 return SP_RESULT_SUCCESS;
286 if ((elapsed > timeout) && timeout)
288 return SP_RESULT_INTERNAL_ERROR;
292 return convertCAResultToSPResult(res);
296 * Function to send request to resource server.
297 * @param[in] method method to be used for sending rquest.
298 * @param[in] endpoint endpoint address
299 * @param[in] secure use secure connection
300 * @param[in] resourceUri resourceUri token.
301 * @param[in] payload Payload to be sent with data. NULL is case message
302 * doesn't have payload.
303 * @param[in] payloadLen Size of data to be sent.
304 * @return CA_STATUS_OK on success, otherwise error code.
306 static CAResult_t sendCARequest(CAMethod_t method,
307 const OCDevAddr *devAddr,
308 OCTransportFlags secure,
309 const char *resourceUri,
310 char *payload, int payloadLen)
312 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
314 OC_LOG(ERROR, TAG, "Error while generating token");
315 return CA_MEMORY_ALLOC_FAILED;
318 CAEndpoint_t *endpoint = NULL;
319 if (CA_STATUS_OK != CACreateEndpoint((CATransportFlags_t)secure,
320 devAddr->adapter, devAddr->addr,
321 devAddr->port, &endpoint))
323 OC_LOG(ERROR, TAG, "Failed to create remote endpoint");
324 CADestroyEndpoint(endpoint);
325 return CA_STATUS_FAILED;
327 CAMessageType_t msgType = CA_MSG_CONFIRM;
328 CAInfo_t requestData = { 0 };
329 requestData.token = gToken;
330 requestData.tokenLength = CA_MAX_TOKEN_LEN;
331 if (payload && '\0' != (*(payload + payloadLen)))
333 OC_LOG(ERROR, TAG, "Payload not properly terminated.");
334 CADestroyEndpoint(endpoint);
335 return CA_STATUS_INVALID_PARAM;
337 requestData.payload = payload;
338 requestData.type = msgType;
339 requestData.resourceUri = (CAURI_t)resourceUri;
341 CARequestInfo_t requestInfo = { 0 };
342 requestInfo.method = method;
343 requestInfo.info = requestData;
344 requestInfo.isMulticast = false;
345 CAResult_t caResult = CA_STATUS_OK;
346 caResult = CASendRequest(endpoint, &requestInfo);
347 if (CA_STATUS_OK != caResult)
349 OC_LOG(ERROR, TAG, "Send Request Error !!");
351 CADestroyEndpoint(endpoint);
358 * @param[in] endpoint Endpoint information
359 * @param[in] doxm pointer to doxm instance.
360 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
362 static SPResult addDevice(const CAEndpoint_t *endpoint, OicSecDoxm_t* doxm)
364 if (NULL == endpoint)
366 return SP_RESULT_INVALID_PARAM;
368 SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *)OICCalloc(1, sizeof (SPTargetDeviceInfo_t));
371 OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
372 return SP_RESULT_MEM_ALLOCATION_FAIL;
375 memcpy(&(ptr->endpoint), endpoint, sizeof(CAEndpoint_t));
379 if (NULL == gStartOfDiscoveredDevices)
381 gStartOfDiscoveredDevices = ptr;
386 gCurrent->next = ptr;
389 return SP_RESULT_SUCCESS;
393 * Function to provide timeframe in which response can be received.
395 * @param[in] timeout Timeout in seconds.
396 * @return SP_RESULT_SUCCESS on success , otherwise error code.
398 static SPResult SPWaitForResponse(unsigned short timeout)
400 return SPTimeout(timeout, SP_NO_MASK);
404 * Function to select appropriate provisioning method.
406 * @param[in] supportedMethodsList List of supported methods
407 * @param[out] selectedMethod Selected methods
408 * @return SP_SUCCESS on success
410 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
411 OicSecOxm_t *selectedMethod)
414 TODO Logic to find appropiate method and assign it to out param
415 for beachhead release method at index 0 will be returned.
417 *selectedMethod = supportedMethods[0];
418 return SP_RESULT_SUCCESS;
422 * Response handler for discovery.
424 * @param[in] object Remote endpoint object
425 * @param[in] requestInfo Datastructure containing request information.
427 static void ProvisionDiscoveryHandler(const CAEndpoint_t *object,
428 const CAResponseInfo_t *responseInfo)
430 if ((gStateManager & SP_DISCOVERY_STARTED) && gToken)
432 // Response handler for discovery.
433 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
435 OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler.");
436 if (NULL == responseInfo->info.payload)
438 OC_LOG(INFO, TAG, "Skiping Null payload");
442 // temp logic for trimming oc attribute from the json.
443 // JSONToBin should handle oc attribute.
444 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
445 if (NULL == pTempPayload)
447 OC_LOG(ERROR, TAG, "Error while Memory allocation.");
448 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
452 strcpy(pTempPayload, responseInfo->info.payload + 8);
453 pTempPayload[strlen(pTempPayload) - 2] = '\0';
454 OC_LOG_V(DEBUG, TAG, "Trimmed payload: %s", pTempPayload);
455 OicSecDoxm_t *ptrDoxm = JSONToDoxmBin(pTempPayload);
456 OICFree(pTempPayload);
460 OC_LOG(INFO, TAG, "Ignoring malformed JSON");
464 OC_LOG(DEBUG, TAG, "Successfully converted doxm json to bin.");
466 SPResult res = addDevice(object, ptrDoxm);
467 if (SP_RESULT_SUCCESS != res)
469 OC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
470 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
471 DeleteDoxmBinData(ptrDoxm);
474 OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
475 gStateManager |= SP_DISCOVERY_DONE;
483 * Response handler ownership transfer.
485 * @param[in] object Remote endpoint object
486 * @param[in] requestInfo Datastructure containing request information.
488 static void OwnerShipTransferModeHandler(const CAEndpoint_t *object,
489 const CAResponseInfo_t *responseInfo)
491 if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken)
493 // response handler for ownership tranfer
494 OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler.");
495 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
497 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result);
498 if (CA_SUCCESS == responseInfo->result)
500 gStateManager |= SP_UP_OWN_TR_METH_DONE;
501 OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler.");
505 gStateManager |= SP_UP_OWN_TR_METH_ERROR;
506 OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler.");
513 * Response handler list methods.
515 * @param[in] object Remote endpoint object
516 * @param[in] requestInfo Datastructure containing request information.
518 static void ListMethodsHandler(const CAEndpoint_t *object,
519 const CAResponseInfo_t *responseInfo)
521 if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
523 OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
524 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
526 OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
527 if (CA_SUCCESS == responseInfo->result)
529 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
530 // Temp logic to trim oc attribute from json
531 // JSONToPstatBin should handle OC in JSON.
532 if (NULL == responseInfo->info.payload)
534 OC_LOG(ERROR, TAG, "response payload is null.");
535 gStateManager |= SP_LIST_METHODS_ERROR;
539 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
540 if (NULL == pTempPayload)
542 OC_LOG(ERROR, TAG, "Error in memory allocation.");
543 gStateManager |= SP_LIST_METHODS_ERROR;
547 strcpy(pTempPayload, responseInfo->info.payload + 8);
548 pTempPayload[strlen(pTempPayload) - 2] = '\0';
550 OicSecPstat_t *pstat = JSONToPstatBin(pTempPayload);
553 OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
554 OICFree(pTempPayload);
555 gStateManager |= SP_LIST_METHODS_ERROR;
558 OICFree(pTempPayload);
559 DeletePstatBinData(gPstat);
562 gStateManager |= SP_LIST_METHODS_DONE;
564 OC_LOG(INFO, TAG, "Exiting ListMethodsHandler.");
571 * Response handler for update operation mode.
573 * @param[in] object Remote endpoint object
574 * @param[in] requestInfo Datastructure containing request information.
576 static void OperationModeUpdateHandler(const CAEndpoint_t *object,
577 const CAResponseInfo_t *responseInfo)
579 if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken)
581 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
583 OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler.");
584 OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result);
585 if (CA_SUCCESS == responseInfo->result)
587 gStateManager |= SP_UPDATE_OP_MODE_DONE;
588 OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler.");
592 gStateManager |= SP_UPDATE_OP_MODE_ERROR;
593 OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler.");
600 * Response handler for ownership transfer.
602 * @param[in] object Remote endpoint object
603 * @param[in] requestInfo Datastructure containing request information.
605 static void OwnerShipUpdateHandler(const CAEndpoint_t *object,
606 const CAResponseInfo_t *responseInfo)
608 if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken)
610 // response handler for ownership tranfer
611 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
613 OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler.");
614 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result);
615 if (CA_SUCCESS == responseInfo->result)
617 gStateManager |= SP_UPDATE_OWNER_DONE;
618 OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler.");
622 gStateManager |= SP_UPDATE_OWNER_ERROR;
623 OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler.");
630 * Response handler for ACL provisioning.
632 * @param[in] object Remote endpoint object
633 * @param[in] requestInfo Datastructure containing request information.
635 static void ACLProvisioningHandler(const CAEndpoint_t *object,
636 const CAResponseInfo_t *responseInfo)
638 if ((gStateManager & SP_PROV_ACL_STARTED) && gToken)
641 // response handler for ACL provisioning.
642 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
644 OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler.");
645 OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result);
646 if (CA_CREATED == responseInfo->result)
648 OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler.");
649 gStateManager |= SP_PROV_ACL_DONE;
653 OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler.");
654 gStateManager |= SP_PROV_ACL_ERROR;
661 * Response handler for provisioning finalization.
663 * @param[in] object Remote endpoint object
664 * @param[in] requestInfo Datastructure containing request information.
666 static void FinalizeProvisioningHandler(const CAEndpoint_t *object,
667 const CAResponseInfo_t *responseInfo)
669 if ((gStateManager & SP_UP_HASH_STARTED) && gToken)
671 // response handler for finalize provisioning.
672 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
674 OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler.");
675 OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result);
676 if (CA_SUCCESS == responseInfo->result)
678 gStateManager |= SP_UP_HASH_DONE;
679 OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler.");
683 gStateManager |= SP_UP_HASH_ERROR;
684 OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler.");
691 * Response handler for Credential provisioning.
693 * @param[in] object Remote endpoint object
694 * @param[in] requestInfo Datastructure containing request information.
696 static void CredProvisioningHandler(const CAEndpoint_t *object,
697 const CAResponseInfo_t *responseInfo)
699 if ((gStateManager & SP_PROV_CRED_STARTED) && gToken)
701 // response handler for CRED provisioning.
702 OC_LOG(INFO, TAG, "Inside CredProvisioningHandler.");
703 OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result);
704 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
706 if (CA_CREATED == responseInfo->result)
708 gStateManager |= SP_PROV_CRED_DONE;
709 OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler.");
713 gStateManager |= SP_PROV_CRED_ERROR;
714 OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler.");
723 * @param[in] object Remote endpoint object
724 * @param[in] responseInfo Datastructure containing response information.
726 static void SPResponseHandler(const CAEndpoint_t *object,
727 const CAResponseInfo_t *responseInfo)
729 if ((NULL != responseInfo) && (NULL != responseInfo->info.token))
731 handler(object, responseInfo);
738 * @param[in] object Remote endpoint object
739 * @param[in] errorInfo Datastructure containing error information.
741 static void SPErrorHandler(const CAEndpoint_t *object,
742 const CAErrorInfo_t *errorInfo)
744 OC_LOG(INFO, TAG, "Error Handler.");
750 * @param[in] object Remote endpoint object
751 * @param[in] requestInfo Datastructure containing request information.
753 static void SPRequestHandler(const CAEndpoint_t *object, const CARequestInfo_t *requestInfo)
755 OC_LOG(INFO, TAG, "Request Handler.");
759 * Function to find the resources using multicast discovery.
761 * @param[in] timeout timeout in secs
762 * @return SP_RESULT_SUCCESS normally otherwise error code.
764 static SPResult findResource(unsigned short timeout)
766 static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
767 CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
768 if (CA_STATUS_OK != res)
770 OC_LOG(ERROR, TAG, "Error while generating token.");
771 return SP_RESULT_INTERNAL_ERROR;
774 CAEndpoint_t endpoint = { CA_DEFAULT_FLAGS };
776 CAMessageType_t msgType = CA_MSG_NONCONFIRM;
777 CAInfo_t requestData = { 0 };
778 requestData.token = gToken;
779 requestData.tokenLength = CA_MAX_TOKEN_LEN;
780 requestData.payload = NULL;
781 requestData.type = msgType;
782 requestData.resourceUri = DOXM_OWNED_FALSE_MULTICAST_QUERY;
783 CARequestInfo_t requestInfo = { 0 };
784 requestInfo.method = CA_GET;
785 requestInfo.info = requestData;
786 requestInfo.isMulticast = true;
787 res = CASendRequest(&endpoint, &requestInfo);
789 handler = &ProvisionDiscoveryHandler;
790 gStateManager |= SP_DISCOVERY_STARTED;
791 if (CA_STATUS_OK != res)
793 OC_LOG(ERROR, TAG, "Error while finding resource.");
794 return convertCAResultToSPResult(res);
798 OC_LOG(INFO, TAG, "Discovery Request sent successfully");
800 return SPWaitForResponse(timeout);
804 * Function to update the operation mode. As per the spec. Operation mode in client driven
805 * single service provisioning it will be updated to 0x3
807 * @param[in] timeout timeout for operation.
808 * @param[in] deviceInfo Device Info.
809 * @return SP_SUCCESS on success
811 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
812 SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
814 SPResult res = SP_RESULT_INTERNAL_ERROR;
816 deviceInfo->doxm->oxmSel = selectedMethod;
817 char *payload = BinToDoxmJSON(deviceInfo->doxm);
820 OC_LOG(ERROR, TAG, "Error while converting bin to json");
821 return SP_RESULT_INTERNAL_ERROR;
823 OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
824 int payloadLen = strlen(payload);
826 handler = &OwnerShipTransferModeHandler;
827 gStateManager |= SP_UP_OWN_TR_METH_STARTED;
829 CAResult_t result = sendCARequest(CA_PUT,
830 &deviceInfo->endpoint,
833 payload, payloadLen);
835 if (CA_STATUS_OK != result)
837 OC_LOG(ERROR, TAG, "Error while sending request.");
838 CADestroyToken(gToken);
839 return convertCAResultToSPResult(result);
841 res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
842 if (SP_RESULT_SUCCESS != res)
844 OC_LOG(ERROR, TAG, "Internal Error occured");
845 CADestroyToken(gToken);
846 return SP_RESULT_TIMEOUT;
848 CADestroyToken(gToken);
849 return SP_RESULT_SUCCESS;
853 * Function to send request to resource to get its pstat resource information.
855 * @param[in] timeout timeout for operation.
856 * @param[in] deviceInfo Device Info.
857 * @return SP_SUCCESS on success
859 static SPResult getProvisioningStatusResource(unsigned short timeout,
860 SPTargetDeviceInfo_t *deviceInfo)
862 handler = &ListMethodsHandler;
863 gStateManager |= SP_LIST_METHODS_STARTED;
865 CAResult_t result = sendCARequest(CA_GET,
866 &deviceInfo->endpoint,
870 if (CA_STATUS_OK != result)
872 OC_LOG(ERROR, TAG, "Failure while sending request.");
873 CADestroyToken(gToken);
874 return convertCAResultToSPResult(result);
876 SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
877 if (SP_RESULT_SUCCESS != res)
879 OC_LOG(ERROR, TAG, "Timeout while getting method list.");
880 CADestroyToken(gToken);
881 return SP_RESULT_TIMEOUT;
883 if (gStateManager && SP_LIST_METHODS_DONE)
885 deviceInfo->pstat = gPstat;
886 CADestroyToken(gToken);
887 OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
888 return SP_RESULT_SUCCESS;
890 CADestroyToken(gToken);
891 return SP_RESULT_INTERNAL_ERROR;
895 * Function to update the operation mode. As per the spec. Operation mode in client driven
896 * single service provisioning it will be updated to 0x3
898 * @param[in] timeout timeout for operation.
899 * @param[in] deviceInfo Device Info.
900 * @return SP_SUCCESS on success
902 static SPResult updateOperationMode(unsigned short timeout,
903 SPTargetDeviceInfo_t *deviceInfo,
904 OicSecDpom_t selectedOperationMode)
907 SPResult res = SP_RESULT_INTERNAL_ERROR;
909 deviceInfo->pstat->om = selectedOperationMode;
911 char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
912 if (NULL == payloadBuffer)
914 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
915 return SP_RESULT_INTERNAL_ERROR;
918 size_t payloadLen = strlen(payloadBuffer);
919 handler = &OperationModeUpdateHandler;
920 gStateManager |= SP_UPDATE_OP_MODE_STARTED;
922 CAResult_t result = sendCARequest(CA_PUT,
923 &deviceInfo->endpoint,
926 payloadBuffer, payloadLen);
927 if (CA_STATUS_OK != result)
929 OC_LOG(ERROR, TAG, "Error while sending request.");
930 CADestroyToken(gToken);
931 OICFree(payloadBuffer);
932 return convertCAResultToSPResult(result);
934 res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
935 if (SP_RESULT_SUCCESS != res)
937 OC_LOG(ERROR, TAG, "Internal Error occured");
938 CADestroyToken(gToken);
939 OICFree(payloadBuffer);
940 return SP_RESULT_TIMEOUT;
942 CADestroyToken(gToken);
943 OICFree(payloadBuffer);
945 if (gStateManager & SP_UPDATE_OP_MODE_DONE)
947 return SP_RESULT_SUCCESS;
949 return SP_RESULT_INTERNAL_ERROR;
953 * Function to initiate DTLS handshake.
955 * @param[in] deviceInfo Provisioning context
956 * @return SP_SUCCESS on success
958 static SPResult initiateDtlsHandshake(const CAEndpoint_t *endpoint)
960 CAResult_t caresult = CAEnableAnonECDHCipherSuite(true);
961 if (CA_STATUS_OK != caresult)
963 OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
964 return SP_RESULT_INTERNAL_ERROR;
966 OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
968 caresult = CAInitiateHandshake(endpoint);
969 if (CA_STATUS_OK != caresult)
971 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
974 return SP_RESULT_SUCCESS;
978 * Function to send ownerShip info. This function would update Owned as true and
979 * owner as UUID for provisioning tool
981 * @param[in] timeout timeout value for the operation.
982 * @param[in] deviceInfo provisioning context.
983 * @return SP_SUCCESS on success
985 static SPResult sendOwnershipInfo(unsigned short timeout,
986 SPTargetDeviceInfo_t *selectedDeviceInfo)
988 OicUuid_t provTooldeviceID = {};
990 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
992 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
993 return SP_RESULT_INTERNAL_ERROR;
995 memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
997 selectedDeviceInfo->doxm->owned = true;
999 char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm);
1000 if (NULL == payloadBuffer)
1002 OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1003 return SP_RESULT_INTERNAL_ERROR;
1005 int payloadLen = strlen(payloadBuffer);
1007 handler = &OwnerShipUpdateHandler;
1008 gStateManager |= SP_UPDATE_OWNER_STARTED;
1010 CAResult_t result = sendCARequest(CA_PUT,
1011 &selectedDeviceInfo->endpoint,
1014 payloadBuffer, payloadLen);
1015 if (CA_STATUS_OK != result)
1017 OC_LOG(ERROR, TAG, "Error while sending request.");
1018 CADestroyToken(gToken);
1019 OICFree(payloadBuffer);
1020 return convertCAResultToSPResult(result);
1022 SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1023 if (SP_RESULT_SUCCESS != res)
1025 OC_LOG(ERROR, TAG, "Internal Error occured");
1026 CADestroyToken(gToken);
1027 OICFree(payloadBuffer);
1028 return SP_RESULT_TIMEOUT;
1030 CADestroyToken(gToken);
1031 OICFree(payloadBuffer);
1032 return SP_RESULT_SUCCESS;
1036 * Function to save ownerPSK at provisioning tool end.
1038 * @return SP_SUCCESS on success
1040 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1042 SPResult result = SP_RESULT_INTERNAL_ERROR;
1044 CAEndpoint_t endpoint = {};
1045 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1046 endpoint.port = CA_SECURE_PORT;
1048 OicUuid_t provTooldeviceID = {};
1049 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1051 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1055 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1057 //Generating OwnerPSK
1058 CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
1059 (uint8_t *)OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1060 sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1061 sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1062 OWNER_PSK_LENGTH_128);
1064 if (CA_STATUS_OK == pskRet)
1066 OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1067 OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1068 //Generating new credential for provisioning tool
1070 uint32_t outLen = 0;
1072 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1073 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1075 if (B64_OK == b64Ret)
1077 OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1078 SYMMETRIC_PAIR_WISE_KEY, NULL,
1079 base64Buff, ownLen, &provTooldeviceID);
1082 //Update the SVR database.
1083 if (OC_STACK_OK == AddCredential(cred))
1085 result = SP_RESULT_SUCCESS;
1089 OC_LOG(ERROR, TAG, "AddCredential failed");
1094 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1099 OC_LOG(ERROR, TAG, "b64Encode failed");
1104 OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1110 * Function to select operation mode.This function will return most secure common operation mode.
1112 * @param[out] selectedMode selected operation mode
1113 * @return SP_SUCCESS on success
1115 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1116 OicSecDpom_t **selectedMode)
1120 while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1122 if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1126 else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1130 else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1132 *selectedMode = &(gProvisioningToolCapability[j]);
1139 * Function to perform onwership tranfer based to ownership transfer mode.
1141 * @param[in] timeout timeout in secs to perform operation. 0 timeout means
1142 function will wait forever.
1143 * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1144 * @return SP_SUCCESS on success
1146 static SPResult doOwnerShipTransfer(unsigned short timeout,
1147 SPTargetDeviceInfo_t *selectedDeviceInfo)
1149 OicSecDpom_t *selectedOperationMode = NULL;
1150 selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1152 SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1153 if (SP_RESULT_SUCCESS != res)
1155 OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1156 return SP_RESULT_INTERNAL_ERROR;
1158 if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1160 CAEndpoint_t endpoint = {0};
1161 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1162 endpoint.port = CA_SECURE_PORT;
1164 res = initiateDtlsHandshake(&endpoint);
1165 if (SP_RESULT_SUCCESS == res)
1167 selectedDeviceInfo->endpoint.port = CA_SECURE_PORT;
1168 res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1169 if (SP_RESULT_SUCCESS != res)
1171 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1173 res = saveOwnerPSK(selectedDeviceInfo);
1175 //Close temporal DTLS session
1176 if(CA_STATUS_OK != CACloseDtlsSession(&endpoint))
1178 OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to close the dtls session");
1183 OC_LOG(ERROR, TAG, "Error during initiating DTLS handshake.");
1186 //Disable Anonymous ECDH cipher suite before leaving this method
1187 if(CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false))
1189 OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to disable Anon ECDH cipher suite");
1192 return (res != SP_RESULT_SUCCESS) ? SP_RESULT_INTERNAL_ERROR : SP_RESULT_SUCCESS;
1197 * Function to provision credentials to specific device.
1199 * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will
1201 * @param[in] cred credential to be provisioned.
1202 * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for
1204 * @return SP_SUCCESS on success
1206 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1207 const SPDevInfo_t *deviceInfo)
1209 char *credJson = NULL;
1210 credJson = BinToCredJSON(cred);
1211 if (NULL == credJson)
1213 OC_LOG(ERROR, TAG, "Memory allocation problem");
1214 return SP_RESULT_MEM_ALLOCATION_FAIL;
1217 int payloadLen = strlen(credJson);
1218 handler = &CredProvisioningHandler;
1219 gStateManager |= SP_PROV_CRED_STARTED;
1221 CAResult_t result = sendCARequest(CA_POST,
1222 &deviceInfo->endpoint,
1225 credJson, payloadLen);
1227 if (CA_STATUS_OK != result)
1229 OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1230 CADestroyToken(gToken);
1231 return convertCAResultToSPResult(result);
1234 SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1235 if (SP_RESULT_SUCCESS != res)
1237 OC_LOG(ERROR, TAG, "Internal Error occured");
1238 CADestroyToken(gToken);
1239 return SP_RESULT_TIMEOUT;
1241 CADestroyToken(gToken);
1246 SPResult SPProvisioningDiscovery(unsigned short timeout,
1247 SPTargetDeviceInfo_t **list)
1251 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1252 return SP_RESULT_INVALID_PARAM;
1255 CARegisterHandler(SPRequestHandler, SPResponseHandler, SPErrorHandler);
1256 SPResult smResponse = SP_RESULT_SUCCESS;
1257 smResponse = findResource(timeout);
1258 if (SP_RESULT_SUCCESS != smResponse)
1260 return SP_RESULT_INTERNAL_ERROR;
1262 if (gStateManager & SP_DISCOVERY_DONE)
1264 if (gStateManager & SP_DISCOVERY_ERROR)
1266 return SP_RESULT_INTERNAL_ERROR;
1268 *list = gStartOfDiscoveredDevices;
1269 return SP_RESULT_SUCCESS;
1271 return SP_RESULT_INTERNAL_ERROR;
1274 SPResult SPInitProvisionContext(unsigned short timeout,
1275 SPTargetDeviceInfo_t *selectedDeviceInfo)
1277 if (NULL == selectedDeviceInfo )
1279 return SP_RESULT_INVALID_PARAM;
1282 SPResult res = SP_RESULT_SUCCESS;
1283 OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1285 selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1287 OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1288 res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1290 if (SP_RESULT_SUCCESS != res)
1292 OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1293 return SP_RESULT_INTERNAL_ERROR;
1296 res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1297 if (SP_RESULT_SUCCESS != res)
1299 OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1300 return SP_RESULT_INTERNAL_ERROR;
1302 OC_LOG(INFO, TAG, "Starting ownership transfer");
1303 return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1307 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1310 if (NULL == selectedDeviceInfo || NULL == acl)
1312 return SP_RESULT_INVALID_PARAM;
1314 char *aclString = NULL;
1315 aclString = BinToAclJSON(acl);
1317 if (NULL == aclString)
1319 OC_LOG(ERROR, TAG, "Memory allocation problem");
1320 return SP_RESULT_MEM_ALLOCATION_FAIL;
1323 int payloadLen = strlen(aclString);
1324 handler = &ACLProvisioningHandler;
1325 gStateManager |= SP_PROV_ACL_STARTED;
1327 CAResult_t result = sendCARequest(CA_POST,
1328 &selectedDeviceInfo->endpoint,
1331 aclString, payloadLen);
1333 if (CA_STATUS_OK != result)
1335 OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1336 CADestroyToken(gToken);
1337 return convertCAResultToSPResult(result);
1340 SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1341 if (SP_RESULT_SUCCESS != res)
1343 OC_LOG(ERROR, TAG, "Internal Error occured");
1344 CADestroyToken(gToken);
1345 return SP_RESULT_TIMEOUT;
1347 CADestroyToken(gToken);
1351 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1352 const SPDevInfo_t *pDevList)
1354 if (NULL == pDevList)
1356 return SP_RESULT_INVALID_PARAM;
1358 const SPDevInfo_t *curr = pDevList;
1359 OicUuid_t provTooldeviceID = {};
1360 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1362 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1363 return SP_RESULT_INTERNAL_ERROR;
1365 //TODO Need to support other key types in future.
1368 case SYMMETRIC_PAIR_WISE_KEY:
1370 if (NULL == curr->next)
1372 return SP_RESULT_INVALID_PARAM;
1374 // Devices if present after second node will not be considered.
1375 // in scenario-2. 2 devices are provisioned with credentials.
1376 const SPDevInfo_t *firstDevice = curr;
1377 const SPDevInfo_t *secondDevice = curr->next;
1379 OicSecCred_t *firstCred = NULL;
1380 OicSecCred_t *secondCred = NULL;
1382 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1383 &firstDevice->deviceId, &secondDevice->deviceId,
1384 &firstCred, &secondCred);
1385 if (res != SP_RESULT_SUCCESS)
1387 OC_LOG(ERROR, TAG, "error while generating credentials");
1388 return SP_RESULT_INTERNAL_ERROR;
1390 res = provisionCredentials(timeout, firstCred, firstDevice);
1391 if (SP_RESULT_SUCCESS != res)
1393 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1394 DeleteCredList(firstCred);
1395 DeleteCredList(secondCred);
1396 return SP_RESULT_INTERNAL_ERROR;
1398 res = provisionCredentials(timeout, secondCred, secondDevice);
1399 if (SP_RESULT_SUCCESS != res)
1401 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1402 DeleteCredList(firstCred);
1403 DeleteCredList(secondCred);
1404 return SP_RESULT_INTERNAL_ERROR;
1406 DeleteCredList(firstCred);
1407 DeleteCredList(secondCred);
1408 return SP_RESULT_SUCCESS;
1412 OC_LOG(ERROR, TAG, "Invalid option.");
1413 return SP_RESULT_INVALID_PARAM;
1415 return SP_RESULT_INTERNAL_ERROR;
1419 SPResult SPFinalizeProvisioning(unsigned short timeout,
1420 SPTargetDeviceInfo_t *selectedDeviceInfo)
1423 if (NULL == selectedDeviceInfo)
1425 OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1426 return SP_RESULT_INVALID_PARAM;
1429 uint16_t aclHash = 0; // value for beachhead version.
1430 selectedDeviceInfo->pstat->commitHash = aclHash;
1431 selectedDeviceInfo->pstat->tm = NORMAL;
1432 char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1433 if (NULL == payloadBuffer)
1435 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1436 return SP_RESULT_INTERNAL_ERROR;
1438 int payloadLen = strlen(payloadBuffer);
1440 handler = &FinalizeProvisioningHandler;
1441 gStateManager |= SP_UP_HASH_STARTED;
1443 CAResult_t result = sendCARequest(CA_PUT,
1444 &selectedDeviceInfo->endpoint,
1447 payloadBuffer, payloadLen);
1448 OICFree(payloadBuffer);
1449 if (CA_STATUS_OK != result)
1451 OC_LOG(ERROR, TAG, "Internal Error occured");
1452 CADestroyToken(gToken);
1453 return convertCAResultToSPResult(result);
1456 SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1457 if (SP_RESULT_SUCCESS != res)
1459 OC_LOG(ERROR, TAG, "Internal Error occured");
1460 CADestroyToken(gToken);
1461 return SP_RESULT_TIMEOUT;
1464 CAEndpoint_t endpoint = {};
1465 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1466 endpoint.port = CA_SECURE_PORT;
1468 result = CACloseDtlsSession(&endpoint);
1469 if (CA_STATUS_OK != result)
1471 OC_LOG(WARNING, TAG, "Failed to close the DTLS session.");
1474 CADestroyToken(gToken);
1480 SPResult SPTerminateProvisioning()
1483 return SP_RESULT_SUCCESS;;