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