17b0f39d38a7c0c364f1d92654a3a090fee69037
[iotivity.git] / resource / csdk / security / provisioning / src / pmutility.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 #ifndef _POSIX_C_SOURCE
21 #define _POSIX_C_SOURCE 200112L
22 #endif
23
24 /* Legacy feature macro. For older versions of glibc < 2.19 */
25 #define _BSD_SOURCE
26 /* New feature macro that provides everything _BSD_SOURCE and more glibc >= 2.20 */
27 #define _DEFAULT_SOURCE
28
29 #include "iotivity_config.h"
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36
37 #include "ocstack.h"
38 #include "oic_malloc.h"
39 #include "oic_string.h"
40 #include "oic_time.h"
41 #include "experimental/logger.h"
42 #include "utlist.h"
43 #include "ocpayload.h"
44
45 #include "srmresourcestrings.h" //@note: SRM's internal header
46 #include "experimental/doxmresource.h"       //@note: SRM's internal header
47 #include "pstatresource.h"      //@note: SRM's internal header
48
49 #include "pmtypes.h"
50 #include "pmutility.h"
51 #include "pmutilityinternal.h"
52
53 #include "srmutility.h"
54
55 #define TAG ("OIC_PM_UTILITY")
56
57 typedef struct _DiscoveryInfo{
58     OCProvisionDev_t    **ppDevicesList;
59     OCProvisionDev_t    *pCandidateList;
60     bool                isOwnedDiscovery;
61     bool                isSingleDiscovery;
62     bool                isFound;
63     const OicUuid_t     *targetId;
64 } DiscoveryInfo;
65
66 /*
67  * Function to discover secre port information through unicast
68  *
69  * @param[in] discoveryInfo The pointer of discovery information to matain result of discovery
70  * @param[in] clientResponse  Response information(It will contain payload)
71  *
72  * @return OC_STACK_OK on success otherwise error.
73  */
74 static OCStackResult SecurePortDiscovery(DiscoveryInfo* discoveryInfo,
75                                          const OCClientResponse *clientResponse);
76
77 /**
78  * Callback handler for PMDeviceDiscovery API.
79  *
80  * @param[in] ctx             User context
81  * @param[in] handle          Handler for response
82  * @param[in] clientResponse  Response information (It will contain payload)
83  * @return OC_STACK_KEEP_TRANSACTION to keep transaction and
84  *         OC_STACK_DELETE_TRANSACTION to delete it.
85  */
86 static OCStackApplicationResult DeviceDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
87                                 OCClientResponse *clientResponse);
88
89 /*
90  * Since security version discovery does not used anymore, disable security version discovery.
91  * Need to discussion to removing all version discovery related codes.
92  */
93
94 /*
95  * Function to discover security version information through unicast
96  *
97  * @param[in] discoveryInfo The pointer of discovery information to matain result of discovery
98  * @param[in] clientResponse  Response information(It will contain payload)
99  *
100  * @return OC_STACK_OK on success otherwise error.
101  */
102 static OCStackResult SpecVersionDiscovery(DiscoveryInfo* discoveryInfo,
103                                               const OCClientResponse *clientResponse);
104 #if 0
105 /**
106  * Callback handler for getting secure port information using /oic/res discovery.
107  *
108  * @param[in] ctx             user context
109  * @param[in] handle          Handle for response
110  * @param[in] clientResponse  Response information(It will contain payload)
111  *
112  * @return OC_STACK_KEEP_TRANSACTION to keep transaction and
113  *         OC_STACK_DELETE_TRANSACTION to delete it.
114  */
115 static OCStackApplicationResult SecurePortDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
116                                  OCClientResponse *clientResponse);
117 #endif
118
119 /*
120  * Since security version discovery does not used anymore, disable security version discovery.
121  * Need to discussion to removing all version discovery related codes.
122  */
123 #if 0
124 /**
125  * Callback handler for security version discovery.
126  *
127  * @param[in] ctx             User context
128  * @param[in] handle          Handler for response
129  * @param[in] clientResponse  Response information (It will contain payload)
130  * @return OC_STACK_KEEP_TRANSACTION to keep transaction and
131  *         OC_STACK_DELETE_TRANSACTION to delete it.
132  */
133 static OCStackApplicationResult SecVersionDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
134                                 OCClientResponse *clientResponse);
135 #endif
136
137 #ifdef MULTIPLE_OWNER
138 OicSecMom_t* CloneOicSecMom(const OicSecMom_t* src)
139 {
140     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
141
142     if (!src)
143     {
144         OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
145         return NULL;
146     }
147
148     OicSecMom_t* newMom = (OicSecMom_t*)OICMalloc(sizeof(*newMom));
149     if (newMom)
150     {
151         *newMom = *src;
152     }
153     else
154     {
155         OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
156     }
157
158     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
159
160     return newMom;
161 }
162
163 OicSecSubOwner_t* CloneOicSecSubOwner(const OicSecSubOwner_t* src)
164 {
165     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
166
167     if (!src)
168     {
169         OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
170         return NULL;
171     }
172
173     OicSecSubOwner_t* newSubOwner = (OicSecSubOwner_t*)OICCalloc(1, sizeof(*newSubOwner));
174     VERIFY_NOT_NULL(TAG, newSubOwner, ERROR);
175
176     memcpy(newSubOwner, src, sizeof(OicSecSubOwner_t));
177
178     if (src->next)
179     {
180         newSubOwner->next = CloneOicSecSubOwner(src->next);
181         VERIFY_NOT_NULL(TAG, newSubOwner->next, ERROR);
182     }
183
184     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
185
186     return newSubOwner;
187
188 exit:
189     OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
190     if (newSubOwner)
191     {
192         OICFree(newSubOwner);
193     }
194     return NULL;
195 }
196 #endif //MULTIPLE_OWNER
197
198 OicSecDoxm_t* CloneOicSecDoxm(const OicSecDoxm_t* src)
199 {
200     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
201
202     if (!src)
203     {
204         OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
205         return NULL;
206     }
207
208     OicSecDoxm_t* newDoxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
209     VERIFY_NOT_NULL(TAG, newDoxm, ERROR);
210
211     memcpy(newDoxm, src, sizeof(OicSecDoxm_t));
212
213 #ifdef MULTIPLE_OWNER
214     newDoxm->subOwners = NULL;
215     newDoxm->mom = NULL;
216
217     if (src->subOwners)
218     {
219         newDoxm->subOwners = CloneOicSecSubOwner(src->subOwners);
220         VERIFY_NOT_NULL(TAG, newDoxm->subOwners, ERROR);
221     }
222
223     if (src->mom)
224     {
225         newDoxm->mom = CloneOicSecMom(src->mom);
226         VERIFY_NOT_NULL(TAG, newDoxm->mom, ERROR);
227     }
228 #endif //MULTIPLE_OWNER
229
230     // We have to assign NULL for not necessary information to prevent memory corruption.
231     newDoxm->oxm = NULL;
232     newDoxm->oxmLen = 0;
233
234     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
235
236     return newDoxm;
237
238 exit:
239     OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
240     DeleteDoxmBinData(newDoxm);
241
242     return NULL;
243 }
244
245 /**
246  * Function to search node in linked list that matches given IP and port.
247  *
248  * @param[in] pList         List of OCProvisionDev_t.
249  * @param[in] addr          address of target device.
250  * @param[in] port          port of remote server.
251  *
252  * @return pointer of OCProvisionDev_t if exist, otherwise NULL
253  */
254 OCProvisionDev_t* GetDevice(OCProvisionDev_t **ppDevicesList, const char* addr, const uint16_t port)
255 {
256     if(NULL == addr || NULL == *ppDevicesList)
257     {
258         OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);
259         return NULL;
260     }
261
262     OCProvisionDev_t *ptr = NULL;
263     LL_FOREACH(*ppDevicesList, ptr)
264     {
265         if( strcmp(ptr->endpoint.addr, addr) == 0 && port == ptr->endpoint.port)
266         {
267             return ptr;
268         }
269     }
270
271     return NULL;
272 }
273
274
275 /**
276  * Add device information to list.
277  *
278  * @param[in] pList         List of OCProvisionDev_t.
279  * @param[in] endpoint      target device endpoint.
280  * @param[in] connType      connectivity type of endpoint
281  * @param[in] doxm          pointer to doxm instance.
282  *
283  * @return OC_STACK_OK for success and error code otherwise.
284  */
285 OCStackResult AddDevice(OCProvisionDev_t **ppDevicesList, OCDevAddr* endpoint,
286                         OCConnectivityType connType, OicSecDoxm_t *doxm)
287 {
288     if (NULL == endpoint)
289     {
290         return OC_STACK_INVALID_PARAM;
291     }
292
293     OCProvisionDev_t *ptr = GetDevice(ppDevicesList, endpoint->addr, endpoint->port);
294     if(!ptr)
295     {
296         ptr = (OCProvisionDev_t *)OICCalloc(1, sizeof (OCProvisionDev_t));
297         if (NULL == ptr)
298         {
299             OIC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
300             return OC_STACK_NO_MEMORY;
301         }
302
303         ptr->endpoint = *endpoint;
304         ptr->doxm = doxm;
305         ptr->securePort = (CT_ADAPTER_GATT_BTLE == connType) ?
306                           endpoint->port : DEFAULT_SECURE_PORT;
307         ptr->next = NULL;
308         ptr->connType = connType;
309         ptr->devStatus = DEV_STATUS_ON; //AddDevice is called when discovery(=alive)
310         OICStrcpy(ptr->specVer, SPEC_MAX_VER_LEN, DEFAULT_SPEC_VERSION); // version initialization
311         ptr->handle = NULL;
312
313         LL_PREPEND(*ppDevicesList, ptr);
314     }
315
316     return OC_STACK_OK;
317 }
318
319 /**
320  * Move device object between two device lists.
321  *
322  * @param[in] ppDstDevicesList         Destination list of OCProvisionDev_t.
323  * @param[in] ppSrcDevicesList         Source list of OCProvisionDev_t.
324  * @param[in] endpoint      target device endpoint.
325  *
326  * @return OC_STACK_OK for success and error code otherwise.
327  */
328 OCStackResult MoveDeviceList(OCProvisionDev_t **ppDstDevicesList,
329                         OCProvisionDev_t **ppSrcDevicesList, OCDevAddr* endpoint)
330 {
331     if (NULL == ppSrcDevicesList || NULL == endpoint)
332     {
333         return OC_STACK_INVALID_PARAM;
334     }
335
336     OCProvisionDev_t *ptr = GetDevice(ppSrcDevicesList, endpoint->addr, endpoint->port);
337     if(ptr)
338     {
339         LL_DELETE(*ppSrcDevicesList, ptr);
340         LL_PREPEND(*ppDstDevicesList, ptr);
341         OIC_LOG_V(DEBUG, TAG, "MoveDeviceList success : %s(%d)", endpoint->addr, endpoint->port);
342         return OC_STACK_OK;
343     }
344
345     return OC_STACK_ERROR;
346 }
347
348 /**
349  * Function to set secure port information from the given list of devices.
350  *
351  * @param[in] pList         List of OCProvisionDev_t.
352  * @param[in] addr          address of target device.
353  * @param[in] port          port of remote server.
354  * @param[in] secureport    secure port information.
355  *
356  * @return OC_STACK_OK for success and errorcode otherwise.
357  */
358 static OCStackResult UpdateSecurePortOfDevice(OCProvisionDev_t **ppDevicesList, const char *addr,
359                                        uint16_t port, uint16_t securePort
360 #ifdef __WITH_TLS__
361                                        ,uint16_t tcpPort
362                                        ,uint16_t tcpSecurePort
363 #endif
364                                        )
365 {
366     OCProvisionDev_t *ptr = GetDevice(ppDevicesList, addr, port);
367
368     if(!ptr)
369     {
370         OIC_LOG(ERROR, TAG, "Can not find device information in the discovery device list");
371         return OC_STACK_ERROR;
372     }
373
374     ptr->securePort = (OC_ADAPTER_GATT_BTLE == ptr->endpoint.adapter) ?
375                       ptr->endpoint.port : securePort;
376
377 #ifdef __WITH_TLS__
378     ptr->tcpPort = tcpPort;
379     ptr->tcpSecurePort = tcpSecurePort;
380 #endif
381
382     return OC_STACK_OK;
383 }
384
385 /**
386  * Function to set security version information from the given list of devices.
387  *
388  * @param[in] pList         List of OCProvisionDev_t.
389  * @param[in] addr          address of target device.
390  * @param[in] port          port of remote server.
391  * @param[in] specVer    security version information.
392  *
393  * @return OC_STACK_OK for success and errorcode otherwise.
394  */
395 static OCStackResult UpdateSpecVersionOfDevice(OCProvisionDev_t **ppDevicesList, const char *addr,
396                                        uint16_t port, const char* specVer)
397 {
398     if (NULL == specVer)
399     {
400         return OC_STACK_INVALID_PARAM;
401     }
402
403     OCProvisionDev_t *ptr = GetDevice(ppDevicesList, addr, port);
404
405     if(!ptr)
406     {
407         OIC_LOG(ERROR, TAG, "Can not find device information in the discovery device list");
408         return OC_STACK_ERROR;
409     }
410
411     OICStrcpy(ptr->specVer, SPEC_MAX_VER_LEN, specVer);
412
413     return OC_STACK_OK;
414 }
415
416 /**
417  * This function deletes list of provision target devices
418  *
419  * @param[in] pDevicesList         List of OCProvisionDev_t.
420  */
421 void PMDeleteDeviceList(OCProvisionDev_t *pDevicesList)
422 {
423     if(pDevicesList)
424     {
425         OCProvisionDev_t *del = NULL, *tmp = NULL;
426         LL_FOREACH_SAFE(pDevicesList, del, tmp)
427         {
428             LL_DELETE(pDevicesList, del);
429
430             DeleteDoxmBinData(del->doxm);
431             del->doxm = NULL;
432             DeletePstatBinData(del->pstat);
433             del->pstat = NULL;
434             OICFree(del);
435             del = NULL;
436         }
437     }
438 }
439
440 OCProvisionDev_t* PMCloneOCProvisionDev(const OCProvisionDev_t* src)
441 {
442     OIC_LOG(DEBUG, TAG, "IN PMCloneOCProvisionDev");
443
444     if (!src)
445     {
446         OIC_LOG(ERROR, TAG, "PMCloneOCProvisionDev : Invalid parameter");
447         return NULL;
448     }
449
450     // TODO: Consider use VERIFY_NON_NULL instead of if ( null check ) { goto exit; }
451     OCProvisionDev_t* newDev = (OCProvisionDev_t*)OICCalloc(1, sizeof(OCProvisionDev_t));
452     VERIFY_NOT_NULL(TAG, newDev, ERROR);
453
454     memcpy(&newDev->endpoint, &src->endpoint, sizeof(OCDevAddr));
455
456     if (src->pstat)
457     {
458         newDev->pstat= (OicSecPstat_t*)OICCalloc(1, sizeof(OicSecPstat_t));
459         VERIFY_NOT_NULL(TAG, newDev->pstat, ERROR);
460
461         memcpy(newDev->pstat, src->pstat, sizeof(OicSecPstat_t));
462         // We have to assign NULL for not necessary information to prevent memory corruption.
463         newDev->pstat->sm = NULL;
464     }
465
466     if (src->doxm)
467     {
468         newDev->doxm = CloneOicSecDoxm(src->doxm);
469         VERIFY_NOT_NULL(TAG, newDev->doxm, ERROR);
470     }
471
472     if (0 == strlen(src->specVer))
473     {
474         OICStrcpy(newDev->specVer, SPEC_MAX_VER_LEN, DEFAULT_SPEC_VERSION);
475     }
476     else
477     {
478         OICStrcpy(newDev->specVer, SPEC_MAX_VER_LEN, src->specVer);
479     }
480
481     newDev->securePort = src->securePort;
482     newDev->devStatus = src->devStatus;
483     newDev->connType = src->connType;
484     newDev->next = NULL;
485
486     OIC_LOG(DEBUG, TAG, "OUT PMCloneOCProvisionDev");
487
488     return newDev;
489
490 exit:
491     OIC_LOG(ERROR, TAG, "PMCloneOCProvisionDev : Failed to allocate memory");
492     PMDeleteDeviceList(newDev);
493     return NULL;
494 }
495
496 OCProvisionDev_t* PMCloneOCProvisionDevList(const OCProvisionDev_t* src)
497 {
498     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
499
500     if (!src)
501     {
502         OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
503         return NULL;
504     }
505
506     OCProvisionDev_t* newDev = PMCloneOCProvisionDev(src);
507     VERIFY_NOT_NULL(TAG, newDev, ERROR);
508
509     OCProvisionDev_t* current = newDev;
510     for (OCProvisionDev_t* next = src->next; NULL != next; next = next->next)
511     {
512         current->next = PMCloneOCProvisionDev(next);
513         VERIFY_NOT_NULL(TAG, current->next, ERROR);
514
515         current = current->next;
516     }
517
518     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
519
520     return newDev;
521
522 exit:
523     OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
524     PMDeleteDeviceList(newDev);
525     return NULL;
526 }
527
528 /**
529  * Timeout implementation for secure discovery. When performing secure discovery,
530  * we should wait a certain period of time for getting response of each devices.
531  *
532  * @param[in]  waittime  Timeout in seconds.
533  * @param[in]  waitForStackResponse if true timeout function will call OCProcess while waiting.
534  * @return OC_STACK_OK on success otherwise error.
535  */
536 OCStackResult PMTimeout(unsigned short waittime, bool waitForStackResponse)
537 {
538     OCStackResult res = OC_STACK_OK;
539
540     uint64_t startTime = OICGetCurrentTime(TIME_IN_MS);
541     while (OC_STACK_OK == res)
542     {
543         uint64_t currTime = OICGetCurrentTime(TIME_IN_MS);
544
545         long elapsed = (long)((currTime - startTime) / MS_PER_SEC);
546         if (elapsed > waittime)
547         {
548             return OC_STACK_OK;
549         }
550         if (waitForStackResponse)
551         {
552             res = OCProcess();
553         }
554     }
555     return res;
556 }
557
558 bool OC_CALL PMGenerateQuery(bool isSecure,
559                              const char* address, uint16_t port,
560                              OCConnectivityType connType,
561                              char* buffer, size_t bufferSize, const char* uri)
562 {
563     if(!address || !buffer || !uri)
564     {
565         OIC_LOG(ERROR, TAG, "PMGenerateQuery : Invalid parameters.");
566         return false;
567     }
568
569     int snRet = 0;
570     char* prefix = (isSecure == true) ? COAPS_PREFIX : COAP_PREFIX;
571
572     switch(connType & CT_MASK_ADAPTER)
573     {
574         case CT_ADAPTER_TCP:
575             prefix = (isSecure == true) ? COAPS_TCP_PREFIX : COAP_TCP_PREFIX;
576             /* fall through */
577         case CT_ADAPTER_IP:
578             switch(connType & CT_MASK_FLAGS & ~CT_FLAG_SECURE)
579             {
580                 case CT_IP_USE_V4:
581                     snRet = snprintf(buffer, bufferSize, "%s%s:%d%s",
582                                      prefix, address, port, uri);
583                     break;
584                 case CT_IP_USE_V6:
585                 {
586                     char addressEncoded[128] = {0};
587
588                     OCStackResult result = OCEncodeAddressForRFC6874(addressEncoded,
589                                                                      sizeof(addressEncoded),
590                                                                      address);
591                     if (OC_STACK_OK != result)
592                     {
593                         OIC_LOG_V(ERROR, TAG, "PMGenerateQuery : encoding error %d\n", result);
594                         return false;
595                     }
596
597                     snRet = snprintf(buffer, bufferSize, "%s[%s]:%d%s",
598                                      prefix, addressEncoded, port, uri);
599                     break;
600                 }
601                 default:
602                     OIC_LOG(ERROR, TAG, "Unknown address format.");
603                     return false;
604             }
605             break;
606         case CT_ADAPTER_GATT_BTLE:
607             snRet = snprintf(buffer, bufferSize, "%s%s%s",
608                              prefix, address, uri);
609             break;
610         case CT_ADAPTER_RFCOMM_BTEDR:
611             OIC_LOG(ERROR, TAG, "Not supported connectivity adapter.");
612             return false;
613         default:
614             OIC_LOG(ERROR, TAG, "Unknown connectivity adapter.");
615             return false;
616     }
617
618     // snprintf return value check
619     if (snRet < 0)
620     {
621         OIC_LOG_V(ERROR, TAG, "PMGenerateQuery : Error (snprintf) %d\n", snRet);
622         return false;
623     }
624     else if ((size_t)snRet >= bufferSize)
625     {
626         OIC_LOG_V(ERROR, TAG, "PMGenerateQuery : Truncated (snprintf) %d\n", snRet);
627         return false;
628     }
629
630     return true;
631 }
632
633 /*
634  * Since security version discovery does not used anymore, disable security version discovery.
635  * Need to discussion to removing all version discovery related codes.
636  */
637 static OCStackApplicationResult SpecVersionDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
638                                 OCClientResponse *clientResponse)
639 {
640     if (ctx == NULL)
641     {
642         OIC_LOG(ERROR, TAG, "Lost List of device information");
643         return OC_STACK_KEEP_TRANSACTION;
644     }
645     (void)UNUSED;
646     if (clientResponse)
647     {
648         if  (NULL == clientResponse->payload)
649         {
650             OIC_LOG(INFO, TAG, "Skiping Null payload");
651             return OC_STACK_KEEP_TRANSACTION;
652         }
653         if (OC_STACK_OK != clientResponse->result)
654         {
655             OIC_LOG(INFO, TAG, "Error in response");
656             return OC_STACK_KEEP_TRANSACTION;
657         }
658         else
659         {
660             if (PAYLOAD_TYPE_REPRESENTATION != clientResponse->payload->type)
661             {
662                 OIC_LOG(INFO, TAG, "Unknown payload type");
663                 return OC_STACK_KEEP_TRANSACTION;
664             }
665             OCRepPayloadValue* val = ((OCRepPayload*) clientResponse->payload)->values;
666
667             char specVer[SPEC_MAX_VER_LEN + 1] = {0};
668             OICStrcpy(specVer, SPEC_MAX_VER_LEN, DEFAULT_SPEC_VERSION);
669             while (val)
670             {
671                 if (val->type == OCREP_PROP_STRING)
672                 {
673                     OIC_LOG_V(DEBUG, TAG, "\t\t%s:%s", val->name, val->str);
674                     if (0 == strcmp(val->name, OC_RSRVD_SPEC_VERSION))
675                     {
676                         OICStrcpy(specVer, SPEC_MAX_VER_LEN, val->str);
677                         break;
678                     }
679                 }
680                 val = val -> next;
681             }
682             //If this is owend device discovery we have to filter out the responses.
683             DiscoveryInfo* pDInfo = (DiscoveryInfo*)ctx;
684             OCStackResult res = UpdateSpecVersionOfDevice(pDInfo->ppDevicesList, clientResponse->devAddr.addr,
685                                                      clientResponse->devAddr.port, specVer);
686             if (OC_STACK_OK != res)
687             {
688                 OIC_LOG(ERROR, TAG, "Error while getting security version.");
689                 return OC_STACK_KEEP_TRANSACTION;
690             }
691
692             OIC_LOG(INFO, TAG, "= Discovered security version =");
693             OIC_LOG_V(DEBUG, TAG, "IP %s", clientResponse->devAddr.addr);
694             OIC_LOG_V(DEBUG, TAG, "PORT %d", clientResponse->devAddr.port);
695             OIC_LOG_V(DEBUG, TAG, "VERSION %s", specVer);
696         }
697     }
698     else
699     {
700         OIC_LOG(INFO, TAG, "Skiping Null response");
701         return OC_STACK_KEEP_TRANSACTION;
702     }
703
704     return  OC_STACK_DELETE_TRANSACTION;
705 }
706
707 static OCStackApplicationResult SecurePortDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
708                                  OCClientResponse *clientResponse)
709 {
710     if (ctx == NULL)
711     {
712         OIC_LOG(ERROR, TAG, "Lost List of device information");
713         return OC_STACK_DELETE_TRANSACTION;
714     }
715     (void)UNUSED;
716     if (clientResponse)
717     {
718         if  (NULL == clientResponse->payload)
719         {
720             OIC_LOG(INFO, TAG, "Skiping Null payload");
721         }
722         else
723         {
724             if (PAYLOAD_TYPE_DISCOVERY != clientResponse->payload->type)
725             {
726                 OIC_LOG(INFO, TAG, "Wrong payload type");
727                 return OC_STACK_DELETE_TRANSACTION;
728             }
729
730             uint16_t securePort = 0;
731 #ifdef __WITH_TLS__
732             uint16_t tcpPort = 0;
733             uint16_t tcpSecurePort = 0;
734 #endif
735             OCResourcePayload* resPayload = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
736
737             // Use seure port of doxm for OTM and Provision.
738             while (resPayload)
739             {
740                 if (0 == strncmp(resPayload->uri, OIC_RSRC_DOXM_URI, strlen(OIC_RSRC_DOXM_URI)))
741                 {
742                     OIC_LOG_V(INFO,TAG,"resPaylod->uri:%s",resPayload->uri);
743                     OIC_LOG(INFO, TAG, "Found doxm resource.");
744                     break;
745                 }
746                 else
747                 {
748                     resPayload = resPayload->next;
749                 }
750             }
751             if (NULL == resPayload)
752             {
753                 OIC_LOG(ERROR, TAG, "Can not find doxm resource.");
754                 return OC_STACK_DELETE_TRANSACTION;
755             }
756             if (resPayload && resPayload->secure)
757             {
758                 securePort = resPayload->port;
759             }
760             else if (resPayload && resPayload->eps)
761             {
762                 OCEndpointPayload* eps = resPayload->eps;
763                 while (eps != NULL)
764                 {
765                     if ((eps->family & OC_FLAG_SECURE) &&
766                         ((OC_IP_USE_V6 == clientResponse->devAddr.flags &&
767                           strchr(eps->addr, ':')) ||
768                          (OC_IP_USE_V4 == clientResponse->devAddr.flags &&
769                           strchr(eps->addr, '.'))))
770                     {
771                             securePort = eps->port;
772                             break;
773                     }
774                     eps = eps->next;
775                 }
776 #ifdef __WITH_TLS__
777                 eps = resPayload->eps;
778                 while (eps != NULL)
779                 {
780                     if ((eps->family & OC_FLAG_SECURE) &&
781                         ((OC_IP_USE_V6 == clientResponse->devAddr.flags &&
782                           strchr(eps->addr, ':')) ||
783                          (OC_IP_USE_V4 == clientResponse->devAddr.flags &&
784                           strchr(eps->addr, '.'))) &&
785                         0 == strncmp(eps->tps, COAPS_TCP_PREFIX, strlen(COAPS_TCP_PREFIX)-3))
786                     {
787                             tcpSecurePort = eps->port;
788                             break;
789                     }
790                     eps = eps->next;
791                 }
792                 eps = resPayload->eps;
793                 while (eps != NULL)
794                 {
795                     if(((OC_IP_USE_V6 == clientResponse->devAddr.flags && strchr(eps->addr, ':')) ||
796                         (OC_IP_USE_V4 == clientResponse->devAddr.flags && strchr(eps->addr, '.'))) &&
797                         0 == strncmp(eps->tps, COAP_TCP_PREFIX, strlen(COAP_TCP_PREFIX)-3)
798                       )
799                     {
800                         tcpPort =  eps->port;
801                         break;
802                     }
803                     eps = eps->next;
804                 }
805 #endif
806                 if (!securePort)
807                 {
808                     OIC_LOG(INFO, TAG, "Can not find secure port information.");
809                     return OC_STACK_DELETE_TRANSACTION;
810                 }
811                 else
812                 {
813                     OIC_LOG_V(INFO, TAG, "%s: secure port: %d", __func__, securePort);
814                 }
815             }
816             else
817             {
818                 OIC_LOG(INFO, TAG, "Can not find secure port information.");
819                 return OC_STACK_DELETE_TRANSACTION;
820             }
821 #ifdef __WITH_TLS__
822             OIC_LOG_V(DEBUG, TAG, "%s: TCP port from discovery = %d", __func__, resPayload->tcpPort);
823 #endif
824             DiscoveryInfo* pDInfo = (DiscoveryInfo*)ctx;
825             OCProvisionDev_t *ptr = GetDevice(&pDInfo->pCandidateList,
826                                               clientResponse->devAddr.addr,
827                                               clientResponse->devAddr.port);
828             if(!ptr)
829             {
830                 OIC_LOG(ERROR, TAG, "Can not find device information in the discovery candidate device list");
831                 return OC_STACK_DELETE_TRANSACTION;
832             }
833
834             OCStackResult res = UpdateSecurePortOfDevice(&pDInfo->pCandidateList,
835                                                          clientResponse->devAddr.addr,
836                                                          clientResponse->devAddr.port,
837                                                          securePort
838 #ifdef __WITH_TLS__
839                                                          ,tcpPort
840                                                          ,tcpSecurePort
841 #endif
842                                                          );
843             if (OC_STACK_OK != res)
844             {
845                 OIC_LOG(ERROR, TAG, "Error while getting secure port.");
846                 return OC_STACK_DELETE_TRANSACTION;
847             }
848
849             res = MoveDeviceList(pDInfo->ppDevicesList, &pDInfo->pCandidateList, &clientResponse->devAddr);
850             if(OC_STACK_OK != res)
851             {
852                 OIC_LOG(ERROR, TAG, "Error while move the discovered device to list.");
853                 return OC_STACK_DELETE_TRANSACTION;
854             }
855
856             if(pDInfo->isSingleDiscovery)
857             {
858                 pDInfo->isFound = true;
859             }
860             else
861             {
862                 res = SpecVersionDiscovery(pDInfo, clientResponse);
863                 if(OC_STACK_OK != res)
864                 {
865                     OIC_LOG(ERROR, TAG, "Failed to SpecVersionDiscovery");
866                     return OC_STACK_DELETE_TRANSACTION;
867                 }
868             }
869
870             OIC_LOG(INFO, TAG, "Exiting SecurePortDiscoveryHandler.");
871         }
872
873         return  OC_STACK_DELETE_TRANSACTION;
874     }
875     else
876     {
877         OIC_LOG(INFO, TAG, "Skiping Null response");
878     }
879
880     return  OC_STACK_DELETE_TRANSACTION;
881 }
882
883 static OCStackApplicationResult DeviceDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
884                                 OCClientResponse *clientResponse)
885 {
886     if (ctx == NULL)
887     {
888         OIC_LOG(ERROR, TAG, "Lost List of device information");
889         return OC_STACK_KEEP_TRANSACTION;
890     }
891     (void)UNUSED;
892
893     if (!clientResponse)
894     {
895         OIC_LOG(INFO, TAG, "Skiping Null response");
896         return OC_STACK_KEEP_TRANSACTION;
897     }
898
899     if  (NULL == clientResponse->payload)
900     {
901         OIC_LOG(INFO, TAG, "Skiping Null payload");
902         return OC_STACK_KEEP_TRANSACTION;
903     }
904     if (OC_STACK_OK != clientResponse->result)
905     {
906         OIC_LOG(INFO, TAG, "Error in response");
907         return OC_STACK_KEEP_TRANSACTION;
908     }
909
910     if (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type)
911     {
912         OIC_LOG(INFO, TAG, "Unknown payload type");
913         return OC_STACK_KEEP_TRANSACTION;
914     }
915
916     OicSecDoxm_t *ptrDoxm = NULL;
917     uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;
918     size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;
919
920     OCStackResult res = CBORPayloadToDoxm(payload, size, &ptrDoxm);
921     if ((NULL == ptrDoxm) || (OC_STACK_OK != res))
922     {
923         OIC_LOG(INFO, TAG, "Ignoring malformed CBOR");
924         return OC_STACK_KEEP_TRANSACTION;
925     }
926
927     OIC_LOG(DEBUG, TAG, "Successfully converted doxm cbor to bin.");
928
929     //If this is owend device discovery we have to filter out the responses.
930     DiscoveryInfo* pDInfo = (DiscoveryInfo*)ctx;
931     OCProvisionDev_t **ppDevicesList = &pDInfo->pCandidateList;
932
933     // Get my device ID from doxm resource
934     OicUuid_t myId;
935     memset(&myId, 0, sizeof(myId));
936     res = GetDoxmDeviceID(&myId);
937     if(OC_STACK_OK != res)
938     {
939         OIC_LOG(ERROR, TAG, "Error while getting my device ID.");
940         DeleteDoxmBinData(ptrDoxm);
941         return OC_STACK_KEEP_TRANSACTION;
942     }
943
944     // If this is owned discovery response but owner is not me then discard it.
945     if( (pDInfo->isOwnedDiscovery) &&
946         (0 != memcmp(&ptrDoxm->owner.id, &myId.id, sizeof(myId.id))) )
947     {
948         OIC_LOG(DEBUG, TAG, "Discovered device is not owend by me");
949         DeleteDoxmBinData(ptrDoxm);
950         return OC_STACK_KEEP_TRANSACTION;
951     }
952
953     //if targetId and discovered deviceID are different, discard it
954     if ((pDInfo->isSingleDiscovery) &&
955         (0 != memcmp(&ptrDoxm->deviceID.id, &pDInfo->targetId->id, sizeof(pDInfo->targetId->id))) )
956     {
957         OIC_LOG(DEBUG, TAG, "Discovered device is not target device");
958         DeleteDoxmBinData(ptrDoxm);
959         return OC_STACK_KEEP_TRANSACTION;
960     }
961     //If self reply, discard it
962     if (0 == memcmp(&ptrDoxm->deviceID.id, &myId.id, sizeof(myId.id)))
963     {
964         OIC_LOG(DEBUG, TAG, "discarding provision tool's reply");
965         DeleteDoxmBinData(ptrDoxm);
966         return OC_STACK_KEEP_TRANSACTION;
967     }
968
969     res = AddDevice(ppDevicesList, &clientResponse->devAddr,
970             clientResponse->connType, ptrDoxm);
971     if (OC_STACK_OK != res)
972     {
973         OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
974         DeleteDoxmBinData(ptrDoxm);
975         return OC_STACK_KEEP_TRANSACTION;
976     }
977
978     res = SecurePortDiscovery(pDInfo, clientResponse);
979     if(OC_STACK_OK != res)
980     {
981         OIC_LOG(ERROR, TAG, "Failed to SecurePortDiscovery");
982         DeleteDoxmBinData(ptrDoxm);
983         return OC_STACK_KEEP_TRANSACTION;
984     }
985
986     OIC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
987
988     return  OC_STACK_KEEP_TRANSACTION;
989 }
990
991 static void DeviceDiscoveryDeleteHandler(void *ctx)
992 {
993     OIC_LOG(DEBUG, TAG, "IN DeviceDiscoveryDeleteHandler");
994     if (NULL == ctx)
995     {
996         OIC_LOG(WARNING, TAG, "Not found context in DeviceDiscoveryDeleteHandler");
997         return;
998     }
999
1000     DiscoveryInfo* pDInfo = (DiscoveryInfo*)ctx;
1001     if (NULL != pDInfo->pCandidateList)
1002     {
1003         OCProvisionDev_t *pDev = NULL;
1004         LL_FOREACH(pDInfo->pCandidateList, pDev)
1005         {
1006             OIC_LOG_V(DEBUG, TAG, "OCCancel - %s : %d",
1007                             pDev->endpoint.addr, pDev->endpoint.port);
1008             if(OC_STACK_OK !=  OCCancel(pDev->handle,OC_HIGH_QOS,NULL,0))
1009             {
1010                 OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1011             }
1012         }
1013         PMDeleteDeviceList(pDInfo->pCandidateList);
1014     }
1015     OIC_LOG(DEBUG, TAG, "OUT DeviceDiscoveryDeleteHandler");
1016 }
1017
1018 /**
1019  * Discover owned/unowned device in the specified endpoint/deviceID.
1020  * It will return the found device even though timeout is not exceeded.
1021  *
1022  * @param[in] waittime           Timeout in seconds
1023  * @param[in] deviceID           deviceID of target device.
1024  * @param[out] ppFoundDevice     OCProvisionDev_t of found device
1025  *
1026  * @return OC_STACK_OK on success otherwise error.\n
1027  *         OC_STACK_INVALID_PARAM when deviceID is NULL or ppFoundDevice is not initailized.
1028  */
1029 OCStackResult PMSingleDeviceDiscovery(unsigned short waittime, const OicUuid_t* deviceID,
1030                                  OCProvisionDev_t **ppFoundDevice)
1031 {
1032     OIC_LOG(DEBUG, TAG, "IN PMSingleDeviceDiscovery");
1033
1034     if (NULL != *ppFoundDevice)
1035     {
1036         OIC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1037         return OC_STACK_INVALID_PARAM;
1038     }
1039
1040     if (NULL == deviceID)
1041     {
1042         OIC_LOG(ERROR, TAG, "Invalid device ID");
1043         return OC_STACK_INVALID_PARAM;
1044     }
1045
1046
1047     DiscoveryInfo *pDInfo = OICCalloc(1, sizeof(DiscoveryInfo));
1048     if(NULL == pDInfo)
1049     {
1050         OIC_LOG(ERROR, TAG, "PMSingleDeviceDiscovery : Memory allocation failed.");
1051         return OC_STACK_NO_MEMORY;
1052     }
1053
1054     pDInfo->ppDevicesList = ppFoundDevice;
1055     pDInfo->pCandidateList = NULL;
1056     pDInfo->isOwnedDiscovery = false;
1057     pDInfo->isSingleDiscovery = true;
1058     pDInfo->isFound = false;
1059     pDInfo->targetId = deviceID;
1060
1061     OCCallbackData cbData;
1062     cbData.cb = &DeviceDiscoveryHandler;
1063     cbData.context = (void *)pDInfo;
1064     cbData.cd = &DeviceDiscoveryDeleteHandler;
1065
1066     OCStackResult res = OC_STACK_ERROR;
1067
1068     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH + 1] = { '\0' };
1069     snprintf(query, MAX_URI_LENGTH + MAX_QUERY_LENGTH + 1, "/oic/sec/doxm");
1070
1071     OCDoHandle handle = NULL;
1072     res = OCDoResource(&handle, OC_REST_DISCOVER, query, 0, 0,
1073                                      CT_DEFAULT, OC_HIGH_QOS, &cbData, NULL, 0);
1074     if (res != OC_STACK_OK)
1075     {
1076         OIC_LOG(ERROR, TAG, "OCStack resource error");
1077         OICFree(pDInfo);
1078         return res;
1079     }
1080
1081     //Waiting for each response.
1082     res = OC_STACK_OK;
1083     uint64_t startTime = OICGetCurrentTime(TIME_IN_MS);
1084     while (OC_STACK_OK == res && !pDInfo->isFound)
1085     {
1086         uint64_t currTime = OICGetCurrentTime(TIME_IN_MS);
1087
1088         long elapsed = (long)((currTime - startTime) / MS_PER_SEC);
1089         if (elapsed > waittime)
1090         {
1091             break;
1092         }
1093         res = OCProcess();
1094     }
1095
1096     if(OC_STACK_OK != res)
1097     {
1098         OIC_LOG(ERROR, TAG, "Failed to wait response for secure discovery.");
1099         OICFree(pDInfo);
1100         OCStackResult resCancel = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
1101         if(OC_STACK_OK !=  resCancel)
1102         {
1103             OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1104         }
1105         return res;
1106     }
1107
1108     res = OCCancel(handle,OC_HIGH_QOS,NULL,0);
1109     if (OC_STACK_OK != res)
1110     {
1111         OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1112         OICFree(pDInfo);
1113         return res;
1114     }
1115     OIC_LOG(DEBUG, TAG, "OUT PMSingleDeviceDiscovery");
1116     OICFree(pDInfo);
1117     return res;
1118 }
1119
1120
1121 /**
1122  * Discover owned/unowned devices in the same IP subnet. .
1123  *
1124  * @param[in] waittime      Timeout in seconds.
1125  * @param[in] isOwned       bool flag for owned / unowned discovery
1126  * @param[in] ppDevicesList        List of OCProvisionDev_t.
1127  *
1128  * @return OC_STACK_OK on success otherwise error.
1129  */
1130 OCStackResult PMDeviceDiscovery(unsigned short waittime, bool isOwned, OCProvisionDev_t **ppDevicesList)
1131 {
1132     OIC_LOG(DEBUG, TAG, "IN PMDeviceDiscovery");
1133
1134     if (NULL != *ppDevicesList)
1135     {
1136         OIC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1137         return OC_STACK_INVALID_PARAM;
1138     }
1139
1140     const char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
1141     const char DOXM_OWNED_TRUE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=TRUE";
1142
1143     DiscoveryInfo *pDInfo = OICCalloc(1, sizeof(DiscoveryInfo));
1144     if(NULL == pDInfo)
1145     {
1146         OIC_LOG(ERROR, TAG, "PMDeviceDiscovery : Memory allocation failed.");
1147         return OC_STACK_NO_MEMORY;
1148     }
1149
1150     pDInfo->ppDevicesList = ppDevicesList;
1151     pDInfo->pCandidateList = NULL;
1152     pDInfo->isOwnedDiscovery = isOwned;
1153     pDInfo->isSingleDiscovery = false;
1154     pDInfo->targetId = NULL;
1155
1156     OCCallbackData cbData;
1157     cbData.cb = &DeviceDiscoveryHandler;
1158     cbData.context = (void *)pDInfo;
1159     cbData.cd = &DeviceDiscoveryDeleteHandler;
1160     OCStackResult res = OC_STACK_ERROR;
1161
1162     const char* query = isOwned ? DOXM_OWNED_TRUE_MULTICAST_QUERY :
1163                                   DOXM_OWNED_FALSE_MULTICAST_QUERY;
1164
1165     OCDoHandle handle = NULL;
1166     res = OCDoResource(&handle, OC_REST_DISCOVER, query, 0, 0,
1167                                      CT_DEFAULT, OC_HIGH_QOS, &cbData, NULL, 0);
1168     if (res != OC_STACK_OK)
1169     {
1170         OIC_LOG(ERROR, TAG, "OCStack resource error");
1171         OICFree(pDInfo);
1172         return res;
1173     }
1174
1175     //Waiting for each response.
1176     res = PMTimeout(waittime, true);
1177     if(OC_STACK_OK != res)
1178     {
1179         OIC_LOG(ERROR, TAG, "Failed to wait response for secure discovery.");
1180         OICFree(pDInfo);
1181         OCStackResult resCancel = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
1182         if(OC_STACK_OK !=  resCancel)
1183         {
1184             OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1185         }
1186         return res;
1187     }
1188     res = OCCancel(handle,OC_HIGH_QOS,NULL,0);
1189     if (OC_STACK_OK != res)
1190     {
1191         OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1192         OICFree(pDInfo);
1193         return res;
1194     }
1195     OIC_LOG(DEBUG, TAG, "OUT PMDeviceDiscovery");
1196     OICFree(pDInfo);
1197     return res;
1198 }
1199
1200 OCStackResult PMSingleDeviceDiscoveryInUnicast(unsigned short waittime, const OicUuid_t* deviceID,
1201                                  const char* hostAddress, OCConnectivityType connType,
1202                                  OCProvisionDev_t **ppFoundDevice)
1203 {
1204     OIC_LOG(DEBUG, TAG, "IN PMSingleDeviceDiscoveryInUnicast");
1205
1206     if (NULL != *ppFoundDevice)
1207     {
1208         OIC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1209         return OC_STACK_INVALID_PARAM;
1210     }
1211
1212     if (NULL == deviceID)
1213     {
1214         OIC_LOG(ERROR, TAG, "Invalid device ID");
1215         return OC_STACK_INVALID_PARAM;
1216     }
1217
1218     DiscoveryInfo *pDInfo = (DiscoveryInfo*)OICCalloc(1, sizeof(DiscoveryInfo));
1219     if (NULL == pDInfo)
1220     {
1221         OIC_LOG(ERROR, TAG, "PMSingleDeviceDiscoveryInUnicast : Memory allocation failed.");
1222         return OC_STACK_NO_MEMORY;
1223     }
1224
1225     pDInfo->ppDevicesList = ppFoundDevice;
1226     pDInfo->pCandidateList = NULL;
1227     pDInfo->isOwnedDiscovery = false;
1228     pDInfo->isSingleDiscovery = true;
1229     pDInfo->isFound = false;
1230     pDInfo->targetId = deviceID;
1231
1232     OCCallbackData cbData;
1233     cbData.cb = &DeviceDiscoveryHandler;
1234     cbData.context = (void *)pDInfo;
1235     cbData.cd = &DeviceDiscoveryDeleteHandler;
1236
1237     OCStackResult res = OC_STACK_ERROR;
1238
1239     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH + 1] = { '\0' };
1240     if (hostAddress == NULL)
1241     {
1242         hostAddress = "";
1243     }
1244     snprintf(query, MAX_URI_LENGTH + MAX_QUERY_LENGTH + 1, "%s/oic/sec/doxm", hostAddress);
1245     connType = connType & CT_MASK_ADAPTER;
1246
1247     OCDoHandle handle = NULL;
1248     res = OCDoResource(&handle, OC_REST_DISCOVER, query, 0, 0,
1249             connType, OC_HIGH_QOS, &cbData, NULL, 0);
1250
1251     if (res != OC_STACK_OK)
1252     {
1253         OIC_LOG(ERROR, TAG, "OCStack resource error");
1254         OICFree(pDInfo);
1255         pDInfo = NULL;
1256         return res;
1257     }
1258
1259     res = OC_STACK_OK;
1260     uint64_t startTime = OICGetCurrentTime(TIME_IN_MS);
1261     while (OC_STACK_OK == res && !pDInfo->isFound)
1262     {
1263         uint64_t currTime = OICGetCurrentTime(TIME_IN_MS);
1264
1265         long elapsed = (long)((currTime - startTime) / MS_PER_SEC);
1266         if (elapsed > waittime)
1267         {
1268             break;
1269         }
1270         res = OCProcess();
1271     }
1272
1273     if (OC_STACK_OK != res)
1274     {
1275         OIC_LOG (ERROR, TAG, "Failed to wait response for secure discovery.");
1276         OICFree(pDInfo);
1277         pDInfo = NULL;
1278         OCStackResult resCancel = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
1279         if (OC_STACK_OK !=  resCancel)
1280         {
1281             OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1282         }
1283         return res;
1284     }
1285
1286     res = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
1287     if (OC_STACK_OK != res)
1288     {
1289         OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1290         OICFree(pDInfo);
1291         pDInfo = NULL;
1292         return res;
1293     }
1294     OIC_LOG(DEBUG, TAG, "OUT PMSingleDeviceDiscoveryInUnicast");
1295     OICFree(pDInfo);
1296     pDInfo = NULL;
1297     return res;
1298 }
1299
1300 #ifdef MULTIPLE_OWNER
1301
1302 static const unsigned int IOTIVITY_USECS_PER_MSEC = 1000;
1303 extern int MOTIsSupportedOnboardingType(OicSecDoxm_t *ptrDoxm);
1304
1305 static OCStackApplicationResult MOTDeviceDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
1306                                 OCClientResponse *clientResponse)
1307 {
1308     if (ctx == NULL)
1309     {
1310         OIC_LOG(ERROR, TAG, "Lost List of device information");
1311         return OC_STACK_KEEP_TRANSACTION;
1312     }
1313     (void)UNUSED;
1314     if (clientResponse)
1315     {
1316         if  (NULL == clientResponse->payload)
1317         {
1318             OIC_LOG(INFO, TAG, "Skipping Null payload");
1319             return OC_STACK_KEEP_TRANSACTION;
1320         }
1321         if (OC_STACK_OK != clientResponse->result)
1322         {
1323             OIC_LOG(INFO, TAG, "Error in response");
1324             return OC_STACK_KEEP_TRANSACTION;
1325         }
1326         else
1327         {
1328             if (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type)
1329             {
1330                 OIC_LOG(INFO, TAG, "Unknown payload type");
1331                 return OC_STACK_KEEP_TRANSACTION;
1332             }
1333
1334             OicSecDoxm_t *ptrDoxm = NULL;
1335             uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;
1336             size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;
1337
1338             OCStackResult res = CBORPayloadToDoxm(payload, size, &ptrDoxm);
1339             if ((NULL == ptrDoxm) || (OC_STACK_OK != res))
1340             {
1341                 OIC_LOG(INFO, TAG, "Ignoring malformed CBOR");
1342                 return OC_STACK_KEEP_TRANSACTION;
1343             }
1344             else
1345             {
1346                 OIC_LOG(DEBUG, TAG, "Successfully converted doxm cbor to bin.");
1347
1348                 //If this is owend device discovery we have to filter out the responses.
1349                 DiscoveryInfo* pDInfo = (DiscoveryInfo*)ctx;
1350                 OCProvisionDev_t **ppDevicesList = &pDInfo->pCandidateList;
1351
1352                 // Get my device ID from doxm resource
1353                 OicUuid_t myId;
1354                 memset(&myId, 0, sizeof(myId));
1355
1356                 res = GetDoxmDeviceID(&myId);
1357                 if(OC_STACK_OK != res)
1358                 {
1359                     OIC_LOG(ERROR, TAG, "Error while getting my device ID.");
1360                     DeleteDoxmBinData(ptrDoxm);
1361                     return OC_STACK_KEEP_TRANSACTION;
1362                 }
1363
1364                 //if targetId and discovered deviceID are different, discard it
1365                 if ((pDInfo->isSingleDiscovery) &&
1366                     (0 != memcmp(&ptrDoxm->deviceID.id, &pDInfo->targetId->id, sizeof(pDInfo->targetId->id))))
1367                 {
1368                     OIC_LOG(DEBUG, TAG, "Discovered device is not target device");
1369                     DeleteDoxmBinData(ptrDoxm);
1370                     return OC_STACK_KEEP_TRANSACTION;
1371                 }
1372
1373                 //if this is owned discovery and this is PT's reply, discard it
1374                 if (((pDInfo->isSingleDiscovery) || (pDInfo->isOwnedDiscovery)) &&
1375                     (0 == memcmp(&ptrDoxm->deviceID.id, &myId.id, sizeof(myId.id))))
1376                 {
1377                     OIC_LOG(DEBUG, TAG, "discarding provision tool's reply");
1378                     DeleteDoxmBinData(ptrDoxm);
1379                     return OC_STACK_KEEP_TRANSACTION;
1380                 }
1381
1382                 if(pDInfo->isOwnedDiscovery)
1383                 {
1384                     OicSecSubOwner_t* subOwner = NULL;
1385                     LL_FOREACH(ptrDoxm->subOwners, subOwner)
1386                     {
1387                         if(memcmp(myId.id, subOwner->uuid.id, sizeof(myId.id)) == 0)
1388                         {
1389                             break;
1390                         }
1391                     }
1392
1393                     if(subOwner)
1394                     {
1395                         res = AddDevice(ppDevicesList, &clientResponse->devAddr,
1396                                 clientResponse->connType, ptrDoxm);
1397                         if (OC_STACK_OK != res)
1398                         {
1399                             OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
1400                             DeleteDoxmBinData(ptrDoxm);
1401                             return OC_STACK_KEEP_TRANSACTION;
1402                         }
1403
1404                         res = SecurePortDiscovery(pDInfo, clientResponse);
1405                         if(OC_STACK_OK != res)
1406                         {
1407                             OIC_LOG(ERROR, TAG, "Failed to SecurePortDiscovery");
1408                             DeleteDoxmBinData(ptrDoxm);
1409                             return OC_STACK_KEEP_TRANSACTION;
1410                         }
1411                     }
1412                     else
1413                     {
1414                         OIC_LOG(ERROR, TAG, "discarding device's reply, because not a SubOwner.");
1415                         DeleteDoxmBinData(ptrDoxm);
1416                         return OC_STACK_KEEP_TRANSACTION;
1417                     }
1418                 }
1419                 else
1420                 {
1421                     if(ptrDoxm->mom && OIC_MULTIPLE_OWNER_DISABLE != ptrDoxm->mom->mode)
1422                     {
1423                         res = AddDevice(ppDevicesList, &clientResponse->devAddr,
1424                                 clientResponse->connType, ptrDoxm);
1425                         if (OC_STACK_OK != res)
1426                         {
1427                             OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
1428                             DeleteDoxmBinData(ptrDoxm);
1429                             return OC_STACK_KEEP_TRANSACTION;
1430                         }
1431
1432                         res = SecurePortDiscovery(pDInfo, clientResponse);
1433                         if(OC_STACK_OK != res)
1434                         {
1435                             OIC_LOG(ERROR, TAG, "Failed to SecurePortDiscovery");
1436                             DeleteDoxmBinData(ptrDoxm);
1437                             return OC_STACK_KEEP_TRANSACTION;
1438                         }
1439                     }
1440                     else
1441                     {
1442                         OIC_LOG(ERROR, TAG, "discarding mom disabled device's reply");
1443                         DeleteDoxmBinData(ptrDoxm);
1444                         return OC_STACK_KEEP_TRANSACTION;
1445                     }
1446                 }
1447
1448                 OIC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
1449             }
1450
1451             return  OC_STACK_KEEP_TRANSACTION;
1452         }
1453     }
1454     else
1455     {
1456         OIC_LOG(INFO, TAG, "Skiping Null response");
1457         return OC_STACK_KEEP_TRANSACTION;
1458     }
1459 }
1460
1461 /**
1462  * The function is responsible for the discovery of an MOT-enabled device with the specified deviceID.
1463  * The function will return when security information for device with deviceID has been obtained or the
1464  * timeout has been exceeded.
1465  *
1466  * @param[in]  timeoutSeconds  Maximum time, in seconds, this function will listen for responses from
1467  *                             servers before returning.
1468  * @param[in]  deviceID        deviceID of target device.
1469  * @param[out] ppFoundDevice   OCProvisionDev_t of found device. Caller should use PMDeleteDeviceList 
1470  *                             to delete the device.
1471  *
1472  * @return OC_STACK_OK on success otherwise error.
1473  *         OC_STACK_INVALID_PARAM when deviceID is NULL or ppFoundDevice is not initailized.
1474  */
1475 OCStackResult PMMultipleOwnerSingleDeviceDiscovery(unsigned short timeoutSeconds,
1476                                                    const OicUuid_t* deviceID,
1477                                                    OCProvisionDev_t **ppFoundDevice)
1478 {
1479     OIC_LOG(DEBUG, TAG, "IN PMMultipleOwnerSingleDeviceDiscovery");
1480
1481     if ((NULL == ppFoundDevice) || (NULL == deviceID))
1482     {
1483         return OC_STACK_INVALID_PARAM;
1484     }
1485
1486     DiscoveryInfo discoveryInfo;
1487     discoveryInfo.ppDevicesList = ppFoundDevice;
1488     discoveryInfo.pCandidateList = NULL;
1489     discoveryInfo.isOwnedDiscovery = false;
1490     discoveryInfo.isSingleDiscovery = true;
1491     discoveryInfo.isFound = false;
1492     discoveryInfo.targetId = deviceID;
1493
1494     OCCallbackData cbData;
1495     cbData.cb = &MOTDeviceDiscoveryHandler;
1496     cbData.context = (void *)&discoveryInfo;
1497     cbData.cd = NULL;
1498
1499     OCStackResult res = OC_STACK_ERROR;
1500     const char query[] = "/oic/sec/doxm?mom!=0&owned=TRUE";
1501
1502     OCDoHandle handle = NULL;
1503     res = OCDoResource(&handle, OC_REST_DISCOVER, query, 0, 0, CT_DEFAULT, OC_HIGH_QOS, &cbData, NULL, 0);
1504     if (res != OC_STACK_OK)
1505     {
1506         OIC_LOG(ERROR, TAG, "OCStack resource error");
1507         return res;
1508     }
1509
1510     //Waiting for each response.
1511     uint64_t startTime = OICGetCurrentTime(TIME_IN_MS);
1512     while ((OC_STACK_OK == res) && !discoveryInfo.isFound)
1513     {
1514         uint64_t currTime = OICGetCurrentTime(TIME_IN_MS);
1515         if (currTime >= startTime)
1516         {
1517             long elapsed = (long)((currTime - startTime) / MS_PER_SEC);
1518             if (elapsed > timeoutSeconds)
1519             {
1520                 break;
1521             }
1522
1523             // Sleep for 100 ms to free up the CPU
1524             usleep(100 * IOTIVITY_USECS_PER_MSEC);
1525
1526             res = OCProcess();
1527         }
1528         else
1529         {
1530             // System time has changed so we cannot reliably continue processing.
1531             // Function returns with no device discovered.
1532             break;
1533         }
1534     }
1535
1536     if (OC_STACK_OK != res)
1537     {
1538         OIC_LOG(ERROR, TAG, "Failed while waiting for a secure discovery response.");
1539         OCStackResult resCancel = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
1540         if (OC_STACK_OK != resCancel)
1541         {
1542             OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1543         }
1544         return res;
1545     }
1546
1547     res = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
1548     if (OC_STACK_OK != res)
1549     {
1550         OIC_LOG(ERROR, TAG, "Failed to remove the registered callback");
1551         return res;
1552     }
1553     OIC_LOG(DEBUG, TAG, "OUT PMMultipleOwnerSingleDeviceDiscovery");
1554     return res;
1555 }
1556
1557 /**
1558  * Discover multiple OTM enabled devices in the same IP subnet.
1559  *
1560  * @param[in] waittime      Timeout in seconds.
1561  * @param[in] ppDevicesList        List of OCProvisionDev_t.
1562  *
1563  * @return OC_STACK_OK on success otherwise error.
1564  */
1565 OCStackResult PMMultipleOwnerDeviceDiscovery(unsigned short waittime, bool isMultipleOwned, OCProvisionDev_t **ppDevicesList)
1566 {
1567     OIC_LOG(DEBUG, TAG, "IN PMMultipleOwnerEnabledDeviceDiscovery");
1568
1569     if (NULL != *ppDevicesList)
1570     {
1571         OIC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1572         return OC_STACK_INVALID_PARAM;
1573     }
1574
1575     const char *DOXM_MOM_ENABLE_MULTICAST_QUERY = "/oic/sec/doxm?mom!=0&owned=TRUE";
1576     const char *DOXM_MULTIPLE_OWNED_MULTICAST_QUERY = "/oic/sec/doxm?owned=TRUE";
1577
1578     DiscoveryInfo *pDInfo = OICCalloc(1, sizeof(DiscoveryInfo));
1579     if(NULL == pDInfo)
1580     {
1581         OIC_LOG(ERROR, TAG, "PMDeviceDiscovery : Memory allocation failed.");
1582         return OC_STACK_NO_MEMORY;
1583     }
1584
1585     pDInfo->ppDevicesList = ppDevicesList;
1586     pDInfo->pCandidateList = NULL;
1587     pDInfo->isOwnedDiscovery = isMultipleOwned;
1588
1589     OCCallbackData cbData;
1590     cbData.cb = &MOTDeviceDiscoveryHandler;
1591     cbData.context = (void *)pDInfo;
1592     cbData.cd = NULL;
1593     OCStackResult res = OC_STACK_ERROR;
1594
1595     const char* query = isMultipleOwned ? DOXM_MULTIPLE_OWNED_MULTICAST_QUERY :
1596                                           DOXM_MOM_ENABLE_MULTICAST_QUERY;
1597
1598     OCDoHandle handle = NULL;
1599     res = OCDoResource(&handle, OC_REST_DISCOVER, query, 0, 0,
1600                                      CT_DEFAULT, OC_HIGH_QOS, &cbData, NULL, 0);
1601     if (res != OC_STACK_OK)
1602     {
1603         OIC_LOG(ERROR, TAG, "OCStack resource error");
1604         OICFree(pDInfo);
1605         return res;
1606     }
1607
1608     //Waiting for each response.
1609     res = PMTimeout(waittime, true);
1610     if(OC_STACK_OK != res)
1611     {
1612         OIC_LOG(ERROR, TAG, "Failed to wait response for secure discovery.");
1613         OICFree(pDInfo);
1614         OCStackResult resCancel = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
1615         if(OC_STACK_OK !=  resCancel)
1616         {
1617             OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1618         }
1619         return res;
1620     }
1621     res = OCCancel(handle,OC_HIGH_QOS,NULL,0);
1622     if (OC_STACK_OK != res)
1623     {
1624         OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
1625         OICFree(pDInfo);
1626         return res;
1627     }
1628     OIC_LOG(DEBUG, TAG, "OUT PMMultipleOwnerEnabledDeviceDiscovery");
1629     OICFree(pDInfo);
1630     return res;
1631 }
1632
1633 /**
1634  * The function is responsible for determining if the caller is a subowner of the specified device.
1635  *
1636  * @param[in] device       MOT enabled device that contains a list of subowners
1637  * @param[out] isSubowner  Bool indicating whether the caller is a subowner of device
1638  *
1639  * @return OC_STACK_OK in case of success and other value otherwise.
1640  */
1641 OCStackResult PMIsSubownerOfDevice(OCProvisionDev_t *device, bool *isSubowner)
1642 {  
1643     if ((NULL == device) || (NULL == isSubowner))
1644     {
1645         return OC_STACK_INVALID_PARAM;
1646     }
1647
1648     OicUuid_t myId;
1649     memset(&myId, 0, sizeof(myId));
1650     OicSecSubOwner_t* subOwner = NULL;
1651
1652     *isSubowner = false;
1653
1654     OCStackResult result = GetDoxmDeviceID(&myId);
1655     if (OC_STACK_OK == result)
1656     {
1657         LL_FOREACH(device->doxm->subOwners, subOwner)
1658         {
1659             if (memcmp(myId.id, subOwner->uuid.id, sizeof(myId.id)) == 0)
1660             {
1661                 *isSubowner = true;
1662                 break;
1663             }
1664         }
1665     }
1666     else
1667     {
1668         OIC_LOG(ERROR, TAG, "Error while getting my UUID.");
1669     }
1670
1671     return result;
1672 }
1673 #endif //MULTIPLE_OWNER
1674
1675 static OCStackResult SecurePortDiscovery(DiscoveryInfo* discoveryInfo,
1676                                          const OCClientResponse *clientResponse)
1677 {
1678     OIC_LOG(DEBUG, TAG, "IN SecurePortDiscovery");
1679
1680     if(NULL == discoveryInfo || NULL == clientResponse)
1681     {
1682         return OC_STACK_INVALID_PARAM;
1683     }
1684
1685     OCProvisionDev_t *pDev = GetDevice(&discoveryInfo->pCandidateList,
1686                         clientResponse->devAddr.addr, clientResponse->devAddr.port);
1687     if(NULL == pDev)
1688     {
1689         OIC_LOG(ERROR, TAG, "SecurePortDiscovery : Failed to get device");
1690         return OC_STACK_ERROR;
1691     }
1692
1693     //Try to the unicast discovery to getting secure port
1694     char query[MAX_URI_LENGTH+MAX_QUERY_LENGTH+1] = {0};
1695     if(!PMGenerateQuery(false,
1696                         pDev->endpoint.addr, pDev->endpoint.port,
1697                         pDev->connType,
1698                         query, sizeof(query), OC_RSRVD_WELL_KNOWN_URI))
1699     {
1700         OIC_LOG(ERROR, TAG, "SecurePortDiscovery : Failed to generate query");
1701         return OC_STACK_ERROR;
1702     }
1703     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
1704
1705     // Set filter query with rt=oic.r.doxm
1706     const char RES_DOXM_QUERY_FMT[] = "%s?%s=%s";
1707     char uri[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
1708     snprintf(uri, sizeof(uri), RES_DOXM_QUERY_FMT, query,
1709             OC_RSRVD_RESOURCE_TYPE, OIC_RSRC_TYPE_SEC_DOXM);
1710
1711     OIC_LOG_V(DEBUG, TAG, "URI=%s", uri);
1712
1713     OCCallbackData cbData;
1714     cbData.cb = &SecurePortDiscoveryHandler;
1715     cbData.context = (void*)discoveryInfo;
1716     cbData.cd = NULL;
1717     OCStackResult ret = OCDoResource(&pDev->handle, OC_REST_DISCOVER, uri, 0, 0,
1718             pDev->connType, OC_HIGH_QOS, &cbData, NULL, 0);
1719     if(OC_STACK_OK != ret)
1720     {
1721         OIC_LOG(ERROR, TAG, "Failed to Secure Port Discovery");
1722         return ret;
1723     }
1724     else
1725     {
1726         OIC_LOG_V(INFO, TAG, "OCDoResource with [%s] Success", query);
1727     }
1728
1729     OIC_LOG(DEBUG, TAG, "OUT SecurePortDiscovery");
1730
1731     return ret;
1732 }
1733
1734
1735 static OCStackResult SpecVersionDiscovery(DiscoveryInfo* discoveryInfo,
1736                                               const OCClientResponse *clientResponse)
1737 {
1738     OIC_LOG(DEBUG, TAG, "IN SpecVersionDiscovery");
1739
1740     if(NULL == discoveryInfo || NULL == clientResponse)
1741     {
1742         return OC_STACK_INVALID_PARAM;
1743     }
1744
1745     //Try to the unicast discovery to getting security version
1746     char query[MAX_URI_LENGTH+MAX_QUERY_LENGTH+1] = {0};
1747     if(!PMGenerateQuery(false,
1748                         clientResponse->devAddr.addr, clientResponse->devAddr.port,
1749                         clientResponse->connType,
1750                         query, sizeof(query), OC_RSRVD_DEVICE_URI))
1751     {
1752         OIC_LOG(ERROR, TAG, "SpecVersionDiscovery : Failed to generate query");
1753         return OC_STACK_ERROR;
1754     }
1755     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
1756
1757     OCCallbackData cbData;
1758     cbData.cb = &SpecVersionDiscoveryHandler;
1759     cbData.context = (void*)discoveryInfo;
1760     cbData.cd = NULL;
1761     OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, query, 0, 0,
1762             clientResponse->connType, OC_HIGH_QOS, &cbData, NULL, 0);
1763     if(OC_STACK_OK != ret)
1764     {
1765         OIC_LOG(ERROR, TAG, "Failed to Security Version Discovery");
1766         return ret;
1767     }
1768     else
1769     {
1770         OIC_LOG_V(INFO, TAG, "OCDoResource with [%s] Success", query);
1771     }
1772
1773     OIC_LOG(DEBUG, TAG, "OUT SpecVersionDiscovery");
1774
1775     return ret;
1776 }
1777
1778 /**
1779  * Function to print OCProvisionDev_t for debug purpose.
1780  *
1781  * @param[in] pDev Pointer to OCProvisionDev_t. It's information will be printed by OIC_LOG_XX
1782  *
1783  */
1784 void PMPrintOCProvisionDev(const OCProvisionDev_t* pDev)
1785 {
1786     if (pDev)
1787     {
1788         OIC_LOG(DEBUG, TAG, "+++++ OCProvisionDev_t Information +++++");
1789         OIC_LOG_V(DEBUG, TAG, "IP %s", pDev->endpoint.addr);
1790         OIC_LOG_V(DEBUG, TAG, "PORT %d", pDev->endpoint.port);
1791         OIC_LOG_V(DEBUG, TAG, "S-PORT %d", pDev->securePort);
1792         OIC_LOG(DEBUG, TAG, "++++++++++++++++++++++++++++++++++++++++");
1793     }
1794     else
1795     {
1796         OIC_LOG(DEBUG, TAG, "+++++ OCProvisionDev_t is NULL +++++");
1797     }
1798 }
1799
1800 bool PMDeleteFromUUIDList(OCUuidList_t **pUuidList, OicUuid_t *targetId)
1801 {
1802     if(*pUuidList == NULL || targetId == NULL)
1803     {
1804         return false;
1805     }
1806     OCUuidList_t *tmp1 = NULL,*tmp2=NULL;
1807     LL_FOREACH_SAFE(*pUuidList, tmp1, tmp2)
1808     {
1809         if(0 == memcmp(tmp1->dev.id, targetId->id, sizeof(targetId->id)))
1810         {
1811             LL_DELETE(*pUuidList, tmp1);
1812             OICFree(tmp1);
1813             return true;
1814         }
1815     }
1816     return false;
1817 }