1e86d3f730c4f99bc8f687965c342a804db9db49
[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. Note that this can only return one, so the caller must
406  * call multiple times to get the list, which is pretty inefficient. The caller is
407  * responsible for freeing the pointer returned via OICFree().
408  * @todo Change the API to allow returning a list or, even better, allow calling
409  *       CAIPPassNetworkChangesToTransportAdapter() at any time from IpAddressChangeCallback.
410  *
411  * @return  Dynamically allocated IP address entry, or NULL if no change.
412  */
413 CAInterface_t *CAFindInterfaceChange()
414 {
415     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
416
417     bool someAddressWentAway = g_CAIPNetworkMonitorSomeAddressWentAway;
418     g_CAIPNetworkMonitorSomeAddressWentAway = false;
419
420     CAInterface_t *newAddress = NULL;
421     if (g_CAIPNetworkMonitorNewAddressQueue)
422     {
423         // Pop the first new address to return.
424         CANewAddress_t *change = g_CAIPNetworkMonitorNewAddressQueue;
425         DL_DELETE(g_CAIPNetworkMonitorNewAddressQueue, change);
426         newAddress = change->ipAddressInfo;
427         OICFree(change);
428     }
429
430     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
431
432     if (someAddressWentAway)
433     {
434         CAIPPassNetworkChangesToTransportAdapter(CA_INTERFACE_DOWN);
435     }
436     if (newAddress)
437     {
438         CAIPPassNetworkChangesToTransportAdapter(CA_INTERFACE_UP);
439     }
440
441     return newAddress;
442 }
443
444 static bool IsValidNetworkAdapter(PIP_ADAPTER_ADDRESSES pAdapterAddr, int desiredIndex)
445 {
446     bool valid = true;
447
448     // If desiredIndex is non-zero, then only retrieve adapter corresponding to desiredIndex.
449     // If desiredIndex is zero, then retrieve all adapters.
450     if (desiredIndex && (pAdapterAddr->IfIndex != desiredIndex))
451     {
452         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i not interesting.", pAdapterAddr->IfIndex);
453         valid = false;
454     }
455
456     if (pAdapterAddr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
457     {
458         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i is loopback.", pAdapterAddr->IfIndex);
459         valid = false;
460     }
461
462     if ((pAdapterAddr->OperStatus & IfOperStatusUp) == 0)
463     {
464         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i is not operational.", pAdapterAddr->IfIndex);
465         valid = false;
466     }
467     return valid;
468 }
469
470 /*
471  * Allocate a new CAInterface_t structure and add it to a given list.  A new entry is added
472  * for each address.
473  *
474  * @param[in/out] iflist  List to add to.
475  * @param[in]     name    Interface name.
476  * @param[in]     index   Interface index.
477  * @param[in]     family  Address family.
478  * @param[in]     addr    Address.
479  * @return Pointer to entry added, or NULL on failure.
480  */
481 CAInterface_t *AddCAInterface(u_arraylist_t *iflist, const char *name, uint32_t index,
482                               uint16_t family, const char *addr)
483 {
484     CAInterface_t *ifitem = AllocateCAInterface(index, name, family, addr, IFF_UP);
485     if (ifitem == NULL)
486     {
487         return NULL;
488     }
489
490     if (!u_arraylist_add(iflist, ifitem))
491     {
492         OIC_LOG(ERROR, TAG, "u_arraylist_add failed");
493         OICFree(ifitem);
494         return NULL;
495     }
496
497     return ifitem;
498 }
499
500 bool IsValidAddress(PIP_ADAPTER_UNICAST_ADDRESS pAddress)
501 {
502     if (pAddress->Address.lpSockaddr->sa_family != AF_INET6)
503     {
504         // All IPv4 addresses are valid.
505         return true;
506     }
507
508     PSOCKADDR_IN6 sockAddr = (PSOCKADDR_IN6)pAddress->Address.lpSockaddr;
509     if (Ipv6UnicastAddressScope(sockAddr->sin6_addr.s6_addr) == ScopeLevelLink)
510     {
511         // IPv6 link local addresses are valid.
512         return true;
513     }
514
515     // Other IPv6 addresses are valid if they are DNS eligible.
516     // That is, ignore temporary addresses.
517     return ((pAddress->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE) != 0);
518 }
519
520 bool AddAddresses(PIP_ADAPTER_ADDRESSES pAdapterAddr, u_arraylist_t *iflist, int desiredIndex)
521 {
522     bool bSucceeded = true;
523     for (PIP_ADAPTER_ADDRESSES pCurAdapterAddr = pAdapterAddr;
524          pCurAdapterAddr != NULL; pCurAdapterAddr = pCurAdapterAddr->Next)
525     {
526         OIC_LOG_V(DEBUG, TAG, "\tInterface Index: %u", pCurAdapterAddr->IfIndex);
527         OIC_LOG_V(DEBUG, TAG, "\tInterface  name: %s", pCurAdapterAddr->AdapterName);
528
529         if (!IsValidNetworkAdapter(pCurAdapterAddr, desiredIndex))
530         {
531             continue;
532         }
533
534         for (PIP_ADAPTER_UNICAST_ADDRESS pAddress = pCurAdapterAddr->FirstUnicastAddress;
535              pAddress != NULL;
536              pAddress = pAddress->Next)
537         {
538             if (!IsValidAddress(pAddress))
539             {
540                 continue;
541             }
542
543             char addr[INET6_ADDRSTRLEN];
544             if (!inet_ntop(pAddress->Address.lpSockaddr->sa_family,
545                            INETADDR_ADDRESS(pAddress->Address.lpSockaddr),
546                            addr,
547                            sizeof(addr)))
548             {
549                 continue;
550             }
551
552             CAInterface_t *ipAddressInfo = AddCAInterface(iflist, pCurAdapterAddr->AdapterName,
553                                                           pCurAdapterAddr->IfIndex,
554                                                           pAddress->Address.lpSockaddr->sa_family,
555                                                           addr);
556             if (!ipAddressInfo)
557             {
558                 OIC_LOG_V(ERROR, TAG, "\tAdding address on interface %i failed",
559                           pCurAdapterAddr->IfIndex);
560                 bSucceeded = false;
561                 break;
562             }
563
564             OIC_LOG_V(DEBUG, TAG, "\t\tAdded address %s", ipAddressInfo->addr);
565         }
566     }
567     return bSucceeded;
568 }
569
570 /*
571  * Get the set of IP_ADAPTER_ADDRESSES structures.  The caller is responsible for
572  * freeng the set using OICFree on the pointer returned.
573  *
574  * @return List of network adapters.
575  */
576 PIP_ADAPTER_ADDRESSES GetAdapters()
577 {
578     ULONG ulOutBufLen = 0;
579     PIP_ADAPTER_ADDRESSES pAdapterAddr = NULL;
580
581     // We don't need most of the default information, so optimize this call by not
582     // asking for them.
583     ULONG flags = GAA_FLAG_SKIP_ANYCAST |
584                   GAA_FLAG_SKIP_MULTICAST |
585                   GAA_FLAG_SKIP_DNS_SERVER |
586                   GAA_FLAG_SKIP_FRIENDLY_NAME;
587
588     // Call up to 3 times: once to get the size, once to get the data, and once more
589     // just in case there was an increase in length in between the first two. If the
590     // length is still increasing due to more addresses being added, even this may fail
591     // and we'll have to wait for the next IP address change notification.
592     for (int i = 0; i < 3; i++)
593     {
594         ULONG ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapterAddr, &ulOutBufLen);
595         if (ERROR_BUFFER_OVERFLOW == ret)
596         {
597             // Redo with updated length.
598             if (pAdapterAddr != NULL)
599             {
600                 OICFree(pAdapterAddr);
601             }
602             pAdapterAddr = (PIP_ADAPTER_ADDRESSES) OICMalloc(ulOutBufLen);
603             if (pAdapterAddr == NULL) {
604                 OIC_LOG(ERROR, TAG, "Allocating memory for GetAdaptersAddresses() failed");
605                 break;
606             }
607             continue;
608         }
609         if (NO_ERROR != ret)
610         {
611             OIC_LOG(ERROR, TAG, "GetAdaptersAddresses() failed");
612             break;
613         }
614
615         // Succeeded getting adapters
616         return pAdapterAddr;
617     }
618
619     if (pAdapterAddr != NULL)
620     {
621         OICFree(pAdapterAddr);
622     }
623     return NULL;
624 }
625
626 /**
627  * Get the list of CAInterface_t items.  Currently only 0 is passed as the desiredIndex by any
628  * caller.
629  *
630  * @param[in]  desiredIndex      Network interface index, or 0 for all.
631  * @return  List of CAInterface_t items.
632  */
633 static u_arraylist_t *GetInterfaceInformation(int desiredIndex)
634 {
635     if (desiredIndex < 0)
636     {
637         OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
638         return NULL;
639     }
640
641     u_arraylist_t *iflist = u_arraylist_create();
642     if (!iflist)
643     {
644         OIC_LOG(ERROR, TAG, "Failed to create iflist");
645         return NULL;
646     }
647
648     PIP_ADAPTER_ADDRESSES pAdapterAddr = GetAdapters();
649     if (!pAdapterAddr)
650     {
651         OIC_LOG(ERROR, TAG, "Enumerating Adapters failed");
652         u_arraylist_destroy(iflist);
653         return NULL;
654     }
655
656     // Cycle through network adapters.
657     // Add valid network addresses to the address list.
658     bool ret = AddAddresses(pAdapterAddr, iflist, desiredIndex);
659     if (false == ret)
660     {
661         OIC_LOG(ERROR, TAG, "AddAddresses() failed");
662         u_arraylist_destroy(iflist);
663         iflist = NULL;
664     }
665
666     // Finished with network adapter list.
667     OICFree(pAdapterAddr);
668
669     return iflist;
670 }
671
672 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
673 {
674     u_arraylist_t *iflist = u_arraylist_create();
675     if (!iflist)
676     {
677         OIC_LOG(ERROR, TAG, "Failed to create iflist");
678         return NULL;
679     }
680
681     // Avoid extra kernel calls by just duplicating what's in our cache.
682     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
683
684     uint32_t list_length = u_arraylist_length(g_CAIPNetworkMonitorAddressList);
685     for (uint32_t list_index = 0; list_index < list_length; list_index++)
686     {
687         CAInterface_t *currItem = (CAInterface_t *)u_arraylist_get(g_CAIPNetworkMonitorAddressList,
688                                                                    list_index);
689         if (!AddCAInterface(iflist, currItem->name, currItem->index, currItem->family,
690                             currItem->addr))
691         {
692             OIC_LOG(ERROR, TAG, "AddCAInterface() failed");
693             u_arraylist_destroy(iflist);
694             iflist = NULL;
695             break;
696         }
697     }
698
699     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
700
701     return iflist;
702 }