1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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 #include "provisioning.h"
31 //EasySetup include files
32 #include "ocpayload.h"
38 #include "oic_malloc.h"
39 #include "oic_string.h"
41 #define ES_PROV_TAG "EASY_SETUP_PROVISIONING"
43 bool g_provisioningCondFlag = false;
45 static EnrolleeNWProvInfo *netProvInfo;
47 char szFindResourceQueryUri[64] = {0};
51 * @brief Callback for providing provisioning status callback to application
53 static OCProvisioningStatusCB cbData = NULL;
56 void ErrorCallback(ProvStatus status) {
57 ProvisioningInfo *provInfo = GetCallbackObjectOnError(status);
63 OCStackResult InitProvisioningHandler() {
64 OCStackResult ret = OC_STACK_ERROR;
65 /* Initialize OCStack*/
66 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK) {
67 OIC_LOG(ERROR, ES_PROV_TAG, "OCStack init error");
72 pthread_t thread_handle;
74 if (pthread_create(&thread_handle, NULL, listeningFunc, NULL)) {
75 OIC_LOG(DEBUG, ES_PROV_TAG, "Thread creation failed");
76 return OC_STACK_ERROR;
82 OCStackResult TerminateProvisioningHandler() {
83 OCStackResult ret = OC_STACK_ERROR;
84 if (OCStop() != OC_STACK_OK) {
85 OIC_LOG(ERROR, ES_PROV_TAG, "OCStack stop error");
88 g_provisioningCondFlag = true;
94 void *listeningFunc(void* /*data*/) {
95 while (!g_provisioningCondFlag) {
100 if (result != OC_STACK_OK) {
101 OIC_LOG(ERROR, ES_PROV_TAG, "OCStack stop error");
104 // To minimize CPU utilization we may wish to do this with sleep
111 OCStackApplicationResult ProvisionEnrolleeResponse(void* /*ctx*/, OCDoHandle /*handle*/,
112 OCClientResponse *clientResponse) {
113 OIC_LOG_V(DEBUG, ES_PROV_TAG, "INSIDE ProvisionEnrolleeResponse");
115 // If user stopped the process then return from this function;
116 if (IsSetupStopped()) {
117 ErrorCallback(DEVICE_NOT_PROVISIONED);
119 return OC_STACK_DELETE_TRANSACTION;
122 if (!ValidateEnrolleResponse(clientResponse)) {
123 ErrorCallback(DEVICE_NOT_PROVISIONED);
124 return OC_STACK_DELETE_TRANSACTION;
130 OCRepPayload *input = (OCRepPayload * )(clientResponse->payload);
135 if (OCRepPayloadGetPropInt(input, OC_RSRVD_ES_PS, &ps)) {
142 OIC_LOG_V(DEBUG, ES_PROV_TAG, "PS is NOT proper");
148 if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_TNN, &tnn)) {
149 if (!strcmp(tnn, netProvInfo->netAddressInfo.WIFI.ssid)) {
150 OIC_LOG_V(DEBUG, ES_PROV_TAG, "SSID is proper");
155 OIC_LOG_V(DEBUG, ES_PROV_TAG, "SSID is NOT proper");
160 if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_CD, &cd)) {
161 if (!strcmp(cd, netProvInfo->netAddressInfo.WIFI.pwd)) {
162 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Password is proper");
167 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Password is NOT proper");
172 LogProvisioningResponse(input->values);
180 SuccessCallback(clientResponse);
182 return OC_STACK_KEEP_TRANSACTION;
189 ErrorCallback(DEVICE_NOT_PROVISIONED);
191 return OC_STACK_DELETE_TRANSACTION;
196 OCStackResult StartProvisioningProcess(const EnrolleeNWProvInfo *netInfo,
197 OCProvisioningStatusCB provisioningStatusCallback,
198 char *findResQuery) {
200 if(findResQuery != NULL)
202 OICStrcpy(szFindResourceQueryUri, sizeof(szFindResourceQueryUri) - 1, findResQuery);
206 OIC_LOG(ERROR, ES_PROV_TAG, PCF("Find resource query is NULL"));
210 pthread_t thread_handle;
212 if (!ValidateEasySetupParams(netInfo, provisioningStatusCallback)) {
216 if (!SetProgress(provisioningStatusCallback)) {
217 // Device provisioning session is running already.
218 OIC_LOG(INFO, ES_PROV_TAG, PCF("Device provisioning session is running already"));
222 if (!ConfigEnrolleeObject(netInfo)) {
226 if (pthread_create(&thread_handle, NULL, FindProvisioningResource, NULL)) {
231 pthread_join(thread_handle, NULL);
238 ErrorCallback(DEVICE_NOT_PROVISIONED);
240 return OC_STACK_ERROR;
245 void StopProvisioningProcess() {
246 //Only basis test is done for below API
252 OIC_LOG(DEBUG, ES_PROV_TAG, "thread_pool_add_task of FindProvisioningResource failed");
253 OICFree(netProvInfo);
258 bool ConfigEnrolleeObject(const EnrolleeNWProvInfo *netInfo) {
260 //Copy Network Provisioning Information
261 netProvInfo = (EnrolleeNWProvInfo *) OICCalloc(1, sizeof(EnrolleeNWProvInfo));
263 if (netProvInfo == NULL) {
264 OIC_LOG(ERROR, ES_PROV_TAG, "Invalid input..");
268 memcpy(netProvInfo, netInfo, sizeof(EnrolleeNWProvInfo));
270 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Network Provisioning Info. SSID = %s",
271 netProvInfo->netAddressInfo.WIFI.ssid);
273 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Network Provisioning Info. PWD = %s",
274 netProvInfo->netAddressInfo.WIFI.pwd);
280 void LogProvisioningResponse(OCRepPayloadValue * val) {
283 case OCREP_PROP_NULL:
284 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s: NULL", val->name);
287 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(int):%lld", val->name, val->i);
289 case OCREP_PROP_DOUBLE:
290 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(double):%f", val->name, val->d);
292 case OCREP_PROP_BOOL:
293 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(bool):%s", val->name, val->b ? "true" : "false");
295 case OCREP_PROP_STRING:
296 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(string):%s", val->name, val->str);
298 case OCREP_PROP_OBJECT:
299 // Note: Only prints the URI (if available), to print further, you'll
300 // need to dig into the object better!
301 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(OCRep):%s", val->name, val->obj->uri);
303 case OCREP_PROP_ARRAY:
304 switch (val->arr.type) {
306 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(int array):%zu x %zu x %zu",
308 val->arr.dimensions[0], val->arr.dimensions[1],
309 val->arr.dimensions[2]);
311 case OCREP_PROP_DOUBLE:
312 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(double array):%zu x %zu x %zu",
314 val->arr.dimensions[0], val->arr.dimensions[1],
315 val->arr.dimensions[2]);
317 case OCREP_PROP_BOOL:
318 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(bool array):%zu x %zu x %zu",
320 val->arr.dimensions[0], val->arr.dimensions[1],
321 val->arr.dimensions[2]);
323 case OCREP_PROP_STRING:
324 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(string array):%zu x %zu x %zu",
326 val->arr.dimensions[0], val->arr.dimensions[1],
327 val->arr.dimensions[2]);
329 case OCREP_PROP_OBJECT:
330 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(OCRep array):%zu x %zu x %zu",
332 val->arr.dimensions[0], val->arr.dimensions[1],
333 val->arr.dimensions[2]);
344 OCStackResult FindNetworkResource() {
345 OCStackResult ret = OC_STACK_ERROR;
346 if (OCStop() != OC_STACK_OK) {
347 OIC_LOG(ERROR, ES_PROV_TAG, "OCStack stop error");
353 ProvisioningInfo *PrepareProvisioingStatusCB(OCClientResponse *clientResponse,
354 ProvStatus provStatus) {
356 ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
358 if (provInfo == NULL) {
359 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
363 OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
365 if (devAddr == NULL) {
366 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
371 OICStrcpy(devAddr->addr, sizeof(devAddr->addr), clientResponse->addr->addr);
373 devAddr->port = clientResponse->addr->port;
375 provInfo->provDeviceInfo.addr = devAddr;
377 provInfo->provStatus = provStatus;
385 // It means already Easy Setup provisioning session is going on.
386 if (NULL != cbData) {
387 OIC_LOG(ERROR, ES_PROV_TAG, "Easy setup session is already in progress");
394 bool SetProgress(OCProvisioningStatusCB provisioningStatusCallback) {
399 cbData = provisioningStatusCallback;
405 bool ResetProgress() {
411 ProvisioningInfo *CreateCallBackObject() {
413 ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
415 if (provInfo == NULL) {
416 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
420 OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
422 if (devAddr == NULL) {
423 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
428 provInfo->provDeviceInfo.addr = devAddr;
434 ProvisioningInfo *GetCallbackObjectOnError(ProvStatus status) {
436 ProvisioningInfo *provInfo = CreateCallBackObject();
437 OICStrcpy(provInfo->provDeviceInfo.addr->addr, sizeof(provInfo->provDeviceInfo.addr->addr),
438 netProvInfo->netAddressInfo.WIFI.ipAddress);
440 provInfo->provDeviceInfo.addr->port = IP_PORT;
441 provInfo->provStatus = status;
445 ProvisioningInfo *GetCallbackObjectOnSuccess(OCClientResponse *clientResponse,
446 ProvStatus provStatus) {
447 ProvisioningInfo *provInfo = CreateCallBackObject();
448 OICStrcpy(provInfo->provDeviceInfo.addr->addr, sizeof(provInfo->provDeviceInfo.addr->addr),
449 clientResponse->addr->addr);
451 provInfo->provDeviceInfo.addr->port = clientResponse->addr->port;
452 provInfo->provStatus = provStatus;
456 bool ValidateFinddResourceResponse(OCClientResponse * clientResponse) {
458 if (!(clientResponse) || !(clientResponse->payload)) {
460 OIC_LOG_V(INFO, ES_PROV_TAG, "ProvisionEnrolleeResponse received Null clientResponse");
468 bool ValidateEnrolleResponse(OCClientResponse * clientResponse) {
470 if (!(clientResponse) || !(clientResponse->payload)) {
472 OIC_LOG_V(INFO, ES_PROV_TAG, "ProvisionEnrolleeResponse received Null clientResponse");
478 if (clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION) {
480 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Incoming payload not a representation");
485 // If flow reachese here means no error condition hit.
490 void SuccessCallback(OCClientResponse * clientResponse) {
491 ProvisioningInfo *provInfo = GetCallbackObjectOnSuccess(clientResponse, DEVICE_PROVISIONED);
496 void* FindProvisioningResource(void* /*data*/) {
498 // If user stopped the process before thread get scheduled then check and return from this function;
499 if (IsSetupStopped()) {
500 ErrorCallback(DEVICE_NOT_PROVISIONED);
505 OCStackResult ret = OC_STACK_ERROR;
507 OIC_LOG_V(DEBUG, ES_PROV_TAG, "szFindResourceQueryUri = %s", szFindResourceQueryUri);
509 OCCallbackData ocCBData;
511 ocCBData.cb = FindProvisioningResourceResponse;
512 ocCBData.context = (void *) EASY_SETUP_DEFAULT_CONTEXT_VALUE;
516 ret = OCDoResource(NULL, OC_REST_DISCOVER, szFindResourceQueryUri, NULL, NULL,
517 netProvInfo->connType, OC_LOW_QOS,
520 if (ret != OC_STACK_OK) {
521 ErrorCallback(DEVICE_NOT_PROVISIONED);
528 OCStackResult InvokeOCDoResource(const char *query, OCMethod method, const OCDevAddr *dest,
529 OCQualityOfService qos, OCClientResponseHandler cb,
530 OCRepPayload *payload,
531 OCHeaderOption *options, uint8_t numOptions) {
533 OCCallbackData cbData;
536 cbData.context = (void *) EASY_SETUP_DEFAULT_CONTEXT_VALUE;
539 ret = OCDoResource(NULL, method, query, dest, (OCPayload *) payload, netProvInfo->connType, qos,
540 &cbData, options, numOptions);
542 if (ret != OC_STACK_OK) {
543 OIC_LOG_V(ERROR, ES_PROV_TAG, "OCDoResource returns error %d with method %d", ret, method);
549 OCStackResult ProvisionEnrollee(OCQualityOfService qos, const char *query, const char *resUri,
550 OCDevAddr *destination, int pauseBeforeStart) {
553 // This sleep is required in case of BLE provisioning due to packet drop issue.
554 OIC_LOG_V(INFO, ES_PROV_TAG, "Sleeping for %d seconds", pauseBeforeStart);
555 sleep(pauseBeforeStart);
556 OIC_LOG_V(INFO, ES_PROV_TAG, "\n\nExecuting ProvisionEnrollee%s", __func__);
558 OCRepPayload *payload = OCRepPayloadCreate();
560 OCRepPayloadSetUri(payload, resUri);
561 OCRepPayloadSetPropString(payload, OC_RSRVD_ES_TNN, netProvInfo->netAddressInfo.WIFI.ssid);
562 OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CD, netProvInfo->netAddressInfo.WIFI.pwd);
564 OIC_LOG_V(DEBUG, ES_PROV_TAG, "OCPayload ready for ProvisionEnrollee");
566 OCStackResult ret = InvokeOCDoResource(query, OC_REST_PUT, destination, qos,
567 ProvisionEnrolleeResponse, payload, NULL, 0);
572 bool IsSetupStopped() {
573 return (cbData == NULL) ? true : false;