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