[IOT-1361]Change "CAFindInterfaceChange()" to support IPv4/6
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / windows / caipnwmonitor.c
1 /* *****************************************************************
2 *
3 * Copyright 2016 Microsoft
4 *
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************/
19
20 #include "iotivity_config.h"
21 #include "caipinterface.h"
22
23 #include <assert.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <winsock2.h>
27 #include <ws2tcpip.h>
28 #include <iphlpapi.h>
29 #include <mstcpip.h>
30 #include <iptypes.h>
31 #include <stdbool.h>
32 #include "octhread.h"
33 #include "caadapterutils.h"
34 #include "logger.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37 #include "caipnwmonitor.h"
38 #include <coap/utlist.h>
39
40 #define TAG "IP_MONITOR"
41
42 /**
43  * Mutex for synchronizing access to cached address information.
44  */
45 static oc_mutex g_CAIPNetworkMonitorMutex = NULL;
46
47 static bool g_CAIPNetworkMonitorSomeAddressWentAway = false;
48
49 typedef struct CANewAddress_t {
50     struct CANewAddress_t *next;
51     struct CANewAddress_t *prev;
52     CAInterface_t *ipAddressInfo; 
53 } CANewAddress_t;
54
55 /**
56  * List of network addresses that we've already reported.
57  */
58 static u_arraylist_t *g_CAIPNetworkMonitorAddressList = NULL;
59
60 /**
61  * Queue of new addresses that haven't yet been returned in CAFindInterfaceChange().
62  */
63 static CANewAddress_t *g_CAIPNetworkMonitorNewAddressQueue = NULL;
64
65 /**
66  * Transport adapter change callback list.
67  */
68 static struct CAIPCBData_t *g_CAIPNetworkMonitorAdapterCallbackList = NULL;
69
70 static CAInterface_t *AllocateCAInterface(int index, const char *name, int family,
71                                           const char *addr, int flags);
72
73 static u_arraylist_t *GetInterfaceInformation(int desiredIndex);
74
75 static void CAIPDestroyNetworkMonitorList();
76
77 static CAResult_t CAIPInitializeNetworkMonitorList()
78 {
79     assert(!g_CAIPNetworkMonitorMutex);
80     assert(!g_CAIPNetworkMonitorAddressList);
81
82     g_CAIPNetworkMonitorMutex = oc_mutex_new();
83     if (!g_CAIPNetworkMonitorMutex)
84     {
85         OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
86         return CA_STATUS_FAILED;
87     }
88
89     g_CAIPNetworkMonitorAddressList = u_arraylist_create();
90     if (!g_CAIPNetworkMonitorAddressList)
91     {
92         OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
93         CAIPDestroyNetworkMonitorList();
94         return CA_STATUS_FAILED;
95     }
96
97     return CA_STATUS_OK;
98 }
99
100 /**
101  * Destroy the network monitoring list.
102  */
103 static void CAIPDestroyNetworkMonitorList()
104 {
105     // Free any new addresses waiting to be indicated up.
106     while (g_CAIPNetworkMonitorNewAddressQueue)
107     {
108         CANewAddress_t *change = g_CAIPNetworkMonitorNewAddressQueue;
109         DL_DELETE(g_CAIPNetworkMonitorNewAddressQueue, change);
110         OICFree(change->ipAddressInfo);
111         OICFree(change);
112     }
113
114     // Free our cache of operational addresses.
115     if (g_CAIPNetworkMonitorAddressList)
116     {
117         u_arraylist_destroy(g_CAIPNetworkMonitorAddressList);
118         g_CAIPNetworkMonitorAddressList = NULL;
119     }
120
121     if (g_CAIPNetworkMonitorMutex)
122     {
123         oc_mutex_free(g_CAIPNetworkMonitorMutex);
124         g_CAIPNetworkMonitorMutex = NULL;
125     }
126 }
127
128 /**
129  * See if a CAInterface_t with a given index and address already exists in a list.
130  *
131  * @param[in] ifIndex  Interface index to look for.
132  * @param[in] family   Family of address to look for.
133  * @param[in] addr     Address to look for.
134  * @return true if already in the list, false if not.
135  */
136 static bool CACmpNetworkList(uint32_t ifIndex, int family, const char *addr, u_arraylist_t *iflist)
137 {
138     uint32_t list_length = u_arraylist_length(iflist);
139     for (uint32_t list_index = 0; list_index < list_length; list_index++)
140     {
141         CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(iflist, list_index);
142         if ((currItem->index == ifIndex) && (currItem->family == family) &&
143             (strcmp(currItem->addr, addr) == 0))
144         {
145             return true;
146         }
147     }
148     return false;
149 }
150
151 static HANDLE g_CAIPNetworkMonitorChangeNotificationHandle = NULL;
152
153 /**
154  * Handle a notification that the IP address info changed.
155  *
156  * @param[in]  context           Context passed to NotifyUnicastIpChange.
157  * @param[in]  row               Interface that changed, or NULL on the initial callback.
158  * @param[in]  notificationType  Type of change that occurred.
159  */
160 static void CALLBACK IpAddressChangeCallback(void *context,
161                                              MIB_UNICASTIPADDRESS_ROW *row,
162                                              MIB_NOTIFICATION_TYPE notificationType)
163 {
164     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
165
166     // Fetch new network address info.
167     u_arraylist_t *newList = GetInterfaceInformation(0);
168     uint32_t newLen = u_arraylist_length(newList);
169
170     u_arraylist_t *oldList = g_CAIPNetworkMonitorAddressList;
171     uint32_t oldLen = u_arraylist_length(oldList);
172
173     if (caglobals.ip.addressChangeEvent)
174     {
175         // Check whether any addresses went away.
176         for (uint32_t i = 0; i < oldLen; i++)
177         {
178             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(oldList, i);
179             if (!CACmpNetworkList(ifitem->index, ifitem->family, ifitem->addr, newList))
180             {
181                 g_CAIPNetworkMonitorSomeAddressWentAway = true;
182                 break;
183             }
184         }
185
186         // Check whether any new addresses are available.
187         for (uint32_t i = 0; i < newLen; i++)
188         {
189             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(newList, i);
190             if (!CACmpNetworkList(ifitem->index, ifitem->family, ifitem->addr, oldList))
191             {
192                 // Create a new CAInterface_t to add to the queue to indicate to the higher
193                 // layer.  We cannot simply invoke the callback here currently, since the
194                 // higher layer is not thread-safe.
195                 CAInterface_t *dup = AllocateCAInterface(ifitem->index, ifitem->name,
196                                                          ifitem->family, ifitem->addr,
197                                                          ifitem->flags);
198                 CANewAddress_t *change = (CANewAddress_t *)OICCalloc(1, sizeof(*change));
199                 if (change)
200                 {
201                     change->ipAddressInfo = dup;
202                     DL_APPEND(g_CAIPNetworkMonitorNewAddressQueue, change);
203                 }
204                 else
205                 {
206                     OIC_LOG(WARNING, TAG, "Couldn't allocate memory for CANewAddress_t");
207                 }
208             }
209         }
210
211         // If the new address queue is not empty, signal the transport server that it needs
212         // to call CAFindInterfaceChange().  We don't need to set the event if an address
213         // went away, since the higher layer just uses the event to ask for new addresses
214         // in order to join the multicast group on the associated interface and address family.
215         if (g_CAIPNetworkMonitorNewAddressQueue)
216         {
217             int ret = WSASetEvent(caglobals.ip.addressChangeEvent);
218
219             // Setting the event should always succeed, since the handle should always be
220             // valid when this code is reached.
221             assert(ret);
222         }
223     }
224
225     // Replace old cached info.
226     g_CAIPNetworkMonitorAddressList = newList;
227     u_arraylist_destroy(oldList);
228
229     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
230 }
231
232 /**
233  * Start network monitor.
234  *
235  * @param[in]  callback     Callback to be notified when IP/TCP adapter connection state changes.
236  * @param[in]  adapter      Transport adapter.
237  * @return ::CA_STATUS_OK or an appropriate error code.
238  */
239 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
240                                    CATransportAdapter_t adapter)
241 {
242     CAResult_t res = CAIPInitializeNetworkMonitorList();
243     if (res != CA_STATUS_OK)
244     {
245         return res;
246     }
247
248     res = CAIPSetNetworkMonitorCallback(callback, adapter);
249     if (res != CA_STATUS_OK)
250     {
251         return res;
252     }
253
254     if (g_CAIPNetworkMonitorChangeNotificationHandle == NULL)
255     {
256         int err = NotifyUnicastIpAddressChange(AF_UNSPEC, IpAddressChangeCallback, NULL,
257                                                true,
258                                                &g_CAIPNetworkMonitorChangeNotificationHandle);
259         if (err != NO_ERROR)
260         {
261             return CA_STATUS_FAILED;
262         }
263     }
264     return CA_STATUS_OK;
265 }
266
267 /**
268  * Stops network monitor.
269  *
270  * @param[in]  adapter      Transport adapter.
271  * @return ::CA_STATUS_OK or an appropriate error code.
272  */
273 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
274 {
275     if (g_CAIPNetworkMonitorChangeNotificationHandle != NULL)
276     {
277         int err = CancelMibChangeNotify2(g_CAIPNetworkMonitorChangeNotificationHandle);
278         assert(err == NO_ERROR);
279         g_CAIPNetworkMonitorChangeNotificationHandle = NULL;
280     }
281
282     CAIPDestroyNetworkMonitorList();
283     return CAIPUnSetNetworkMonitorCallback(adapter);
284 }
285
286 /**
287  * Let the network monitor update the polling interval.
288  * @param[in] interval Current polling interval, in seconds
289  *
290  * @return  desired polling interval
291  */
292 int CAGetPollingInterval(int interval)
293 {
294     // Don't change the polling interval.
295     return interval;
296 }
297
298 /**
299  * Pass the changed network status through the stored callback.
300  * Note that the current API doesn't allow us to specify which address changed,
301  * the caller has to look at the return from CAFindInterfaceChange() to learn about
302  * each new address, and look through CAIPGetInterfaceInformation() to see what's
303  * missing to detect any removed addresses.
304  *
305  * @param[in] status Network status to pass to the callback.
306  */
307 static void CAIPPassNetworkChangesToTransportAdapter(CANetworkStatus_t status)
308 {
309     CAIPCBData_t *cbitem = NULL;
310     LL_FOREACH(g_CAIPNetworkMonitorAdapterCallbackList, cbitem)
311     {
312         if (cbitem && cbitem->adapter)
313         {
314             cbitem->callback(cbitem->adapter, status);
315         }
316     }
317 }
318
319 /**
320  * Set callback for receiving local IP/TCP adapter connection status.
321  *
322  * @param[in]  callback     Callback to be notified when IP/TCP adapter connection state changes.
323  * @param[in]  adapter      Transport adapter.
324  * @return ::CA_STATUS_OK or an appropriate error code.
325  */
326 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
327                                          CATransportAdapter_t adapter)
328 {
329     if (!callback)
330     {
331         OIC_LOG(ERROR, TAG, "callback is null");
332         return CA_STATUS_INVALID_PARAM;
333     }
334
335     CAIPCBData_t *cbitem = NULL;
336     LL_FOREACH(g_CAIPNetworkMonitorAdapterCallbackList, cbitem)
337     {
338         if ((adapter == cbitem->adapter) && (callback == cbitem->callback))
339         {
340             OIC_LOG(DEBUG, TAG, "this callback is already added");
341             return CA_STATUS_OK;
342         }
343     }
344
345     cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
346     if (!cbitem)
347     {
348         OIC_LOG(ERROR, TAG, "Malloc failed");
349         return CA_STATUS_FAILED;
350     }
351
352     cbitem->adapter = adapter;
353     cbitem->callback = callback;
354     LL_APPEND(g_CAIPNetworkMonitorAdapterCallbackList, cbitem);
355
356     return CA_STATUS_OK;
357 }
358
359 /**
360  * Unset callback for receiving local IP/TCP adapter connection status.
361  *
362  * @param[in]  adapter      Transport adapter.
363  * @return CA_STATUS_OK.
364  */
365 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
366 {
367     CAIPCBData_t *cbitem = NULL;
368     CAIPCBData_t *tmpCbitem = NULL;
369     LL_FOREACH_SAFE(g_CAIPNetworkMonitorAdapterCallbackList, cbitem, tmpCbitem)
370     {
371         if (cbitem && adapter == cbitem->adapter)
372         {
373             OIC_LOG(DEBUG, TAG, "remove specific callback");
374             LL_DELETE(g_CAIPNetworkMonitorAdapterCallbackList, cbitem);
375             OICFree(cbitem);
376             return CA_STATUS_OK;
377         }
378     }
379     return CA_STATUS_OK;
380 }
381
382 /**
383  * Allocate a new CAInterface_t entry for a given IP address.
384  */
385 static CAInterface_t *AllocateCAInterface(int index, const char *name, int family,
386                                           const char *addr, int flags)
387 {
388     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(*ifitem));
389     if (!ifitem)
390     {
391         OIC_LOG(ERROR, TAG, "Allocating memory for a CAInterface_t failed");
392         return NULL;
393     }
394
395     OICStrcpy(ifitem->name, sizeof(ifitem->name), name);
396     ifitem->index = index;
397     ifitem->family = family;
398     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
399     ifitem->flags = flags;
400
401     return ifitem;
402 }
403
404 /**
405  * Find a new IP address.
406  * The caller is responsible for freeing the pointer returned via u_arraylist_destroy().
407  *
408  * @return  Dynamically allocated IP address list, or NULL if no change.
409  */
410 u_arraylist_t  *CAFindInterfaceChange()
411 {
412     u_arraylist_t *iflist = u_arraylist_create();
413     if (!iflist)
414     {
415         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
416         return NULL;
417     }
418
419     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
420
421     bool someAddressWentAway = g_CAIPNetworkMonitorSomeAddressWentAway;
422     g_CAIPNetworkMonitorSomeAddressWentAway = false;
423
424     bool newAddress = false;
425
426     // Pop whole new address in list.
427     while (g_CAIPNetworkMonitorNewAddressQueue)
428     {
429         CANewAddress_t *change = g_CAIPNetworkMonitorNewAddressQueue;
430
431         bool result = u_arraylist_add(iflist, change->ipAddressInfo);
432         if (!result)
433         {
434             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
435             break;
436         }
437         else
438         {
439             DL_DELETE(g_CAIPNetworkMonitorNewAddressQueue, change);
440             OICFree(change);
441             newAddress = true;
442         }
443     }
444
445     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
446
447     if (someAddressWentAway)
448     {
449         CAIPPassNetworkChangesToTransportAdapter(CA_INTERFACE_DOWN);
450     }
451     if (newAddress)
452     {
453         CAIPPassNetworkChangesToTransportAdapter(CA_INTERFACE_UP);
454     }
455
456     return iflist;
457 }
458
459 static bool IsValidNetworkAdapter(PIP_ADAPTER_ADDRESSES pAdapterAddr, int desiredIndex)
460 {
461     bool valid = true;
462
463     // If desiredIndex is non-zero, then only retrieve adapter corresponding to desiredIndex.
464     // If desiredIndex is zero, then retrieve all adapters.
465     if (desiredIndex && (pAdapterAddr->IfIndex != desiredIndex))
466     {
467         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i not interesting.", pAdapterAddr->IfIndex);
468         valid = false;
469     }
470
471     if (pAdapterAddr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
472     {
473         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i is loopback.", pAdapterAddr->IfIndex);
474         valid = false;
475     }
476
477     if ((pAdapterAddr->OperStatus & IfOperStatusUp) == 0)
478     {
479         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i is not operational.", pAdapterAddr->IfIndex);
480         valid = false;
481     }
482     return valid;
483 }
484
485 /*
486  * Allocate a new CAInterface_t structure and add it to a given list.  A new entry is added
487  * for each address.
488  *
489  * @param[in/out] iflist  List to add to.
490  * @param[in]     name    Interface name.
491  * @param[in]     index   Interface index.
492  * @param[in]     family  Address family.
493  * @param[in]     addr    Address.
494  * @return Pointer to entry added, or NULL on failure.
495  */
496 CAInterface_t *AddCAInterface(u_arraylist_t *iflist, const char *name, uint32_t index,
497                               uint16_t family, const char *addr)
498 {
499     CAInterface_t *ifitem = AllocateCAInterface(index, name, family, addr, IFF_UP);
500     if (ifitem == NULL)
501     {
502         return NULL;
503     }
504
505     if (!u_arraylist_add(iflist, ifitem))
506     {
507         OIC_LOG(ERROR, TAG, "u_arraylist_add failed");
508         OICFree(ifitem);
509         return NULL;
510     }
511
512     return ifitem;
513 }
514
515 bool IsValidAddress(PIP_ADAPTER_UNICAST_ADDRESS pAddress)
516 {
517     if (pAddress->Address.lpSockaddr->sa_family != AF_INET6)
518     {
519         // All IPv4 addresses are valid.
520         return true;
521     }
522
523     PSOCKADDR_IN6 sockAddr = (PSOCKADDR_IN6)pAddress->Address.lpSockaddr;
524     if (Ipv6UnicastAddressScope(sockAddr->sin6_addr.s6_addr) == ScopeLevelLink)
525     {
526         // IPv6 link local addresses are valid.
527         return true;
528     }
529
530     // Other IPv6 addresses are valid if they are DNS eligible.
531     // That is, ignore temporary addresses.
532     return ((pAddress->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE) != 0);
533 }
534
535 bool AddAddresses(PIP_ADAPTER_ADDRESSES pAdapterAddr, u_arraylist_t *iflist, int desiredIndex)
536 {
537     bool bSucceeded = true;
538     for (PIP_ADAPTER_ADDRESSES pCurAdapterAddr = pAdapterAddr;
539          pCurAdapterAddr != NULL; pCurAdapterAddr = pCurAdapterAddr->Next)
540     {
541         OIC_LOG_V(DEBUG, TAG, "\tInterface Index: %u", pCurAdapterAddr->IfIndex);
542         OIC_LOG_V(DEBUG, TAG, "\tInterface  name: %s", pCurAdapterAddr->AdapterName);
543
544         if (!IsValidNetworkAdapter(pCurAdapterAddr, desiredIndex))
545         {
546             continue;
547         }
548
549         for (PIP_ADAPTER_UNICAST_ADDRESS pAddress = pCurAdapterAddr->FirstUnicastAddress;
550              pAddress != NULL;
551              pAddress = pAddress->Next)
552         {
553             if (!IsValidAddress(pAddress))
554             {
555                 continue;
556             }
557
558             char addr[INET6_ADDRSTRLEN];
559             if (!inet_ntop(pAddress->Address.lpSockaddr->sa_family,
560                            INETADDR_ADDRESS(pAddress->Address.lpSockaddr),
561                            addr,
562                            sizeof(addr)))
563             {
564                 continue;
565             }
566
567             CAInterface_t *ipAddressInfo = AddCAInterface(iflist, pCurAdapterAddr->AdapterName,
568                                                           pCurAdapterAddr->IfIndex,
569                                                           pAddress->Address.lpSockaddr->sa_family,
570                                                           addr);
571             if (!ipAddressInfo)
572             {
573                 OIC_LOG_V(ERROR, TAG, "\tAdding address on interface %i failed",
574                           pCurAdapterAddr->IfIndex);
575                 bSucceeded = false;
576                 break;
577             }
578
579             OIC_LOG_V(DEBUG, TAG, "\t\tAdded address %s", ipAddressInfo->addr);
580         }
581     }
582     return bSucceeded;
583 }
584
585 /*
586  * Get the set of IP_ADAPTER_ADDRESSES structures.  The caller is responsible for
587  * freeng the set using OICFree on the pointer returned.
588  *
589  * @return List of network adapters.
590  */
591 PIP_ADAPTER_ADDRESSES GetAdapters()
592 {
593     ULONG ulOutBufLen = 0;
594     PIP_ADAPTER_ADDRESSES pAdapterAddr = NULL;
595
596     // We don't need most of the default information, so optimize this call by not
597     // asking for them.
598     ULONG flags = GAA_FLAG_SKIP_ANYCAST |
599                   GAA_FLAG_SKIP_MULTICAST |
600                   GAA_FLAG_SKIP_DNS_SERVER |
601                   GAA_FLAG_SKIP_FRIENDLY_NAME;
602
603     // Call up to 3 times: once to get the size, once to get the data, and once more
604     // just in case there was an increase in length in between the first two. If the
605     // length is still increasing due to more addresses being added, even this may fail
606     // and we'll have to wait for the next IP address change notification.
607     for (int i = 0; i < 3; i++)
608     {
609         ULONG ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapterAddr, &ulOutBufLen);
610         if (ERROR_BUFFER_OVERFLOW == ret)
611         {
612             // Redo with updated length.
613             if (pAdapterAddr != NULL)
614             {
615                 OICFree(pAdapterAddr);
616             }
617             pAdapterAddr = (PIP_ADAPTER_ADDRESSES) OICMalloc(ulOutBufLen);
618             if (pAdapterAddr == NULL) {
619                 OIC_LOG(ERROR, TAG, "Allocating memory for GetAdaptersAddresses() failed");
620                 break;
621             }
622             continue;
623         }
624         if (NO_ERROR != ret)
625         {
626             OIC_LOG(ERROR, TAG, "GetAdaptersAddresses() failed");
627             break;
628         }
629
630         // Succeeded getting adapters
631         return pAdapterAddr;
632     }
633
634     if (pAdapterAddr != NULL)
635     {
636         OICFree(pAdapterAddr);
637     }
638     return NULL;
639 }
640
641 /**
642  * Get the list of CAInterface_t items.  Currently only 0 is passed as the desiredIndex by any
643  * caller.
644  *
645  * @param[in]  desiredIndex      Network interface index, or 0 for all.
646  * @return  List of CAInterface_t items.
647  */
648 static u_arraylist_t *GetInterfaceInformation(int desiredIndex)
649 {
650     if (desiredIndex < 0)
651     {
652         OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
653         return NULL;
654     }
655
656     u_arraylist_t *iflist = u_arraylist_create();
657     if (!iflist)
658     {
659         OIC_LOG(ERROR, TAG, "Failed to create iflist");
660         return NULL;
661     }
662
663     PIP_ADAPTER_ADDRESSES pAdapterAddr = GetAdapters();
664     if (!pAdapterAddr)
665     {
666         OIC_LOG(ERROR, TAG, "Enumerating Adapters failed");
667         u_arraylist_destroy(iflist);
668         return NULL;
669     }
670
671     // Cycle through network adapters.
672     // Add valid network addresses to the address list.
673     bool ret = AddAddresses(pAdapterAddr, iflist, desiredIndex);
674     if (false == ret)
675     {
676         OIC_LOG(ERROR, TAG, "AddAddresses() failed");
677         u_arraylist_destroy(iflist);
678         iflist = NULL;
679     }
680
681     // Finished with network adapter list.
682     OICFree(pAdapterAddr);
683
684     return iflist;
685 }
686
687 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
688 {
689     u_arraylist_t *iflist = u_arraylist_create();
690     if (!iflist)
691     {
692         OIC_LOG(ERROR, TAG, "Failed to create iflist");
693         return NULL;
694     }
695
696     // Avoid extra kernel calls by just duplicating what's in our cache.
697     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
698
699     uint32_t list_length = u_arraylist_length(g_CAIPNetworkMonitorAddressList);
700     for (uint32_t list_index = 0; list_index < list_length; list_index++)
701     {
702         CAInterface_t *currItem = (CAInterface_t *)u_arraylist_get(g_CAIPNetworkMonitorAddressList,
703                                                                    list_index);
704         if (!AddCAInterface(iflist, currItem->name, currItem->index, currItem->family,
705                             currItem->addr))
706         {
707             OIC_LOG(ERROR, TAG, "AddCAInterface() failed");
708             u_arraylist_destroy(iflist);
709             iflist = NULL;
710             break;
711         }
712     }
713
714     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
715
716     return iflist;
717 }