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"
37 #include "oic_malloc.h"
38 #include "oic_string.h"
40 #define ES_PROV_TAG "EASY_SETUP_PROVISIONING"
42 bool gProvisioningCondFlag = false;
44 static ProvConfig *gProvConfig;
45 static WiFiOnboadingConnection *gOnboardConn;
46 static char gSzFindResourceQueryUri[64] =
51 * @brief Callback for providing provisioning status callback to application
53 static OCProvisioningStatusCB cbData = NULL;
56 * Utility function for error callback.
58 void ErrorCallback(ProvStatus status)
60 ProvisioningInfo *provInfo = GetCallbackObjectOnError(status);
68 * Functions implementing the exposed APIs.
70 OCStackResult InitProvisioningHandler()
72 OCStackResult ret = OC_STACK_ERROR;
73 /* Initialize OCStack*/
74 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
76 OIC_LOG(ERROR, ES_PROV_TAG, "OCStack init error");
83 OCStackResult StartProvisioningProcess(const ProvConfig *netInfo,
84 WiFiOnboadingConnection *onboardConn, OCProvisioningStatusCB provisioningStatusCallback,
88 if (findResQuery != NULL)
90 OICStrcpy(gSzFindResourceQueryUri, sizeof(gSzFindResourceQueryUri) - 1, findResQuery);
94 OIC_LOG(ERROR, ES_PROV_TAG, PCF("Find resource query is NULL"));
98 pthread_t thread_handle;
100 if (!ValidateEasySetupParams(netInfo, onboardConn, provisioningStatusCallback))
105 if (!SetProgress(provisioningStatusCallback))
107 // Device provisioning session is running already.
108 OIC_LOG(INFO, ES_PROV_TAG, PCF("Device provisioning session is running already"));
112 if (!ConfigEnrolleeObject(netInfo, onboardConn))
117 if (pthread_create(&thread_handle, NULL, FindProvisioningResource, NULL))
123 pthread_join(thread_handle, NULL);
129 ErrorCallback(DEVICE_NOT_PROVISIONED);
131 return OC_STACK_ERROR;
136 void StopProvisioningProcess()
141 OCStackResult TerminateProvisioningHandler()
143 OCStackResult ret = OC_STACK_ERROR;
144 if (OCStop() != OC_STACK_OK)
146 OIC_LOG(ERROR, ES_PROV_TAG, "OCStack stop error");
149 gProvisioningCondFlag = true;
156 OCStackApplicationResult TriggerNetworkConnectionResponse(void* /*ctx*/, OCDoHandle /*handle*/,
157 OCClientResponse *clientResponse)
159 OIC_LOG_V(DEBUG, ES_PROV_TAG, "INSIDE TriggerNetworkConnectionResponse");
161 // If user stopped the process then return from this function;
162 if (IsSetupStopped())
164 ErrorCallback(DEVICE_NOT_PROVISIONED);
166 return OC_STACK_DELETE_TRANSACTION;
169 if (!ValidateEnrolleeBasicResponse(clientResponse))
171 ErrorCallback(DEVICE_NOT_PROVISIONED);
172 return OC_STACK_DELETE_TRANSACTION;
175 SuccessCallback(clientResponse);
176 return OC_STACK_KEEP_TRANSACTION;
179 OCStackResult TriggerNetworkConnection(OCQualityOfService qos, const char *query,
180 const char *resUri, OCDevAddr *destination, int /*pauseBeforeStart*/)
182 OIC_LOG_V(INFO, ES_PROV_TAG, "Inside TriggerNetworkConnection");
184 OCRepPayload *payload = OCRepPayloadCreate();
186 OCRepPayloadSetUri(payload, resUri);
187 OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_TR, ES_PS_TRIGGER_CONNECTION);
189 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Triggering network connection from Mediator");
191 OCStackResult ret = InvokeOCDoResource(query, OC_REST_POST, destination, qos,
192 TriggerNetworkConnectionResponse, payload, NULL, 0);
202 OIC_LOG(DEBUG, ES_PROV_TAG, "thread_pool_add_task of FindProvisioningResource failed");
203 OICFree(gProvConfig);
204 OICFree(gOnboardConn);
210 bool ConfigEnrolleeObject(const ProvConfig *netInfo, WiFiOnboadingConnection *connection)
213 //Copy Network Provisioning Information
214 gProvConfig = (ProvConfig *) OICCalloc(1, sizeof(ProvConfig));
215 gOnboardConn = (WiFiOnboadingConnection *) OICCalloc(1, sizeof(WiFiOnboadingConnection));
217 if (gProvConfig == NULL)
219 OIC_LOG(ERROR, ES_PROV_TAG, "Invalid input..");
223 if (gOnboardConn == NULL)
225 OIC_LOG(ERROR, ES_PROV_TAG, "Invalid input..");
229 memcpy(gProvConfig, netInfo, sizeof(ProvConfig));
230 memcpy(gOnboardConn, connection, sizeof(WiFiOnboadingConnection));
232 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Network Provisioning Info. SSID = %s",
233 gProvConfig->provData.WIFI.ssid);
235 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Network Provisioning Info. PWD = %s",
236 gProvConfig->provData.WIFI.pwd);
242 void LogProvisioningResponse(OCRepPayloadValue * val)
247 case OCREP_PROP_NULL:
248 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s: NULL", val->name);
251 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(int):%lld", val->name, val->i);
253 case OCREP_PROP_DOUBLE:
254 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(double):%f", val->name, val->d);
256 case OCREP_PROP_BOOL:
257 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(bool):%s", val->name, val->b ? "true" : "false");
259 case OCREP_PROP_STRING:
260 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(string):%s", val->name, val->str);
262 case OCREP_PROP_OBJECT:
263 // Note: Only prints the URI (if available), to print further, you'll
264 // need to dig into the object better!
265 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(OCRep):%s", val->name, val->obj->uri);
267 case OCREP_PROP_ARRAY:
268 switch (val->arr.type)
271 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(int array):%zu x %zu x %zu",
273 val->arr.dimensions[0], val->arr.dimensions[1],
274 val->arr.dimensions[2]);
276 case OCREP_PROP_DOUBLE:
277 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(double array):%zu x %zu x %zu",
279 val->arr.dimensions[0], val->arr.dimensions[1],
280 val->arr.dimensions[2]);
282 case OCREP_PROP_BOOL:
283 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(bool array):%zu x %zu x %zu",
285 val->arr.dimensions[0], val->arr.dimensions[1],
286 val->arr.dimensions[2]);
288 case OCREP_PROP_STRING:
289 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(string array):%zu x %zu x %zu",
291 val->arr.dimensions[0], val->arr.dimensions[1],
292 val->arr.dimensions[2]);
294 case OCREP_PROP_OBJECT:
295 OIC_LOG_V(DEBUG, ES_PROV_TAG, "\t\t%s(OCRep array):%zu x %zu x %zu",
297 val->arr.dimensions[0], val->arr.dimensions[1],
298 val->arr.dimensions[2]);
309 OCStackResult FindNetworkResource()
311 OCStackResult ret = OC_STACK_ERROR;
312 if (OCStop() != OC_STACK_OK)
314 OIC_LOG(ERROR, ES_PROV_TAG, "OCStack stop error");
320 ProvisioningInfo *PrepareProvisioingStatusCB(OCClientResponse *clientResponse,
321 ProvStatus provStatus)
324 ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
326 if (provInfo == NULL)
328 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
332 OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
336 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
341 OICStrcpy(devAddr->addr, sizeof(devAddr->addr), clientResponse->addr->addr);
343 devAddr->port = clientResponse->addr->port;
345 provInfo->provDeviceInfo.addr = devAddr;
347 provInfo->provStatus = provStatus;
355 // It means already Easy Setup provisioning session is going on.
358 OIC_LOG(ERROR, ES_PROV_TAG, "Easy setup session is already in progress");
365 bool SetProgress(OCProvisioningStatusCB provisioningStatusCallback)
371 cbData = provisioningStatusCallback;
383 ProvisioningInfo *CreateCallBackObject()
386 ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
388 if (provInfo == NULL)
390 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
394 OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
398 OIC_LOG_V(ERROR, ES_PROV_TAG, "Failed to allocate memory");
403 provInfo->provDeviceInfo.addr = devAddr;
409 ProvisioningInfo *GetCallbackObjectOnError(ProvStatus status)
412 ProvisioningInfo *provInfo = CreateCallBackObject();
413 OICStrcpy(provInfo->provDeviceInfo.addr->addr, sizeof(provInfo->provDeviceInfo.addr->addr),
414 gOnboardConn->ipAddress);
416 provInfo->provDeviceInfo.addr->port = IP_PORT;
417 provInfo->provStatus = status;
421 ProvisioningInfo *GetCallbackObjectOnSuccess(OCClientResponse *clientResponse,
422 ProvStatus provStatus)
424 ProvisioningInfo *provInfo = CreateCallBackObject();
425 OICStrcpy(provInfo->provDeviceInfo.addr->addr, sizeof(provInfo->provDeviceInfo.addr->addr),
426 clientResponse->addr->addr);
428 provInfo->provDeviceInfo.addr->port = clientResponse->addr->port;
429 provInfo->provStatus = provStatus;
433 bool ValidateFindResourceResponse(OCClientResponse * clientResponse)
435 if (!(clientResponse) || !(clientResponse->payload))
437 OIC_LOG_V(INFO, ES_PROV_TAG, "Received Null clientResponse");
441 if (clientResponse->payload->type != PAYLOAD_TYPE_DISCOVERY)
443 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Payload is not discovery type");
450 bool ValidateEnrolleeResponse(OCClientResponse * clientResponse)
452 if (!(clientResponse) || !(clientResponse->payload))
454 OIC_LOG_V(INFO, ES_PROV_TAG, "Received Null clientResponse");
458 if (clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
460 OIC_LOG_V(DEBUG, ES_PROV_TAG, "Incoming payload is not a representation");
464 // If flow reachese here means no error condition hit.
468 bool ValidateEnrolleeBasicResponse(OCClientResponse * clientResponse)
472 OIC_LOG_V(INFO, ES_PROV_TAG, "Received Null clientResponse");
476 if(clientResponse->result != OC_STACK_OK)
478 OIC_LOG_V(INFO, ES_PROV_TAG, "Received error response");
482 // If flow reaches, then there no error condition hit.
487 void SuccessCallback(OCClientResponse * clientResponse)
489 ProvisioningInfo *provInfo = GetCallbackObjectOnSuccess(clientResponse, DEVICE_PROVISIONED);
496 void* FindProvisioningResource(void* /*data*/)
499 // If user stopped the process before thread get scheduled then check and return from this function;
500 if (IsSetupStopped())
502 ErrorCallback(DEVICE_NOT_PROVISIONED);
507 OCStackResult ret = OC_STACK_ERROR;
509 OIC_LOG_V(DEBUG, ES_PROV_TAG, "szFindResourceQueryUri = %s", gSzFindResourceQueryUri);
511 OCCallbackData ocCBData;
513 ocCBData.cb = FindProvisioningResourceResponse;
514 ocCBData.context = (void *) EASY_SETUP_DEFAULT_CONTEXT_VALUE;
517 ret = OCDoResource(NULL, OC_REST_DISCOVER, gSzFindResourceQueryUri, NULL, NULL,
518 gProvConfig->connType, OC_LOW_QOS, &ocCBData, NULL, 0);
520 if (ret != OC_STACK_OK)
522 ErrorCallback(DEVICE_NOT_PROVISIONED);
529 OCStackResult InvokeOCDoResource(const char *query, OCMethod method, const OCDevAddr *dest,
530 OCQualityOfService qos, OCClientResponseHandler cb, OCRepPayload *payload,
531 OCHeaderOption *options, uint8_t numOptions)
534 OCCallbackData cbData;
537 cbData.context = (void *) EASY_SETUP_DEFAULT_CONTEXT_VALUE;
540 ret = OCDoResource(NULL, method, query, dest, (OCPayload *) payload, gProvConfig->connType, qos,
541 &cbData, options, numOptions);
543 if (ret != OC_STACK_OK)
545 OIC_LOG_V(ERROR, ES_PROV_TAG, "OCDoResource returns error %d with method %d", ret, method);
551 OCStackResult ProvisionEnrollee(OCQualityOfService qos, const char *query, const char *resUri,
552 OCDevAddr *destination, int pauseBeforeStart)
555 // This sleep is required in case of BLE provisioning due to packet drop issue.
556 OIC_LOG_V(INFO, ES_PROV_TAG, "Sleeping for %d seconds", pauseBeforeStart);
557 sleep(pauseBeforeStart);
558 OIC_LOG_V(INFO, ES_PROV_TAG, "\n\nExecuting ProvisionEnrollee%s", __func__);
560 OCRepPayload *payload = OCRepPayloadCreate();
562 OCRepPayloadSetUri(payload, resUri);
563 OCRepPayloadSetPropString(payload, OC_RSRVD_ES_TNN, gProvConfig->provData.WIFI.ssid);
564 OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CD, gProvConfig->provData.WIFI.pwd);
566 OIC_LOG_V(DEBUG, ES_PROV_TAG, "OCPayload ready for ProvisionEnrollee");
568 OCStackResult ret = InvokeOCDoResource(query, OC_REST_POST, destination, qos,
569 ProvisionEnrolleeResponse, payload, NULL, 0);
574 bool IsSetupStopped()
576 return (cbData == NULL) ? true : false;