Merge "Merge branch '1.1-rel'"
[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  * function to provision credential to devices.
167  *
168  * @param[in] ctx Application context would be returned in result callback.
169  * @param[in] type Type of credentials to be provisioned to the device.
170  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
171    @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
172  * @param[in] resultCallback callback provided by API user, callback will be called when
173  *            provisioning request recieves a response from first resource server.
174  * @return  OC_STACK_OK in case of success and other value otherwise.
175  */
176 OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
177                                       const OCProvisionDev_t *pDev1,
178                                       const OCProvisionDev_t *pDev2,
179                                       OCProvisionResultCB resultCallback)
180 {
181     return SRPProvisionCredentials(ctx, type, keySize,
182                                       pDev1, pDev2, resultCallback);
183
184 }
185
186 /**
187  * this function sends Direct-Pairing Configuration to a device.
188  *
189  * @param[in] ctx Application context would be returned in result callback.
190  * @param[in] selectedDeviceInfo Selected target device.
191  * @param[in] pconf PCONF pointer.
192  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
193               request recieves a response from resource server.
194  * @return  OC_STACK_OK in case of success and other value otherwise.
195  */
196 OCStackResult OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecPconf_t *pconf,
197                              OCProvisionResultCB resultCallback)
198 {
199     return SRPProvisionDirectPairing(ctx, selectedDeviceInfo, pconf, resultCallback);
200 }
201
202 /*
203 * Function to unlink devices.
204 * This function will remove the credential & relationship between the two devices.
205 *
206 * @param[in] ctx Application context would be returned in result callback
207 * @param[in] pTargetDev1 first device information to be unlinked.
208 * @param[in] pTargetDev2 second device information to be unlinked.
209 * @param[in] resultCallback callback provided by API user, callback will be called when
210 *            device unlink is finished.
211  * @return  OC_STACK_OK in case of success and other value otherwise.
212 */
213 OCStackResult OCUnlinkDevices(void* ctx,
214                               const OCProvisionDev_t* pTargetDev1,
215                               const OCProvisionDev_t* pTargetDev2,
216                               OCProvisionResultCB resultCallback)
217 {
218     OIC_LOG(INFO, TAG, "IN OCUnlinkDevices");
219     OCUuidList_t* idList = NULL;
220     size_t numOfDev = 0;
221
222     if (!pTargetDev1 || !pTargetDev2 || !pTargetDev1->doxm || !pTargetDev2->doxm)
223     {
224         OIC_LOG(ERROR, TAG, "OCUnlinkDevices : NULL parameters");
225         return OC_STACK_INVALID_PARAM;
226     }
227     if (!resultCallback)
228     {
229         OIC_LOG(INFO, TAG, "OCUnlinkDevices : NULL Callback");
230         return OC_STACK_INVALID_CALLBACK;
231     }
232     if (0 == memcmp(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID, sizeof(OicUuid_t)))
233     {
234         OIC_LOG(INFO, TAG, "OCUnlinkDevices : Same device ID");
235         return OC_STACK_INVALID_PARAM;
236     }
237
238     // Get linked devices with the first device.
239     OCStackResult res = PDMGetLinkedDevices(&(pTargetDev1->doxm->deviceID), &idList, &numOfDev);
240     if (OC_STACK_OK != res)
241     {
242         OIC_LOG(ERROR, TAG, "OCUnlinkDevices : PDMgetOwnedDevices failed");
243         goto error;
244     }
245     if (1 > numOfDev)
246     {
247         OIC_LOG(DEBUG, TAG, "OCUnlinkDevices : Can not find linked devices");
248         res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made
249         goto error;
250     }
251
252     // Check the linked devices contains the second device. If yes send credential DELETE request.
253     OCUuidList_t* curDev = idList;
254     while (NULL != curDev)
255     {
256         if (memcmp(pTargetDev2->doxm->deviceID.id, curDev->dev.id, sizeof(curDev->dev.id)) == 0)
257         {
258             res = SRPUnlinkDevices(ctx, pTargetDev1, pTargetDev2, resultCallback);
259             if (OC_STACK_OK != res)
260             {
261                 OIC_LOG(ERROR, TAG, "OCUnlinkDevices : Failed to unlink devices.");
262             }
263             goto error;
264         }
265         curDev = curDev->next;
266     }
267     OIC_LOG(DEBUG, TAG, "No matched pair found from provisioning database");
268     res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made
269
270 error:
271     OIC_LOG(INFO, TAG, "OUT OCUnlinkDevices");
272
273     PDMDestoryOicUuidLinkList(idList);
274     return res;
275 }
276
277 /*
278 * Function to device revocation
279 * This function will remove credential of target device from all devices in subnet.
280 *
281 * @param[in] ctx Application context would be returned in result callback
282 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
283 * @param[in] pTargetDev Device information to be revoked.
284 * @param[in] resultCallback callback provided by API user, callback will be called when
285 *            credential revocation is finished.
286  * @return  OC_STACK_OK in case of success and other value otherwise.
287 */
288 OCStackResult OCRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
289                             const OCProvisionDev_t* pTargetDev,
290                             OCProvisionResultCB resultCallback)
291 {
292     OIC_LOG(INFO, TAG, "IN OCRemoveDevice");
293     OCStackResult res = OC_STACK_ERROR;
294     if (!pTargetDev || 0 == waitTimeForOwnedDeviceDiscovery)
295     {
296         OIC_LOG(INFO, TAG, "OCRemoveDevice : Invalied parameters");
297         return OC_STACK_INVALID_PARAM;
298     }
299     if (!resultCallback)
300     {
301         OIC_LOG(INFO, TAG, "OCRemoveDevice : NULL Callback");
302         return OC_STACK_INVALID_CALLBACK;
303     }
304
305     // Send DELETE requests to linked devices
306     OCStackResult resReq = OC_STACK_ERROR; // Check that we have to wait callback or not.
307     resReq = SRPRemoveDevice(ctx, waitTimeForOwnedDeviceDiscovery, pTargetDev, resultCallback);
308     if (OC_STACK_OK != resReq)
309     {
310         if (OC_STACK_CONTINUE == resReq)
311         {
312             OIC_LOG(DEBUG, TAG, "OCRemoveDevice : Revoked device has no linked device except PT.");
313         }
314         else
315         {
316             OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to invoke SRPRemoveDevice");
317             res = resReq;
318             goto error;
319         }
320     }
321
322     // Remove credential of revoked device from SVR database
323     const OicSecCred_t *cred = NULL;
324     cred = GetCredResourceData(&pTargetDev->doxm->deviceID);
325     if (cred == NULL)
326     {
327         OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to get credential of remove device.");
328         goto error;
329     }
330
331     res = RemoveCredential(&cred->subject);
332     if (res != OC_STACK_RESOURCE_DELETED)
333     {
334         OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to remove credential.");
335         goto error;
336     }
337
338     /**
339      * Change the device status as stale status.
340      * If all request are successed, this device information will be deleted.
341      */
342     res = PDMSetDeviceStale(&pTargetDev->doxm->deviceID);
343     if (res != OC_STACK_OK)
344     {
345         OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to set device status as stale");
346         goto error;
347     }
348
349     // TODO: We need to add new mechanism to clean up the stale state of the device.
350
351     res = resReq;
352
353     //Close the DTLS session of the removed device.
354     CAEndpoint_t* endpoint = (CAEndpoint_t *)&pTargetDev->endpoint;
355     endpoint->port = pTargetDev->securePort;
356     CAResult_t caResult = CACloseDtlsSession(endpoint);
357     if(CA_STATUS_OK != caResult)
358     {
359         OIC_LOG_V(WARNING, TAG, "OCRemoveDevice : Failed to close DTLS session : %d", caResult);
360     }
361
362     /**
363      * If there is no linked device, PM does not send any request.
364      * So we should directly invoke the result callback to inform the result of OCRemoveDevice.
365      */
366     if(OC_STACK_CONTINUE == res)
367     {
368         if(resultCallback)
369         {
370             resultCallback(ctx, 0, NULL, false);
371         }
372         res = OC_STACK_OK;
373     }
374
375 error:
376     OIC_LOG(INFO, TAG, "OUT OCRemoveDevice");
377     return res;
378 }
379
380
381 /**
382  * Internal Function to update result in link result array.
383  */
384 static void UpdateLinkResults(Linkdata_t *link, int device, OCStackResult stackresult)
385 {
386
387     OIC_LOG_V(INFO,TAG,"value of link->currentCountResults is %d",link->currentCountResults);
388     if (1 == device)
389     {
390         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev1->doxm->deviceID.id,UUID_LENGTH);
391     }
392     else
393     {
394         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev2->doxm->deviceID.id,UUID_LENGTH);
395     }
396     link->resArr[(link->currentCountResults)].res = stackresult;
397     ++(link->currentCountResults);
398
399 }
400
401 /**
402  * Callback to handle ACL provisioning for device 2.
403  */
404 static void AclProv2CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
405 {
406
407     if (NULL == ctx)
408     {
409         OIC_LOG(ERROR,TAG,"Context is Null in ACLProv 2");
410         return;
411     }
412     (void)nOfRes;
413     Linkdata_t *link = (Linkdata_t*)ctx;
414     OCProvisionResultCB resultCallback = link->resultCallback;
415
416
417     if (hasError)
418     {
419         UpdateLinkResults(link, 2,arr[0].res);
420         OIC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
421         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
422                                                 link->resArr,
423                                                 true);
424         OICFree(link->resArr);
425         OICFree(link) ;
426         return;
427     }
428     UpdateLinkResults(link, 2, arr[0].res);
429    ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
430                                            link->resArr,
431                                            false);
432     OICFree(link->resArr);
433     OICFree(link);
434     return;
435 }
436
437 /**
438  * Callback to handle ACL provisioning for device 1
439  */
440 static void AclProv1CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
441 {
442
443     if (NULL == ctx)
444     {
445         OIC_LOG(ERROR,TAG,"Context is Null in ACLProv1");
446         return;
447     }
448     (void)nOfRes;
449     Linkdata_t *link = (Linkdata_t*)ctx;
450     OCProvisionResultCB resultCallback = link->resultCallback;
451
452     if (hasError)
453     {
454         OIC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
455         UpdateLinkResults(link, 1, arr[0].res);
456         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
457                                                 link->resArr,
458                                                 true);
459         OICFree(link->resArr);
460         OICFree(link);
461         return;
462     }
463     UpdateLinkResults(link, 1, arr[0].res);
464     if (NULL != link->pDev2Acl)
465     {
466         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
467         if (OC_STACK_OK!=res)
468         {
469              UpdateLinkResults(link, 2, res);
470              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
471                                                      link->resArr,
472                                                      true);
473
474         }
475     }
476     else
477     {
478         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
479                                                 link->resArr,
480                                                 false);
481         OICFree(link->resArr);
482         OICFree(link);
483     }
484
485     return;
486 }
487
488 /**
489  * Callback to handle credential provisioning.
490  */
491 static void ProvisionCredsCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
492 {
493     if (NULL == ctx)
494     {
495         OIC_LOG(ERROR,TAG,"Error occured while credential provisioning");
496         return;
497     }
498     Linkdata_t *link = (Linkdata_t*)ctx;
499     OCProvisionResultCB resultCallback = link->resultCallback;
500     OIC_LOG_V(INFO, TAG, "has error returned %d",hasError);
501     UpdateLinkResults(link, 1, arr[0].res);
502     UpdateLinkResults(link, 2, arr[1].res);
503     if (hasError)
504     {
505         OIC_LOG(ERROR,TAG,"Error occured while credential provisioning");
506         ((OCProvisionResultCB)(resultCallback))(link->ctx, nOfRes,
507                                                 link->resArr,
508                                                 true);
509          OICFree(link->resArr);
510          OICFree(link);
511          return;
512     }
513     if (NULL != link->pDev1Acl)
514     {
515
516         OCStackResult res =  SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, &AclProv1CB);
517         if (OC_STACK_OK!=res)
518         {
519              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 1");
520              UpdateLinkResults(link, 1, res);
521              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
522                                                      link->resArr,
523                                                      true);
524               OICFree(link->resArr);
525               OICFree(link);
526         }
527     }
528     else if (NULL!=link->pDev2Acl)
529     {
530         OIC_LOG(ERROR, TAG, "ACL for device 1 is NULL");
531         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
532         if (OC_STACK_OK!=res)
533         {
534              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 2");
535               UpdateLinkResults(link, 2, res);
536              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
537                                                      link->resArr,
538                                                      true);
539               OICFree(link->resArr);
540               OICFree(link);
541         }
542     }
543     else
544     {
545         OIC_LOG(INFO, TAG, "ACLs of both devices are NULL");
546         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
547                                                 link->resArr,
548                                                 false);
549         OICFree(link->resArr);
550         OICFree(link);
551     }
552     return;
553 }
554 /**
555  * function to provision credentials between two devices and ACLs for the devices who act as a server.
556  *
557  * @param[in] ctx Application context would be returned in result callback.
558  * @param[in] type Type of credentials to be provisioned to the device.
559  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
560  * @param[in] acl ACL for device 1. If this is not required set NULL.
561  * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
562  * @param[in] acl ACL for device 2. If this is not required set NULL.
563  * @param[in] resultCallback callback provided by API user, callback will be called when
564  *            provisioning request recieves a response from first resource server.
565  * @return  OC_STACK_OK in case of success and other value otherwise.
566  */
567 OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,
568                                          const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,
569                                          const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,
570                                          OCProvisionResultCB resultCallback)
571 {
572
573     if (!pDev1 || !pDev2 || !pDev1->doxm || !pDev2->doxm)
574     {
575         OIC_LOG(ERROR, TAG, "OCProvisionPairwiseDevices : Invalid parameters");
576         return OC_STACK_INVALID_PARAM;
577     }
578     if (!resultCallback)
579     {
580         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : NULL Callback");
581         return OC_STACK_INVALID_CALLBACK;
582     }
583     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
584     {
585         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Invalid key size");
586         return OC_STACK_INVALID_PARAM;
587     }
588     if (0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t)))
589     {
590         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Same device ID");
591         return OC_STACK_INVALID_PARAM;
592     }
593
594     OIC_LOG(DEBUG, TAG, "Checking link in DB");
595     bool linkExists = true;
596     OCStackResult res = PDMIsLinkExists(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, &linkExists);
597     if(res != OC_STACK_OK)
598     {
599         OIC_LOG(ERROR, TAG, "Internal Error Occured");
600         return res;
601     }
602     if (linkExists)
603     {
604         OIC_LOG(ERROR, TAG, "Link already exists");
605         return OC_STACK_INVALID_PARAM;
606     }
607
608     int noOfResults = 2; // Initial Value
609     if (NULL != pDev1Acl)
610     {
611         ++noOfResults;
612     }
613     if (NULL != pDev2Acl)
614     {
615        ++noOfResults;
616     }
617     Linkdata_t *link = (Linkdata_t*) OICMalloc(sizeof(Linkdata_t));
618     if (!link)
619     {
620         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
621         return OC_STACK_NO_MEMORY;
622     }
623     OIC_LOG_V(INFO,TAG, "Maximum no od results %d",noOfResults);
624
625     link->pDev1 = pDev1;
626     link->pDev1Acl = pDev1Acl;
627     link->pDev2 = pDev2;
628     link->pDev2Acl = pDev2Acl;
629     link->ctx = ctx;
630     // 1 call for each device for credential provisioning. implict call by SRPProvisioning credential
631     // 1 call for ACL provisioning for device 1 and 1 call for ACL provisioning for device 2.
632     link->numOfResults = noOfResults;
633     link->resultCallback = resultCallback;
634     link->currentCountResults = 0;
635     link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
636     res = SRPProvisionCredentials(link, type, keySize,
637                                      pDev1, pDev2, &ProvisionCredsCB);
638     if (res != OC_STACK_OK)
639     {
640         OICFree(link->resArr);
641         OICFree(link);
642     }
643     return res;
644
645 }
646
647 OCStackResult OCGetDevInfoFromNetwork(unsigned short waittime,
648                                        OCProvisionDev_t** pOwnedDevList,
649                                        OCProvisionDev_t** pUnownedDevList)
650 {
651     //TODO will be replaced by more efficient logic
652     if (pOwnedDevList == NULL || *pOwnedDevList != NULL || pUnownedDevList == NULL
653          || *pUnownedDevList != NULL || 0 == waittime)
654     {
655         return OC_STACK_INVALID_PARAM;
656     }
657
658     // Code for unowned discovery
659     OCProvisionDev_t *unownedDevice = NULL;
660     OCStackResult res =  OCDiscoverUnownedDevices(waittime/2, &unownedDevice);
661     if (OC_STACK_OK != res)
662     {
663         OIC_LOG(ERROR,TAG, "Error in unowned discovery");
664         return res;
665     }
666
667     // Code for owned discovery
668     OCProvisionDev_t *ownedDevice = NULL;
669     res =  OCDiscoverOwnedDevices(waittime/2, &ownedDevice);
670     if (OC_STACK_OK != res)
671     {
672         OIC_LOG(ERROR,TAG, "Error in owned discovery");
673         PMDeleteDeviceList(unownedDevice);
674         return res;
675     }
676
677     // Code to get list of all the owned devices.
678     OCUuidList_t *uuidList = NULL;
679     size_t numOfDevices = 0;
680     res =  PDMGetOwnedDevices(&uuidList, &numOfDevices);
681     if (OC_STACK_OK != res)
682     {
683         OIC_LOG(ERROR, TAG, "Error while getting info from DB");
684         PMDeleteDeviceList(unownedDevice);
685         PMDeleteDeviceList(ownedDevice);
686         return res;
687     }
688
689     // Code to compare devices in owned list and deviceid from DB.
690     OCProvisionDev_t* pCurDev = ownedDevice;
691     size_t deleteCnt = 0;
692     while (pCurDev)
693     {
694         if(true == PMDeleteFromUUIDList(uuidList, &pCurDev->doxm->deviceID))
695         {
696             deleteCnt++;
697         }
698         pCurDev = pCurDev->next;
699     }
700     // If there is no remaind device in uuidList, we have to assign NULL to prevent free.
701     if (deleteCnt == numOfDevices)
702     {
703         uuidList = NULL;
704     }
705     // Code to add information of the devices which are currently off in owned list.
706     OCUuidList_t *powerOffDeviceList = uuidList;
707     while (powerOffDeviceList)
708     {
709         OCProvisionDev_t *ptr = (OCProvisionDev_t *)OICCalloc(1, sizeof (OCProvisionDev_t));
710         if (NULL == ptr)
711         {
712             OIC_LOG(ERROR,TAG,"Fail to allocate memory");
713             PMDeleteDeviceList(unownedDevice);
714             PMDeleteDeviceList(ownedDevice);
715             OCDeleteUuidList(uuidList);
716             return OC_STACK_NO_MEMORY;
717         }
718
719         ptr->doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
720         if (NULL == ptr->doxm)
721         {
722             OIC_LOG(ERROR,TAG,"Fail to allocate memory");
723             PMDeleteDeviceList(unownedDevice);
724             PMDeleteDeviceList(ownedDevice);
725             OCDeleteUuidList(uuidList);
726             OICFree(ptr);
727             return OC_STACK_NO_MEMORY;
728         }
729
730         memcpy(ptr->doxm->deviceID.id, powerOffDeviceList->dev.id, sizeof(ptr->doxm->deviceID.id));
731
732         ptr->devStatus = DEV_STATUS_OFF;
733         LL_PREPEND(ownedDevice, ptr);
734         powerOffDeviceList = powerOffDeviceList->next;
735
736     }
737     OCDeleteUuidList(uuidList);
738     *pOwnedDevList = ownedDevice;
739     *pUnownedDevList = unownedDevice;
740     return OC_STACK_OK;
741 }
742
743 OCStackResult OCGetLinkedStatus(const OicUuid_t* uuidOfDevice, OCUuidList_t** uuidList,
744                                  size_t* numOfDevices)
745 {
746     return PDMGetLinkedDevices(uuidOfDevice, uuidList, numOfDevices);
747 }
748
749 void OCDeleteUuidList(OCUuidList_t* pList)
750 {
751     PDMDestoryOicUuidLinkList(pList);
752 }
753
754 /**
755  * This function deletes ACL data.
756  *
757  * @param pAcl Pointer to OicSecAcl_t structure.
758  */
759 void OCDeleteACLList(OicSecAcl_t* pAcl)
760 {
761     DeleteACLList(pAcl);
762 }
763
764 /**
765  * This function deletes PDACL data.
766  *
767  * @param pPdAcl Pointer to OicSecPdAcl_t structure.
768  */
769 void OCDeletePdAclList(OicSecPdAcl_t* pPdAcl)
770 {
771     FreePdAclList(pPdAcl);
772 }
773
774
775 #ifdef __WITH_X509__
776 /**
777  * this function sends CRL information to resource.
778  *
779  * @param[in] ctx Application context would be returned in result callback.
780  * @param[in] selectedDeviceInfo Selected target device.
781  * @param[in] crl CRL to provision.
782  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
783               request recieves a response from resource server.
784  * @return  OC_STACK_OK in case of success and other value otherwise.
785  */
786 OCStackResult OCProvisionCRL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecCrl_t *crl,
787                              OCProvisionResultCB resultCallback)
788 {
789     return SRPProvisionCRL(ctx, selectedDeviceInfo, crl, resultCallback);
790 }
791 #endif // __WITH_X509__
792