Merge branch 'cloud-interface'
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / ocprovisioningmanager.c
1 /* *****************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  * *****************************************************************/
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include "ocprovisioningmanager.h"
24 #include "pmutility.h"
25 #include "ownershiptransfermanager.h"
26 #include "oic_malloc.h"
27 #include "logger.h"
28 #include "secureresourceprovider.h"
29 #include "provisioningdatabasemanager.h"
30 #include "credresource.h"
31 #include "utlist.h"
32 #include "aclresource.h" //Note: SRM internal header
33 #include "pconfresource.h"
34
35 #define TAG "OCPMAPI"
36
37 typedef struct Linkdata Linkdata_t;
38 struct Linkdata
39 {
40     void *ctx;
41     const OCProvisionDev_t *pDev1;
42     OicSecAcl_t *pDev1Acl;
43     const OCProvisionDev_t *pDev2;
44     OicSecAcl_t *pDev2Acl;
45     OCProvisionResult_t *resArr;
46     int numOfResults;
47     int currentCountResults;
48     OCProvisionResultCB resultCallback;
49
50 };
51
52 /**
53  * The function is responsible for initializaton of the provisioning manager. It will load
54  * provisioning database which have owned device's list and their linked status.
55  * TODO: In addition, if there is a device(s) which has not up-to-date credentials, this function will
56  * automatically try to update the deivce(s).
57  *
58  * @param[in] dbPath file path of the sqlite3 db
59  *
60  * @return OC_STACK_OK in case of success and other value otherwise.
61  */
62 OCStackResult OCInitPM(const char* dbPath)
63 {
64     return PDMInit(dbPath);
65 }
66
67 /**
68  * The function is responsible for discovery of device is current subnet. It will list
69  * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as
70  * OCMode.
71  *
72  * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
73  *                    server before returning the list of devices.
74  * @param[out] ppList List of candidate devices to be provisioned
75  * @return OTM_SUCCESS in case of success and other value otherwise.
76  */
77 OCStackResult OCDiscoverUnownedDevices(unsigned short timeout, OCProvisionDev_t **ppList)
78 {
79     if( ppList == NULL || *ppList != NULL || 0 == timeout)
80     {
81         return OC_STACK_INVALID_PARAM;
82     }
83
84     return PMDeviceDiscovery(timeout, false, ppList);
85 }
86
87 /**
88  * The function is responsible for discovery of owned device is current subnet. It will list
89  * all the device in subnet which are owned by calling provisioning client.
90  *
91  * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
92  *                    server before returning the list of devices.
93  * @param[out] ppList List of device owned by provisioning tool.
94  * @return OTM_SUCCESS in case of success and other value otherwise.
95  */
96 OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList)
97 {
98     if( ppList == NULL || *ppList != NULL || 0 == timeout)
99     {
100         return OC_STACK_INVALID_PARAM;
101     }
102
103     return PMDeviceDiscovery(timeout, true, ppList);
104 }
105
106 /**
107  * API to register for particular OxM.
108  *
109  * @param[in] Ownership transfer method.
110  * @param[in] Implementation of callback functions for owership transfer.
111  * @return  OC_STACK_OK in case of success and other value otherwise.
112  */
113 OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData)
114 {
115     if(NULL == callbackData)
116     {
117         return OC_STACK_INVALID_CALLBACK ;
118     }
119
120     return OTMSetOwnershipTransferCallbackData(oxm, callbackData);
121 }
122
123 OCStackResult OCDoOwnershipTransfer(void* ctx,
124                                       OCProvisionDev_t *targetDevices,
125                                       OCProvisionResultCB resultCallback)
126 {
127     if( NULL == targetDevices )
128     {
129         return OC_STACK_INVALID_PARAM;
130     }
131     if (!resultCallback)
132     {
133         OIC_LOG(INFO, TAG, "OCDoOwnershipTransfer : NULL Callback");
134         return OC_STACK_INVALID_CALLBACK;
135     }
136     return OTMDoOwnershipTransfer(ctx, targetDevices, resultCallback);
137 }
138
139 /**
140  * This function deletes memory allocated to linked list created by OCDiscover_XXX_Devices API.
141  *
142  * @param[in] pList Pointer to OCProvisionDev_t which should be deleted.
143  */
144 void OCDeleteDiscoveredDevices(OCProvisionDev_t *pList)
145 {
146     PMDeleteDeviceList(pList);
147 }
148
149 /**
150  * this function sends ACL information to resource.
151  *
152  * @param[in] ctx Application context would be returned in result callback.
153  * @param[in] selectedDeviceInfo Selected target device.
154  * @param[in] acl ACL to provision.
155  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
156               request recieves a response from resource server.
157  * @return  OC_STACK_OK in case of success and other value otherwise.
158  */
159 OCStackResult OCProvisionACL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
160                              OCProvisionResultCB resultCallback)
161 {
162     return SRPProvisionACL(ctx, selectedDeviceInfo, acl, resultCallback);
163 }
164
165 /**
166  * this function requests CRED information to resource.
167  *
168  * @param[in] ctx Application context would be returned in result callback.
169  * @param[in] selectedDeviceInfo Selected target device.
170  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
171               request recieves a response from resource server.
172  * @return  OC_STACK_OK in case of success and other value otherwise.
173  */
174 OCStackResult OCGetCredResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
175                              OCProvisionResultCB resultCallback)
176 {
177     return SRPGetCredResource(ctx, selectedDeviceInfo, resultCallback);
178 }
179
180 /**
181  * this function requests ACL information to resource.
182  *
183  * @param[in] ctx Application context would be returned in result callback.
184  * @param[in] selectedDeviceInfo Selected target device.
185  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
186               request recieves a response from resource server.
187  * @return  OC_STACK_OK in case of success and other value otherwise.
188  */
189 OCStackResult OCGetACLResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
190                              OCProvisionResultCB resultCallback)
191 {
192     return SRPGetACLResource(ctx, selectedDeviceInfo, resultCallback);
193 }
194
195 /**
196  * function to provision credential to devices.
197  *
198  * @param[in] ctx Application context would be returned in result callback.
199  * @param[in] type Type of credentials to be provisioned to the device.
200  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
201    @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
202  * @param[in] resultCallback callback provided by API user, callback will be called when
203  *            provisioning request recieves a response from first resource server.
204  * @return  OC_STACK_OK in case of success and other value otherwise.
205  */
206 OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
207                                       const OCProvisionDev_t *pDev1,
208                                       const OCProvisionDev_t *pDev2,
209                                       OCProvisionResultCB resultCallback)
210 {
211     return SRPProvisionCredentials(ctx, type, keySize,
212                                       pDev1, pDev2, resultCallback);
213
214 }
215
216 /**
217  * this function sends Direct-Pairing Configuration to a device.
218  *
219  * @param[in] ctx Application context would be returned in result callback.
220  * @param[in] selectedDeviceInfo Selected target device.
221  * @param[in] pconf PCONF pointer.
222  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
223               request recieves a response from resource server.
224  * @return  OC_STACK_OK in case of success and other value otherwise.
225  */
226 OCStackResult OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecPconf_t *pconf,
227                              OCProvisionResultCB resultCallback)
228 {
229     return SRPProvisionDirectPairing(ctx, selectedDeviceInfo, pconf, resultCallback);
230 }
231
232 /*
233 * Function to unlink devices.
234 * This function will remove the credential & relationship between the two devices.
235 *
236 * @param[in] ctx Application context would be returned in result callback
237 * @param[in] pTargetDev1 first device information to be unlinked.
238 * @param[in] pTargetDev2 second device information to be unlinked.
239 * @param[in] resultCallback callback provided by API user, callback will be called when
240 *            device unlink is finished.
241  * @return  OC_STACK_OK in case of success and other value otherwise.
242 */
243 OCStackResult OCUnlinkDevices(void* ctx,
244                               const OCProvisionDev_t* pTargetDev1,
245                               const OCProvisionDev_t* pTargetDev2,
246                               OCProvisionResultCB resultCallback)
247 {
248     OIC_LOG(INFO, TAG, "IN OCUnlinkDevices");
249     OCUuidList_t* idList = NULL;
250     size_t numOfDev = 0;
251
252     if (!pTargetDev1 || !pTargetDev2 || !pTargetDev1->doxm || !pTargetDev2->doxm)
253     {
254         OIC_LOG(ERROR, TAG, "OCUnlinkDevices : NULL parameters");
255         return OC_STACK_INVALID_PARAM;
256     }
257     if (!resultCallback)
258     {
259         OIC_LOG(INFO, TAG, "OCUnlinkDevices : NULL Callback");
260         return OC_STACK_INVALID_CALLBACK;
261     }
262     if (0 == memcmp(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID, sizeof(OicUuid_t)))
263     {
264         OIC_LOG(INFO, TAG, "OCUnlinkDevices : Same device ID");
265         return OC_STACK_INVALID_PARAM;
266     }
267
268     // Get linked devices with the first device.
269     OCStackResult res = PDMGetLinkedDevices(&(pTargetDev1->doxm->deviceID), &idList, &numOfDev);
270     if (OC_STACK_OK != res)
271     {
272         OIC_LOG(ERROR, TAG, "OCUnlinkDevices : PDMgetOwnedDevices failed");
273         goto error;
274     }
275     if (1 > numOfDev)
276     {
277         OIC_LOG(DEBUG, TAG, "OCUnlinkDevices : Can not find linked devices");
278         res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made
279         goto error;
280     }
281
282     // Check the linked devices contains the second device. If yes send credential DELETE request.
283     OCUuidList_t* curDev = idList;
284     while (NULL != curDev)
285     {
286         if (memcmp(pTargetDev2->doxm->deviceID.id, curDev->dev.id, sizeof(curDev->dev.id)) == 0)
287         {
288             res = SRPUnlinkDevices(ctx, pTargetDev1, pTargetDev2, resultCallback);
289             if (OC_STACK_OK != res)
290             {
291                 OIC_LOG(ERROR, TAG, "OCUnlinkDevices : Failed to unlink devices.");
292             }
293             goto error;
294         }
295         curDev = curDev->next;
296     }
297     OIC_LOG(DEBUG, TAG, "No matched pair found from provisioning database");
298     res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made
299
300 error:
301     OIC_LOG(INFO, TAG, "OUT OCUnlinkDevices");
302
303     PDMDestoryOicUuidLinkList(idList);
304     return res;
305 }
306
307 /*
308 * Function to device revocation
309 * This function will remove credential of target device from all devices in subnet.
310 *
311 * @param[in] ctx Application context would be returned in result callback
312 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
313 * @param[in] pTargetDev Device information to be revoked.
314 * @param[in] resultCallback callback provided by API user, callback will be called when
315 *            credential revocation is finished.
316  * @return  OC_STACK_OK in case of success and other value otherwise.
317 */
318 OCStackResult OCRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
319                             const OCProvisionDev_t* pTargetDev,
320                             OCProvisionResultCB resultCallback)
321 {
322     OIC_LOG(INFO, TAG, "IN OCRemoveDevice");
323     OCStackResult res = OC_STACK_ERROR;
324     if (!pTargetDev || 0 == waitTimeForOwnedDeviceDiscovery)
325     {
326         OIC_LOG(INFO, TAG, "OCRemoveDevice : Invalied parameters");
327         return OC_STACK_INVALID_PARAM;
328     }
329     if (!resultCallback)
330     {
331         OIC_LOG(INFO, TAG, "OCRemoveDevice : NULL Callback");
332         return OC_STACK_INVALID_CALLBACK;
333     }
334
335     // Send DELETE requests to linked devices
336     OCStackResult resReq = OC_STACK_ERROR; // Check that we have to wait callback or not.
337     resReq = SRPRemoveDevice(ctx, waitTimeForOwnedDeviceDiscovery, pTargetDev, resultCallback);
338     if (OC_STACK_OK != resReq)
339     {
340         if (OC_STACK_CONTINUE == resReq)
341         {
342             OIC_LOG(DEBUG, TAG, "OCRemoveDevice : Revoked device has no linked device except PT.");
343         }
344         else
345         {
346             OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to invoke SRPRemoveDevice");
347             res = resReq;
348             goto error;
349         }
350     }
351
352     // Remove credential of revoked device from SVR database
353     const OicSecCred_t *cred = NULL;
354     cred = GetCredResourceData(&pTargetDev->doxm->deviceID);
355     if (cred == NULL)
356     {
357         OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to get credential of remove device.");
358         goto error;
359     }
360
361     res = RemoveCredential(&cred->subject);
362     if (res != OC_STACK_RESOURCE_DELETED)
363     {
364         OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to remove credential.");
365         goto error;
366     }
367
368     /**
369      * Change the device status as stale status.
370      * If all request are successed, this device information will be deleted.
371      */
372     res = PDMSetDeviceStale(&pTargetDev->doxm->deviceID);
373     if (res != OC_STACK_OK)
374     {
375         OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to set device status as stale");
376         goto error;
377     }
378
379     // TODO: We need to add new mechanism to clean up the stale state of the device.
380
381     res = resReq;
382
383     //Close the DTLS session of the removed device.
384     CAEndpoint_t* endpoint = (CAEndpoint_t *)&pTargetDev->endpoint;
385     endpoint->port = pTargetDev->securePort;
386     CAResult_t caResult = CACloseDtlsSession(endpoint);
387     if(CA_STATUS_OK != caResult)
388     {
389         OIC_LOG_V(WARNING, TAG, "OCRemoveDevice : Failed to close DTLS session : %d", caResult);
390     }
391
392     /**
393      * If there is no linked device, PM does not send any request.
394      * So we should directly invoke the result callback to inform the result of OCRemoveDevice.
395      */
396     if(OC_STACK_CONTINUE == res)
397     {
398         if(resultCallback)
399         {
400             resultCallback(ctx, 0, NULL, false);
401         }
402         res = OC_STACK_OK;
403     }
404
405 error:
406     OIC_LOG(INFO, TAG, "OUT OCRemoveDevice");
407     return res;
408 }
409
410 /*
411  * Function to reset the target device.
412  * This function will remove credential and ACL of target device from all devices in subnet.
413  *
414  * @param[in] ctx Application context would be returned in result callback
415  * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
416  * @param[in] pTargetDev Device information to be revoked.
417  * @param[in] resultCallback callback provided by API user, callback will be called when
418  *            credential revocation is finished.
419  * @return  OC_STACK_OK in case of success and other value otherwise.
420  */
421 OCStackResult OCResetDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
422                             const OCProvisionDev_t* pTargetDev,
423                             OCProvisionResultCB resultCallback)
424 {
425     OIC_LOG(INFO, TAG, "IN OCResetDevice");
426     OCStackResult res = OC_STACK_ERROR;
427     if (!pTargetDev || 0 == waitTimeForOwnedDeviceDiscovery)
428     {
429         OIC_LOG(INFO, TAG, "OCResetDevice : Invalid parameters");
430         return OC_STACK_INVALID_PARAM;
431     }
432     if (!resultCallback)
433     {
434         OIC_LOG(INFO, TAG, "OCResetDevice : NULL Callback");
435         return OC_STACK_INVALID_CALLBACK;
436     }
437
438     // Send DELETE requests to linked devices
439     res = SRPSyncDevice(ctx, waitTimeForOwnedDeviceDiscovery, pTargetDev, resultCallback);
440     if (OC_STACK_CONTINUE == res)
441     {
442         OIC_LOG(DEBUG, TAG, "OCResetDevice : Target device has no linked device except PT.");
443         if(resultCallback)
444         {
445             resultCallback(ctx, 0, NULL, false);
446         }
447         SRPResetDevice(pTargetDev, resultCallback);
448         res = OC_STACK_OK;
449     }
450     else if(OC_STACK_OK != res)
451     {
452         OIC_LOG(ERROR, TAG, "OCResetDevice : Failed to invoke SRPSyncDevice");
453     }
454     OIC_LOG(INFO, TAG, "OUT OCResetDevice");
455     return res;
456 }
457
458 /**
459  * Internal Function to update result in link result array.
460  */
461 static void UpdateLinkResults(Linkdata_t *link, int device, OCStackResult stackresult)
462 {
463
464     OIC_LOG_V(INFO,TAG,"value of link->currentCountResults is %d",link->currentCountResults);
465     if (1 == device)
466     {
467         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev1->doxm->deviceID.id,UUID_LENGTH);
468     }
469     else
470     {
471         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev2->doxm->deviceID.id,UUID_LENGTH);
472     }
473     link->resArr[(link->currentCountResults)].res = stackresult;
474     ++(link->currentCountResults);
475
476 }
477
478 /**
479  * Callback to handle ACL provisioning for device 2.
480  */
481 static void AclProv2CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
482 {
483
484     if (NULL == ctx)
485     {
486         OIC_LOG(ERROR,TAG,"Context is Null in ACLProv 2");
487         return;
488     }
489     (void)nOfRes;
490     Linkdata_t *link = (Linkdata_t*)ctx;
491     OCProvisionResultCB resultCallback = link->resultCallback;
492
493
494     if (hasError)
495     {
496         UpdateLinkResults(link, 2,arr[0].res);
497         OIC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
498         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
499                                                 link->resArr,
500                                                 true);
501         OICFree(link->resArr);
502         OICFree(link) ;
503         return;
504     }
505     UpdateLinkResults(link, 2, arr[0].res);
506    ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
507                                            link->resArr,
508                                            false);
509     OICFree(link->resArr);
510     OICFree(link);
511     return;
512 }
513
514 /**
515  * Callback to handle ACL provisioning for device 1
516  */
517 static void AclProv1CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
518 {
519
520     if (NULL == ctx)
521     {
522         OIC_LOG(ERROR,TAG,"Context is Null in ACLProv1");
523         return;
524     }
525     (void)nOfRes;
526     Linkdata_t *link = (Linkdata_t*)ctx;
527     OCProvisionResultCB resultCallback = link->resultCallback;
528
529     if (hasError)
530     {
531         OIC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
532         UpdateLinkResults(link, 1, arr[0].res);
533         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
534                                                 link->resArr,
535                                                 true);
536         OICFree(link->resArr);
537         OICFree(link);
538         return;
539     }
540     UpdateLinkResults(link, 1, arr[0].res);
541     if (NULL != link->pDev2Acl)
542     {
543         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
544         if (OC_STACK_OK!=res)
545         {
546              UpdateLinkResults(link, 2, res);
547              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
548                                                      link->resArr,
549                                                      true);
550
551         }
552     }
553     else
554     {
555         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
556                                                 link->resArr,
557                                                 false);
558         OICFree(link->resArr);
559         OICFree(link);
560     }
561
562     return;
563 }
564
565 /**
566  * Callback to handle credential provisioning.
567  */
568 static void ProvisionCredsCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
569 {
570     if (NULL == ctx)
571     {
572         OIC_LOG(ERROR,TAG,"Error occured while credential provisioning");
573         return;
574     }
575     Linkdata_t *link = (Linkdata_t*)ctx;
576     OCProvisionResultCB resultCallback = link->resultCallback;
577     OIC_LOG_V(INFO, TAG, "has error returned %d",hasError);
578     UpdateLinkResults(link, 1, arr[0].res);
579     UpdateLinkResults(link, 2, arr[1].res);
580     if (hasError)
581     {
582         OIC_LOG(ERROR,TAG,"Error occured while credential provisioning");
583         ((OCProvisionResultCB)(resultCallback))(link->ctx, nOfRes,
584                                                 link->resArr,
585                                                 true);
586          OICFree(link->resArr);
587          OICFree(link);
588          return;
589     }
590     if (NULL != link->pDev1Acl)
591     {
592
593         OCStackResult res =  SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, &AclProv1CB);
594         if (OC_STACK_OK!=res)
595         {
596              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 1");
597              UpdateLinkResults(link, 1, res);
598              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
599                                                      link->resArr,
600                                                      true);
601               OICFree(link->resArr);
602               OICFree(link);
603         }
604     }
605     else if (NULL!=link->pDev2Acl)
606     {
607         OIC_LOG(ERROR, TAG, "ACL for device 1 is NULL");
608         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
609         if (OC_STACK_OK!=res)
610         {
611              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 2");
612               UpdateLinkResults(link, 2, res);
613              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
614                                                      link->resArr,
615                                                      true);
616               OICFree(link->resArr);
617               OICFree(link);
618         }
619     }
620     else
621     {
622         OIC_LOG(INFO, TAG, "ACLs of both devices are NULL");
623         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
624                                                 link->resArr,
625                                                 false);
626         OICFree(link->resArr);
627         OICFree(link);
628     }
629     return;
630 }
631 /**
632  * function to provision credentials between two devices and ACLs for the devices who act as a server.
633  *
634  * @param[in] ctx Application context would be returned in result callback.
635  * @param[in] type Type of credentials to be provisioned to the device.
636  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
637  * @param[in] acl ACL for device 1. If this is not required set NULL.
638  * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
639  * @param[in] acl ACL for device 2. If this is not required set NULL.
640  * @param[in] resultCallback callback provided by API user, callback will be called when
641  *            provisioning request recieves a response from first resource server.
642  * @return  OC_STACK_OK in case of success and other value otherwise.
643  */
644 OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,
645                                          const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,
646                                          const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,
647                                          OCProvisionResultCB resultCallback)
648 {
649
650     if (!pDev1 || !pDev2 || !pDev1->doxm || !pDev2->doxm)
651     {
652         OIC_LOG(ERROR, TAG, "OCProvisionPairwiseDevices : Invalid parameters");
653         return OC_STACK_INVALID_PARAM;
654     }
655     if (!resultCallback)
656     {
657         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : NULL Callback");
658         return OC_STACK_INVALID_CALLBACK;
659     }
660     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
661     {
662         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Invalid key size");
663         return OC_STACK_INVALID_PARAM;
664     }
665     if (0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t)))
666     {
667         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Same device ID");
668         return OC_STACK_INVALID_PARAM;
669     }
670
671     OIC_LOG(DEBUG, TAG, "Checking link in DB");
672     bool linkExists = true;
673     OCStackResult res = PDMIsLinkExists(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, &linkExists);
674     if(res != OC_STACK_OK)
675     {
676         OIC_LOG(ERROR, TAG, "Internal Error Occured");
677         return res;
678     }
679     if (linkExists)
680     {
681         OIC_LOG(ERROR, TAG, "Link already exists");
682         return OC_STACK_INVALID_PARAM;
683     }
684
685     int noOfResults = 2; // Initial Value
686     if (NULL != pDev1Acl)
687     {
688         ++noOfResults;
689     }
690     if (NULL != pDev2Acl)
691     {
692        ++noOfResults;
693     }
694     Linkdata_t *link = (Linkdata_t*) OICMalloc(sizeof(Linkdata_t));
695     if (!link)
696     {
697         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
698         return OC_STACK_NO_MEMORY;
699     }
700     OIC_LOG_V(INFO,TAG, "Maximum no od results %d",noOfResults);
701
702     link->pDev1 = pDev1;
703     link->pDev1Acl = pDev1Acl;
704     link->pDev2 = pDev2;
705     link->pDev2Acl = pDev2Acl;
706     link->ctx = ctx;
707     // 1 call for each device for credential provisioning. implict call by SRPProvisioning credential
708     // 1 call for ACL provisioning for device 1 and 1 call for ACL provisioning for device 2.
709     link->numOfResults = noOfResults;
710     link->resultCallback = resultCallback;
711     link->currentCountResults = 0;
712     link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
713     res = SRPProvisionCredentials(link, type, keySize,
714                                      pDev1, pDev2, &ProvisionCredsCB);
715     if (res != OC_STACK_OK)
716     {
717         OICFree(link->resArr);
718         OICFree(link);
719     }
720     return res;
721
722 }
723
724 OCStackResult OCGetDevInfoFromNetwork(unsigned short waittime,
725                                        OCProvisionDev_t** pOwnedDevList,
726                                        OCProvisionDev_t** pUnownedDevList)
727 {
728     //TODO will be replaced by more efficient logic
729     if (pOwnedDevList == NULL || *pOwnedDevList != NULL || pUnownedDevList == NULL
730          || *pUnownedDevList != NULL || 0 == waittime)
731     {
732         return OC_STACK_INVALID_PARAM;
733     }
734
735     // Code for unowned discovery
736     OCProvisionDev_t *unownedDevice = NULL;
737     OCStackResult res =  OCDiscoverUnownedDevices(waittime/2, &unownedDevice);
738     if (OC_STACK_OK != res)
739     {
740         OIC_LOG(ERROR,TAG, "Error in unowned discovery");
741         return res;
742     }
743
744     // Code for owned discovery
745     OCProvisionDev_t *ownedDevice = NULL;
746     res =  OCDiscoverOwnedDevices(waittime/2, &ownedDevice);
747     if (OC_STACK_OK != res)
748     {
749         OIC_LOG(ERROR,TAG, "Error in owned discovery");
750         PMDeleteDeviceList(unownedDevice);
751         return res;
752     }
753
754     // Code to get list of all the owned devices.
755     OCUuidList_t *uuidList = NULL;
756     size_t numOfDevices = 0;
757     res =  PDMGetOwnedDevices(&uuidList, &numOfDevices);
758     if (OC_STACK_OK != res)
759     {
760         OIC_LOG(ERROR, TAG, "Error while getting info from DB");
761         PMDeleteDeviceList(unownedDevice);
762         PMDeleteDeviceList(ownedDevice);
763         return res;
764     }
765
766     // Code to compare devices in owned list and deviceid from DB.
767     OCProvisionDev_t* pCurDev = ownedDevice;
768     size_t deleteCnt = 0;
769     while (pCurDev)
770     {
771         if(true == PMDeleteFromUUIDList(uuidList, &pCurDev->doxm->deviceID))
772         {
773             deleteCnt++;
774         }
775         pCurDev = pCurDev->next;
776     }
777     // If there is no remaind device in uuidList, we have to assign NULL to prevent free.
778     if (deleteCnt == numOfDevices)
779     {
780         uuidList = NULL;
781     }
782     // Code to add information of the devices which are currently off in owned list.
783     OCUuidList_t *powerOffDeviceList = uuidList;
784     while (powerOffDeviceList)
785     {
786         OCProvisionDev_t *ptr = (OCProvisionDev_t *)OICCalloc(1, sizeof (OCProvisionDev_t));
787         if (NULL == ptr)
788         {
789             OIC_LOG(ERROR,TAG,"Fail to allocate memory");
790             PMDeleteDeviceList(unownedDevice);
791             PMDeleteDeviceList(ownedDevice);
792             OCDeleteUuidList(uuidList);
793             return OC_STACK_NO_MEMORY;
794         }
795
796         ptr->doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
797         if (NULL == ptr->doxm)
798         {
799             OIC_LOG(ERROR,TAG,"Fail to allocate memory");
800             PMDeleteDeviceList(unownedDevice);
801             PMDeleteDeviceList(ownedDevice);
802             OCDeleteUuidList(uuidList);
803             OICFree(ptr);
804             return OC_STACK_NO_MEMORY;
805         }
806
807         memcpy(ptr->doxm->deviceID.id, powerOffDeviceList->dev.id, sizeof(ptr->doxm->deviceID.id));
808
809         ptr->devStatus = DEV_STATUS_OFF;
810         LL_PREPEND(ownedDevice, ptr);
811         powerOffDeviceList = powerOffDeviceList->next;
812
813     }
814     OCDeleteUuidList(uuidList);
815     *pOwnedDevList = ownedDevice;
816     *pUnownedDevList = unownedDevice;
817     return OC_STACK_OK;
818 }
819
820 OCStackResult OCGetLinkedStatus(const OicUuid_t* uuidOfDevice, OCUuidList_t** uuidList,
821                                  size_t* numOfDevices)
822 {
823     return PDMGetLinkedDevices(uuidOfDevice, uuidList, numOfDevices);
824 }
825
826 void OCDeleteUuidList(OCUuidList_t* pList)
827 {
828     PDMDestoryOicUuidLinkList(pList);
829 }
830
831 /**
832  * This function deletes ACL data.
833  *
834  * @param pAcl Pointer to OicSecAcl_t structure.
835  */
836 void OCDeleteACLList(OicSecAcl_t* pAcl)
837 {
838     DeleteACLList(pAcl);
839 }
840
841 /**
842  * This function deletes PDACL data.
843  *
844  * @param pPdAcl Pointer to OicSecPdAcl_t structure.
845  */
846 void OCDeletePdAclList(OicSecPdAcl_t* pPdAcl)
847 {
848     FreePdAclList(pPdAcl);
849 }
850
851
852 #ifdef __WITH_X509__
853 /**
854  * this function sends CRL information to resource.
855  *
856  * @param[in] ctx Application context would be returned in result callback.
857  * @param[in] selectedDeviceInfo Selected target device.
858  * @param[in] crl CRL to provision.
859  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
860               request recieves a response from resource server.
861  * @return  OC_STACK_OK in case of success and other value otherwise.
862  */
863 OCStackResult OCProvisionCRL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecCrl_t *crl,
864                              OCProvisionResultCB resultCallback)
865 {
866     return SRPProvisionCRL(ctx, selectedDeviceInfo, crl, resultCallback);
867 }
868 #endif // __WITH_X509__
869