1 /* *****************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * *****************************************************************/
21 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1b, Real-time extensions
24 // (IEEE Std 1003.1b-1993) specification
26 // For this specific file, see use of clock_gettime,
27 // Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
28 // and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
30 #ifndef _POSIX_C_SOURCE
31 #define _POSIX_C_SOURCE 200809L
41 #include "oic_malloc.h"
44 #include "cainterface.h"
45 #include "provisioningmanager.h"
46 #include "credentialgenerator.h"
49 #include "aclresource.h"
50 #include "doxmresource.h"
51 #include "pstatresource.h"
52 #include "srmresourcestrings.h"
53 #include "credresource.h"
58 SP_DISCOVERY_STARTED = (0x1 << 1),
59 SP_DISCOVERY_ERROR = (0x1 << 2),
60 SP_DISCOVERY_DONE = (0x1 << 3),
61 SP_UP_OWN_TR_METH_STARTED = (0x1 << 4),
62 SP_UP_OWN_TR_METH_ERROR = (0x1 << 5),
63 SP_UP_OWN_TR_METH_DONE = (0x1 << 6),
64 SP_LIST_METHODS_STARTED = (0x1 << 7),
65 SP_LIST_METHODS_ERROR = (0x1 << 8),
66 SP_LIST_METHODS_DONE = (0x1 << 9),
67 SP_UPDATE_OP_MODE_STARTED = (0x1 << 10),
68 SP_UPDATE_OP_MODE_ERROR = (0x1 << 11),
69 SP_UPDATE_OP_MODE_DONE = (0x1 << 12),
70 SP_UPDATE_OWNER_STARTED = (0x1 << 13),
71 SP_UPDATE_OWNER_ERROR = (0x1 << 14),
72 SP_UPDATE_OWNER_DONE = (0x1 << 15),
73 SP_PROV_ACL_STARTED = (0x1 << 16),
74 SP_PROV_ACL_ERROR = (0x1 << 17),
75 SP_PROV_ACL_DONE = (0x1 << 18),
76 SP_UP_HASH_STARTED = (0x1 << 19),
77 SP_UP_HASH_ERROR = (0x1 << 20),
78 SP_UP_HASH_DONE = (0x1 << 21),
79 SP_PROV_CRED_STARTED = (0x1 << 22),
80 SP_PROV_CRED_ERROR = (0x1 << 23),
81 SP_PROV_CRED_DONE = (0x1 << 24)
83 } SPProvisioningStates;
85 #define SP_MAX_BUF_LEN 1024
86 #define TAG "SPProvisionAPI"
87 #define COAP_QUERY "coap://%s:%d%s"
88 #define COAPS_QUERY "coaps://%s:%d%s"
89 #define CA_SECURE_PORT 5684
91 void (*handler)(const CAEndpoint_t *, const CAResponseInfo_t *);
94 * CA token to keep track of response.
96 static CAToken_t gToken = NULL;
99 * start pointer for discovered device linked list.
101 static SPTargetDeviceInfo_t *gStartOfDiscoveredDevices = NULL;
104 * current pointer of device linked list.
106 static SPTargetDeviceInfo_t *gCurrent = NULL;
109 * Variable to keep track of various request.
111 static uint32_t gStateManager = 0;
114 * Variable for storing provisioning tool's provisioning capabilities
115 * Must be in decreasing order of preference. More prefered method should
116 * have lower array index.
118 static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN };
121 * Number of supported provisioning methods
122 * current version supports only one.
124 static int gNumOfProvisioningMethodsPT = 1;
127 * Global variable to save pstat.
129 static OicSecPstat_t *gPstat = NULL;
132 * Secure String copy function
133 * @param[in] destination Pointer to destination string.
134 * @param[in] source Pointer to source string.
135 * @return pointer to destination string, NULL in case of error.
137 static inline char *SPStringCopy(char *destination, const char *source, size_t num)
139 if (strncpy(destination, source, num))
141 destination[num - 1] = '\0';
148 * Function to convert CA result code to SP result code.
150 * @return result code of SP corresponding to that of CA.
152 static SPResult convertCAResultToSPResult(CAResult_t caResult)
158 return SP_RESULT_SUCCESS;
160 case CA_STATUS_INVALID_PARAM:
162 return SP_RESULT_CONN_INVALID_PARAM;
164 case CA_ADAPTER_NOT_ENABLED:
166 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
168 case CA_SERVER_STARTED_ALREADY:
170 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
172 case CA_SERVER_NOT_STARTED:
174 return SP_RESULT_CONN_SERVER_NOT_STARTED;
176 case CA_DESTINATION_NOT_REACHABLE:
178 return SP_RESULT_CONN_DESTINATION_NOT_REACHABLE;
180 case CA_SOCKET_OPERATION_FAILED:
182 return SP_RESULT_CONN_SOCKET_OPERATION_FAILED;
186 return SP_RESULT_CONN_SEND_FAILED;
188 case CA_RECEIVE_FAILED:
190 return SP_RESULT_CONN_RECEIVE_FAILED;
192 case CA_MEMORY_ALLOC_FAILED:
194 return SP_RESULT_CONN_MEMORY_ALLOC_FAILED;
196 case CA_REQUEST_TIMEOUT:
198 return SP_RESULT_CONN_REQUEST_TIMEOUT;
200 case CA_DESTINATION_DISCONNECTED:
202 return SP_RESULT_CONN_DESTINATION_DISCONNECTED;
204 case CA_STATUS_FAILED:
206 return SP_RESULT_CONN_STATUS_FAILED;
208 case CA_NOT_SUPPORTED:
210 return SP_RESULT_CONN_NOT_SUPPORTED;
214 return SP_RESULT_INTERNAL_ERROR;
220 * Function to delete memory allocated to linked list.
223 static void deleteList()
225 SPTargetDeviceInfo_t *current = gStartOfDiscoveredDevices;
229 SPTargetDeviceInfo_t *next = current->next;
230 DeleteDoxmBinData(current->doxm);
231 DeletePstatBinData(current->pstat);
235 gStartOfDiscoveredDevices = NULL;
239 * Timeout implementation.
240 * @param[in] timeout Timeout in seconds. with 0 it will wait forever for success.
241 * @param[in] mask Mask of operation and 0 for no mask.
242 * @return SP_RESULT_SUCCESS on success otherwise error.
244 static SPResult SPTimeout(unsigned short timeout, uint32_t mask)
246 struct timespec startTime = {};
247 struct timespec currTime = {};
249 CAResult_t res = SP_RESULT_SUCCESS;
250 #ifdef _POSIX_MONOTONIC_CLOCK
251 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
253 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
257 return SP_RESULT_INTERNAL_ERROR;
259 while (CA_STATUS_OK == res)
261 res = CAHandleRequestResponse();
262 #ifdef _POSIX_MONOTONIC_CLOCK
263 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
265 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
269 return SP_RESULT_INTERNAL_ERROR;
271 long elapsed = (currTime.tv_sec - startTime.tv_sec);
272 if (SP_NO_MASK == mask)
274 if (elapsed > timeout)
276 return SP_RESULT_SUCCESS;
281 if (gStateManager & mask)
283 return SP_RESULT_SUCCESS;
285 if ((elapsed > timeout) && timeout)
287 return SP_RESULT_INTERNAL_ERROR;
291 return convertCAResultToSPResult(res);
295 * Function to send request to resource server.
296 * @param[in] method method to be used for sending rquest.
297 * @param[in] endpoint endpoint address
298 * @param[in] secure use secure connection
299 * @param[in] resourceUri resourceUri token.
300 * @param[in] payload Payload to be sent with data. NULL is case message
301 * doesn't have payload.
302 * @param[in] payloadLen Size of data to be sent.
303 * @return CA_STATUS_OK on success, otherwise error code.
305 static CAResult_t sendCARequest(CAMethod_t method,
306 const OCDevAddr *devAddr,
307 OCTransportFlags secure,
308 const char *resourceUri,
309 char *payload, int payloadLen)
311 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
313 OC_LOG(ERROR, TAG, "Error while generating token");
314 return CA_MEMORY_ALLOC_FAILED;
317 CAEndpoint_t *endpoint = NULL;
318 if (CA_STATUS_OK != CACreateEndpoint((CATransportFlags_t)secure,
319 devAddr->adapter, devAddr->addr,
320 devAddr->port, &endpoint))
322 OC_LOG(ERROR, TAG, "Failed to create remote endpoint");
323 CADestroyEndpoint(endpoint);
324 return CA_STATUS_FAILED;
326 CAMessageType_t msgType = CA_MSG_CONFIRM;
327 CAInfo_t requestData = { 0 };
328 requestData.token = gToken;
329 requestData.tokenLength = CA_MAX_TOKEN_LEN;
330 if (payload && '\0' != (*(payload + payloadLen)))
332 OC_LOG(ERROR, TAG, "Payload not properly terminated.");
333 CADestroyEndpoint(endpoint);
334 return CA_STATUS_INVALID_PARAM;
336 requestData.payload = payload;
337 requestData.type = msgType;
338 CARequestInfo_t requestInfo = { 0 };
339 requestInfo.method = method;
340 requestInfo.info = requestData;
341 requestInfo.isMulticast = false;
342 CAResult_t caResult = CA_STATUS_OK;
343 caResult = CASendRequest(endpoint, &requestInfo);
344 if (CA_STATUS_OK != caResult)
346 OC_LOG(ERROR, TAG, "Send Request Error !!");
348 CADestroyEndpoint(endpoint);
355 * @param[in] ip IP of target device.
356 * @param[in] port port of remote server.
357 * @param[in] adapter adapter type of endpoint.
358 * @param[in] doxm pointer to doxm instance.
359 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
361 static SPResult addDevice(const char *ip, int port, OCTransportAdapter adapter, OicSecDoxm_t *doxm)
363 if (NULL == ip || 0 >= port)
365 return SP_RESULT_INVALID_PARAM;
367 SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *)OICCalloc(1, sizeof (SPTargetDeviceInfo_t));
370 OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
371 return SP_RESULT_MEM_ALLOCATION_FAIL;
374 SPStringCopy(ptr->endpoint.addr, ip, MAX_ADDR_STR_SIZE);
375 ptr->endpoint.port = port;
376 ptr->endpoint.adapter = adapter;
382 if (NULL == gStartOfDiscoveredDevices)
384 gStartOfDiscoveredDevices = ptr;
389 gCurrent->next = ptr;
392 return SP_RESULT_SUCCESS;
396 * Function to provide timeframe in which response can be received.
398 * @param[in] timeout Timeout in seconds.
399 * @return SP_RESULT_SUCCESS on success , otherwise error code.
401 static SPResult SPWaitForResponse(unsigned short timeout)
403 return SPTimeout(timeout, SP_NO_MASK);
407 * Function to select appropriate provisioning method.
409 * @param[in] supportedMethodsList List of supported methods
410 * @param[out] selectedMethod Selected methods
411 * @return SP_SUCCESS on success
413 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
414 OicSecOxm_t *selectedMethod)
417 TODO Logic to find appropiate method and assign it to out param
418 for beachhead release method at index 0 will be returned.
420 *selectedMethod = supportedMethods[0];
421 return SP_RESULT_SUCCESS;
425 * Response handler for discovery.
427 * @param[in] object Remote endpoint object
428 * @param[in] requestInfo Datastructure containing request information.
430 static void 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->addr, object->port, object->adapter, 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;
486 * Response handler ownership transfer.
488 * @param[in] object Remote endpoint object
489 * @param[in] requestInfo Datastructure containing request information.
491 static void OwnerShipTransferModeHandler(const CAEndpoint_t *object,
492 const CAResponseInfo_t *responseInfo)
494 if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken)
496 // response handler for ownership tranfer
497 OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler.");
498 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
500 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result);
501 if (CA_SUCCESS == responseInfo->result)
503 gStateManager |= SP_UP_OWN_TR_METH_DONE;
504 OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler.");
508 gStateManager |= SP_UP_OWN_TR_METH_ERROR;
509 OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler.");
516 * Response handler list methods.
518 * @param[in] object Remote endpoint object
519 * @param[in] requestInfo Datastructure containing request information.
521 static void ListMethodsHandler(const CAEndpoint_t *object,
522 const CAResponseInfo_t *responseInfo)
524 if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
526 OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
527 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
529 OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
530 if (CA_SUCCESS == responseInfo->result)
532 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
533 // Temp logic to trim oc attribute from json
534 // JSONToPstatBin should handle OC in JSON.
535 if (NULL == responseInfo->info.payload)
537 OC_LOG(ERROR, TAG, "response payload is null.");
538 gStateManager |= SP_LIST_METHODS_ERROR;
542 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
543 if (NULL == pTempPayload)
545 OC_LOG(ERROR, TAG, "Error in memory allocation.");
546 gStateManager |= SP_LIST_METHODS_ERROR;
550 strcpy(pTempPayload, responseInfo->info.payload + 8);
551 pTempPayload[strlen(pTempPayload) - 2] = '\0';
553 OicSecPstat_t *pstat = JSONToPstatBin(pTempPayload);
556 OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
557 OICFree(pTempPayload);
558 gStateManager |= SP_LIST_METHODS_ERROR;
561 OICFree(pTempPayload);
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.type = msgType;
785 requestData.resourceUri = DOXM_OWNED_FALSE_MULTICAST_QUERY;
786 CARequestInfo_t requestInfo = { 0 };
787 requestInfo.method = CA_GET;
788 requestInfo.info = requestData;
789 requestInfo.isMulticast = true;
790 res = CASendRequest(&endpoint, &requestInfo);
792 handler = &ProvisionDiscoveryHandler;
793 gStateManager |= SP_DISCOVERY_STARTED;
794 if (CA_STATUS_OK != res)
796 OC_LOG(ERROR, TAG, "Error while finding resource.");
797 return convertCAResultToSPResult(res);
801 OC_LOG(INFO, TAG, "Discovery Request sent successfully");
803 return SPWaitForResponse(timeout);
807 * Function to update the operation mode. As per the spec. Operation mode in client driven
808 * single service provisioning it will be updated to 0x3
810 * @param[in] timeout timeout for operation.
811 * @param[in] deviceInfo Device Info.
812 * @return SP_SUCCESS on success
814 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
815 SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
817 SPResult res = SP_RESULT_INTERNAL_ERROR;
819 deviceInfo->doxm->oxmSel = selectedMethod;
820 char *payload = BinToDoxmJSON(deviceInfo->doxm);
823 OC_LOG(ERROR, TAG, "Error while converting bin to json");
824 return SP_RESULT_INTERNAL_ERROR;
826 OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
827 int payloadLen = strlen(payload);
829 handler = &OwnerShipTransferModeHandler;
830 gStateManager |= SP_UP_OWN_TR_METH_STARTED;
832 CAResult_t result = sendCARequest(CA_PUT,
833 &deviceInfo->endpoint,
836 payload, payloadLen);
838 if (CA_STATUS_OK != result)
840 OC_LOG(ERROR, TAG, "Error while sending request.");
841 CADestroyToken(gToken);
842 return convertCAResultToSPResult(result);
844 res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
845 if (SP_RESULT_SUCCESS != res)
847 OC_LOG(ERROR, TAG, "Internal Error occured");
848 CADestroyToken(gToken);
849 return SP_RESULT_TIMEOUT;
851 CADestroyToken(gToken);
852 return SP_RESULT_SUCCESS;
856 * Function to send request to resource to get its pstat resource information.
858 * @param[in] timeout timeout for operation.
859 * @param[in] deviceInfo Device Info.
860 * @return SP_SUCCESS on success
862 static SPResult getProvisioningStatusResource(unsigned short timeout,
863 SPTargetDeviceInfo_t *deviceInfo)
865 handler = &ListMethodsHandler;
866 gStateManager |= SP_LIST_METHODS_STARTED;
868 CAResult_t result = sendCARequest(CA_GET,
869 &deviceInfo->endpoint,
873 if (CA_STATUS_OK != result)
875 OC_LOG(ERROR, TAG, "Failure while sending request.");
876 CADestroyToken(gToken);
877 return convertCAResultToSPResult(result);
879 SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
880 if (SP_RESULT_SUCCESS != res)
882 OC_LOG(ERROR, TAG, "Timeout while getting method list.");
883 CADestroyToken(gToken);
884 return SP_RESULT_TIMEOUT;
886 if (gStateManager && SP_LIST_METHODS_DONE)
888 deviceInfo->pstat = gPstat;
889 CADestroyToken(gToken);
890 OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
891 return SP_RESULT_SUCCESS;
893 CADestroyToken(gToken);
894 return SP_RESULT_INTERNAL_ERROR;
898 * Function to update the operation mode. As per the spec. Operation mode in client driven
899 * single service provisioning it will be updated to 0x3
901 * @param[in] timeout timeout for operation.
902 * @param[in] deviceInfo Device Info.
903 * @return SP_SUCCESS on success
905 static SPResult updateOperationMode(unsigned short timeout,
906 SPTargetDeviceInfo_t *deviceInfo,
907 OicSecDpom_t selectedOperationMode)
910 SPResult res = SP_RESULT_INTERNAL_ERROR;
912 deviceInfo->pstat->om = selectedOperationMode;
914 char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
915 if (NULL == payloadBuffer)
917 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
918 return SP_RESULT_INTERNAL_ERROR;
921 size_t payloadLen = strlen(payloadBuffer);
922 handler = &OperationModeUpdateHandler;
923 gStateManager |= SP_UPDATE_OP_MODE_STARTED;
925 CAResult_t result = sendCARequest(CA_PUT,
926 &deviceInfo->endpoint,
929 payloadBuffer, payloadLen);
930 if (CA_STATUS_OK != result)
932 OC_LOG(ERROR, TAG, "Error while sending request.");
933 CADestroyToken(gToken);
934 OICFree(payloadBuffer);
935 return convertCAResultToSPResult(result);
937 res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
938 if (SP_RESULT_SUCCESS != res)
940 OC_LOG(ERROR, TAG, "Internal Error occured");
941 CADestroyToken(gToken);
942 OICFree(payloadBuffer);
943 return SP_RESULT_TIMEOUT;
945 CADestroyToken(gToken);
946 OICFree(payloadBuffer);
948 if (gStateManager & SP_UPDATE_OP_MODE_DONE)
950 return SP_RESULT_SUCCESS;
952 return SP_RESULT_INTERNAL_ERROR;
956 * Function to initiate DTLS handshake.
958 * @param[in] deviceInfo Provisioning context
959 * @return SP_SUCCESS on success
961 static SPResult initiateDtlsHandshake(const SPTargetDeviceInfo_t *deviceInfo)
963 CAResult_t caresult = CASelectCipherSuite(TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
965 if (CA_STATUS_OK != caresult)
967 OC_LOG(ERROR, TAG, "Unable to select cipher suite");
968 return SP_RESULT_INTERNAL_ERROR;
970 OC_LOG(INFO, TAG, "Anonymous cipher suite selected. ");
971 caresult = CAEnableAnonECDHCipherSuite(true);
972 if (CA_STATUS_OK != caresult)
974 OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
975 return SP_RESULT_INTERNAL_ERROR;
977 OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
979 caresult = CAInitiateHandshake((CAEndpoint_t *)&deviceInfo->endpoint);
980 if (CA_STATUS_OK != caresult)
982 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
985 return SP_RESULT_SUCCESS;
989 * Function to send ownerShip info. This function would update Owned as true and
990 * owner as UUID for provisioning tool
992 * @param[in] timeout timeout value for the operation.
993 * @param[in] deviceInfo provisioning context.
994 * @return SP_SUCCESS on success
996 static SPResult sendOwnershipInfo(unsigned short timeout,
997 SPTargetDeviceInfo_t *selectedDeviceInfo)
999 OicUuid_t provTooldeviceID = {};
1001 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1003 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1004 return SP_RESULT_INTERNAL_ERROR;
1006 memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
1008 selectedDeviceInfo->doxm->owned = true;
1010 char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm);
1011 if (NULL == payloadBuffer)
1013 OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1014 return SP_RESULT_INTERNAL_ERROR;
1016 int payloadLen = strlen(payloadBuffer);
1018 handler = &OwnerShipUpdateHandler;
1019 gStateManager |= SP_UPDATE_OWNER_STARTED;
1021 CAResult_t result = sendCARequest(CA_PUT,
1022 &selectedDeviceInfo->endpoint,
1025 payloadBuffer, payloadLen);
1026 if (CA_STATUS_OK != result)
1028 OC_LOG(ERROR, TAG, "Error while sending request.");
1029 CADestroyToken(gToken);
1030 OICFree(payloadBuffer);
1031 return convertCAResultToSPResult(result);
1033 SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1034 if (SP_RESULT_SUCCESS != res)
1036 OC_LOG(ERROR, TAG, "Internal Error occured");
1037 CADestroyToken(gToken);
1038 OICFree(payloadBuffer);
1039 return SP_RESULT_TIMEOUT;
1041 CADestroyToken(gToken);
1042 OICFree(payloadBuffer);
1043 return SP_RESULT_SUCCESS;
1047 * Function to save ownerPSK at provisioning tool end.
1049 * @return SP_SUCCESS on success
1051 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1053 SPResult result = SP_RESULT_INTERNAL_ERROR;
1055 CAEndpoint_t endpoint = {0};
1056 strncpy(endpoint.addr, selectedDeviceInfo->endpoint.addr, MAX_ADDR_STR_SIZE_CA);
1057 endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';
1058 endpoint.port = CA_SECURE_PORT;
1060 OicUuid_t provTooldeviceID = {};
1061 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1063 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1067 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1069 //Generating OwnerPSK
1070 CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
1071 (uint8_t *)OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1072 sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1073 sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1074 OWNER_PSK_LENGTH_128);
1076 if (CA_STATUS_OK == pskRet)
1078 OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1079 OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1080 //Generating new credential for provisioning tool
1082 uint32_t outLen = 0;
1084 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1085 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1087 if (B64_OK == b64Ret)
1089 OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1090 SYMMETRIC_PAIR_WISE_KEY, NULL,
1091 base64Buff, ownLen, &provTooldeviceID);
1094 //Update the SVR database.
1095 if (OC_STACK_OK == AddCredential(cred))
1097 result = SP_RESULT_SUCCESS;
1101 OC_LOG(ERROR, TAG, "AddCredential failed");
1106 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1111 OC_LOG(ERROR, TAG, "b64Encode failed");
1116 OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1122 * Function to select operation mode.This function will return most secure common operation mode.
1124 * @param[out] selectedMode selected operation mode
1125 * @return SP_SUCCESS on success
1127 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1128 OicSecDpom_t **selectedMode)
1132 while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1134 if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1138 else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1142 else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1144 *selectedMode = &(gProvisioningToolCapability[j]);
1151 * Function to perform onwership tranfer based to ownership transfer mode.
1153 * @param[in] timeout timeout in secs to perform operation. 0 timeout means
1154 function will wait forever.
1155 * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1156 * @return SP_SUCCESS on success
1158 static SPResult doOwnerShipTransfer(unsigned short timeout,
1159 SPTargetDeviceInfo_t *selectedDeviceInfo)
1161 OicSecDpom_t *selectedOperationMode = NULL;
1162 selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1164 SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1165 if (SP_RESULT_SUCCESS != res)
1167 OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1168 return SP_RESULT_INTERNAL_ERROR;
1170 if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1172 res = initiateDtlsHandshake(selectedDeviceInfo);
1173 if (SP_RESULT_SUCCESS != res)
1175 OC_LOG(ERROR, TAG, "Error while DTLS handshake.");
1176 return SP_RESULT_INTERNAL_ERROR;
1179 res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1180 if (SP_RESULT_SUCCESS != res)
1182 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1183 return SP_RESULT_INTERNAL_ERROR;
1186 saveOwnerPSK(selectedDeviceInfo);
1188 return SP_RESULT_SUCCESS;
1193 * Function to provision credentials to specific device.
1195 * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will
1197 * @param[in] cred credential to be provisioned.
1198 * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for
1200 * @return SP_SUCCESS on success
1202 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1203 const SPDevInfo_t *deviceInfo)
1205 char *credJson = NULL;
1206 credJson = BinToCredJSON(cred);
1207 if (NULL == credJson)
1209 OC_LOG(ERROR, TAG, "Memory allocation problem");
1210 return SP_RESULT_MEM_ALLOCATION_FAIL;
1213 int payloadLen = strlen(credJson);
1214 handler = &CredProvisioningHandler;
1215 gStateManager |= SP_PROV_CRED_STARTED;
1217 CAResult_t result = sendCARequest(CA_POST,
1218 &deviceInfo->endpoint,
1221 credJson, payloadLen);
1223 if (CA_STATUS_OK != result)
1225 OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1226 CADestroyToken(gToken);
1227 return convertCAResultToSPResult(result);
1230 SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1231 if (SP_RESULT_SUCCESS != res)
1233 OC_LOG(ERROR, TAG, "Internal Error occured");
1234 CADestroyToken(gToken);
1235 return SP_RESULT_TIMEOUT;
1237 CADestroyToken(gToken);
1241 SPResult SPProvisioningDiscovery(unsigned short timeout,
1242 SPTargetDeviceInfo_t **list)
1246 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1247 return SP_RESULT_INVALID_PARAM;
1250 CARegisterHandler(SPRequestHandler, SPResponseHandler, SPErrorHandler);
1251 SPResult smResponse = SP_RESULT_SUCCESS;
1252 smResponse = findResource(timeout);
1253 if (SP_RESULT_SUCCESS != smResponse)
1255 return SP_RESULT_INTERNAL_ERROR;
1257 if (gStateManager & SP_DISCOVERY_DONE)
1259 if (gStateManager & SP_DISCOVERY_ERROR)
1261 return SP_RESULT_INTERNAL_ERROR;
1263 *list = gStartOfDiscoveredDevices;
1264 return SP_RESULT_SUCCESS;
1266 return SP_RESULT_INTERNAL_ERROR;
1269 SPResult SPInitProvisionContext(unsigned short timeout,
1270 SPTargetDeviceInfo_t *selectedDeviceInfo)
1272 if (NULL == selectedDeviceInfo )
1274 return SP_RESULT_INVALID_PARAM;
1277 SPResult res = SP_RESULT_SUCCESS;
1278 OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1280 selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1282 OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1283 res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1285 if (SP_RESULT_SUCCESS != res)
1287 OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1288 return SP_RESULT_INTERNAL_ERROR;
1291 res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1292 if (SP_RESULT_SUCCESS != res)
1294 OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1295 return SP_RESULT_INTERNAL_ERROR;
1297 OC_LOG(INFO, TAG, "Starting ownership transfer");
1298 return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1302 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1305 if (NULL == selectedDeviceInfo || NULL == acl)
1307 return SP_RESULT_INVALID_PARAM;
1309 char *aclString = NULL;
1310 aclString = BinToAclJSON(acl);
1312 if (NULL == aclString)
1314 OC_LOG(ERROR, TAG, "Memory allocation problem");
1315 return SP_RESULT_MEM_ALLOCATION_FAIL;
1318 int payloadLen = strlen(aclString);
1319 handler = &ACLProvisioningHandler;
1320 gStateManager |= SP_PROV_ACL_STARTED;
1322 CAResult_t result = sendCARequest(CA_POST,
1323 &selectedDeviceInfo->endpoint,
1326 aclString, payloadLen);
1328 if (CA_STATUS_OK != result)
1330 OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1331 CADestroyToken(gToken);
1332 return convertCAResultToSPResult(result);
1335 SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1336 if (SP_RESULT_SUCCESS != res)
1338 OC_LOG(ERROR, TAG, "Internal Error occured");
1339 CADestroyToken(gToken);
1340 return SP_RESULT_TIMEOUT;
1342 CADestroyToken(gToken);
1346 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1347 const SPDevInfo_t *pDevList)
1349 if (NULL == pDevList)
1351 return SP_RESULT_INVALID_PARAM;
1353 const SPDevInfo_t *curr = pDevList;
1354 OicUuid_t provTooldeviceID = {};
1355 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1357 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1358 return SP_RESULT_INTERNAL_ERROR;
1360 //TODO Need to support other key types in future.
1363 case SYMMETRIC_PAIR_WISE_KEY:
1365 if (NULL == curr->next)
1367 return SP_RESULT_INVALID_PARAM;
1369 // Devices if present after second node will not be considered.
1370 // in scenario-2. 2 devices are provisioned with credentials.
1371 const SPDevInfo_t *firstDevice = curr;
1372 const SPDevInfo_t *secondDevice = curr->next;
1374 OicSecCred_t *firstCred = NULL;
1375 OicSecCred_t *secondCred = NULL;
1377 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1378 &firstDevice->deviceId, &secondDevice->deviceId,
1379 &firstCred, &secondCred);
1380 if (res != SP_RESULT_SUCCESS)
1382 OC_LOG(ERROR, TAG, "error while generating credentials");
1383 return SP_RESULT_INTERNAL_ERROR;
1385 res = provisionCredentials(timeout, firstCred, firstDevice);
1386 if (SP_RESULT_SUCCESS != res)
1388 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1389 DeleteCredList(firstCred);
1390 DeleteCredList(secondCred);
1391 return SP_RESULT_INTERNAL_ERROR;
1393 res = provisionCredentials(timeout, secondCred, secondDevice);
1394 if (SP_RESULT_SUCCESS != res)
1396 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1397 DeleteCredList(firstCred);
1398 DeleteCredList(secondCred);
1399 return SP_RESULT_INTERNAL_ERROR;
1401 DeleteCredList(firstCred);
1402 DeleteCredList(secondCred);
1403 return SP_RESULT_SUCCESS;
1407 OC_LOG(ERROR, TAG, "Invalid option.");
1408 return SP_RESULT_INVALID_PARAM;
1410 return SP_RESULT_INTERNAL_ERROR;
1414 SPResult SPFinalizeProvisioning(unsigned short timeout,
1415 SPTargetDeviceInfo_t *selectedDeviceInfo)
1418 if (NULL == selectedDeviceInfo)
1420 OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1421 return SP_RESULT_INVALID_PARAM;
1424 uint16_t aclHash = 0; // value for beachhead version.
1425 selectedDeviceInfo->pstat->commitHash = aclHash;
1426 selectedDeviceInfo->pstat->tm = NORMAL;
1427 char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1428 if (NULL == payloadBuffer)
1430 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1431 return SP_RESULT_INTERNAL_ERROR;
1433 int payloadLen = strlen(payloadBuffer);
1435 handler = &FinalizeProvisioningHandler;
1436 gStateManager |= SP_UP_HASH_STARTED;
1438 CAResult_t result = sendCARequest(CA_PUT,
1439 &selectedDeviceInfo->endpoint,
1442 payloadBuffer, payloadLen);
1443 OICFree(payloadBuffer);
1444 if (CA_STATUS_OK != result)
1446 OC_LOG(ERROR, TAG, "Internal Error occured");
1447 CADestroyToken(gToken);
1448 return convertCAResultToSPResult(result);
1451 SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1452 if (SP_RESULT_SUCCESS != res)
1454 OC_LOG(ERROR, TAG, "Internal Error occured");
1455 CADestroyToken(gToken);
1456 return SP_RESULT_TIMEOUT;
1459 CAEndpoint_t endpoint = {0};
1460 strncpy(endpoint.addr, selectedDeviceInfo->endpoint.addr, MAX_ADDR_STR_SIZE_CA);
1461 endpoint.addr[DEV_ADDR_SIZE_MAX - 1] = '\0';
1462 endpoint.port = CA_SECURE_PORT;
1464 result = CACloseDtlsSession(&endpoint);
1465 if (CA_STATUS_OK != result)
1467 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
1470 CADestroyToken(gToken);
1476 SPResult SPTerminateProvisioning()
1479 return SP_RESULT_SUCCESS;;