Use `URI` all caps in documentation
[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 "iotivity_debug.h"
22 #include "caipinterface.h"
23
24 #include <assert.h>
25 #include <sys/types.h>
26 #include <string.h>
27 #include <winsock2.h>
28 #include <ws2tcpip.h>
29 #include <iphlpapi.h>
30 #include <mstcpip.h>
31 #include <iptypes.h>
32 #include <stdbool.h>
33 #include "octhread.h"
34 #include "caadapterutils.h"
35 #include "experimental/logger.h"
36 #include "oic_malloc.h"
37 #include "oic_string.h"
38 #include "caipnwmonitor.h"
39 #include <coap/utlist.h>
40
41 #define TAG "IP_MONITOR"
42
43 // When this is defined, a socket will be used to get address change events.  The
44 // SIO_ADDRESS_LIST_CHANGE socket option is accessible on all versions of Windows
45 // and is available to both desktop and store apps, but it is more complex and hence
46 // more appropriate for use by applications using SIO_ADDRESS_LIST_QUERY to get addresses
47 // from Winsock rather than GetAdaptersAddresses() which we need to use to get additional
48 // information.  We expect NotifyUnicastIpAddressChange will be available to store apps
49 // at some point in the future and this workaround can go away at that point.
50 #define USE_SOCKET_ADDRESS_CHANGE_EVENT
51
52 /**
53 * Buffer size for PIP_ADAPTER_ADDRESSES
54 */
55 #define WORKING_BUFFER_SIZE 15000
56
57 /**
58  * Mutex for synchronizing access to cached address information.
59  */
60 static oc_mutex g_CAIPNetworkMonitorMutex = NULL;
61
62 static bool g_CAIPNetworkMonitorSomeAddressWentAway = false;
63
64 typedef struct CANewAddress_t {
65     struct CANewAddress_t *next;
66     struct CANewAddress_t *prev;
67     CAInterface_t *ipAddressInfo; 
68 } CANewAddress_t;
69
70 /**
71  * List of network addresses that we've already reported.
72  */
73 static u_arraylist_t *g_CAIPNetworkMonitorAddressList = NULL;
74
75 /**
76  * Queue of new addresses that haven't yet been returned in CAFindInterfaceChange().
77  */
78 static CANewAddress_t *g_CAIPNetworkMonitorNewAddressQueue = NULL;
79
80 /**
81  * Transport adapter change callback list.
82  */
83 static struct CAIPCBData_t *g_CAIPNetworkMonitorAdapterCallbackList = NULL;
84
85 static CAInterface_t *AllocateCAInterface(int index, const char *name, uint16_t family,
86                                           const char *addr, int flags);
87
88 static u_arraylist_t *GetInterfaceInformation(int desiredIndex);
89
90 static void CAIPDestroyNetworkMonitorList(void);
91
92 static CAResult_t CAIPInitializeNetworkMonitorList(void)
93 {
94     assert(!g_CAIPNetworkMonitorMutex);
95     assert(!g_CAIPNetworkMonitorAddressList);
96
97     g_CAIPNetworkMonitorMutex = oc_mutex_new();
98     if (!g_CAIPNetworkMonitorMutex)
99     {
100         OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
101         return CA_STATUS_FAILED;
102     }
103
104     g_CAIPNetworkMonitorAddressList = u_arraylist_create();
105     if (!g_CAIPNetworkMonitorAddressList)
106     {
107         OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
108         CAIPDestroyNetworkMonitorList();
109         return CA_STATUS_FAILED;
110     }
111
112     return CA_STATUS_OK;
113 }
114
115 /**
116  * Destroy the network monitoring list.
117  */
118 static void CAIPDestroyNetworkMonitorList(void)
119 {
120     // Free any new addresses waiting to be indicated up.
121     while (g_CAIPNetworkMonitorNewAddressQueue)
122     {
123         CANewAddress_t *change = g_CAIPNetworkMonitorNewAddressQueue;
124         DL_DELETE(g_CAIPNetworkMonitorNewAddressQueue, change);
125         OICFree(change->ipAddressInfo);
126         OICFree(change);
127     }
128
129     // Free our cache of operational addresses.
130     if (g_CAIPNetworkMonitorAddressList)
131     {
132         u_arraylist_destroy(g_CAIPNetworkMonitorAddressList);
133         g_CAIPNetworkMonitorAddressList = NULL;
134     }
135
136     if (g_CAIPNetworkMonitorMutex)
137     {
138         oc_mutex_free(g_CAIPNetworkMonitorMutex);
139         g_CAIPNetworkMonitorMutex = NULL;
140     }
141 }
142
143 /**
144  * See if a CAInterface_t with a given index and address already exists in a list.
145  *
146  * @param[in] ifIndex  Interface index to look for.
147  * @param[in] family   Family of address to look for.
148  * @param[in] addr     Address to look for.
149  * @return true if already in the list, false if not.
150  */
151 static bool CACmpNetworkList(uint32_t ifIndex, int family, const char *addr, u_arraylist_t *iflist)
152 {
153     size_t list_length = u_arraylist_length(iflist);
154     for (size_t list_index = 0; list_index < list_length; list_index++)
155     {
156         CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(iflist, list_index);
157         if ((currItem->index == ifIndex) && (currItem->family == family) &&
158             (strcmp(currItem->addr, addr) == 0))
159         {
160             return true;
161         }
162     }
163     return false;
164 }
165
166 static HANDLE g_CAIPNetworkMonitorNotificationHandle = NULL;
167
168 /**
169  * Handle a notification that the IP address info changed.
170  *
171  * @param[in]  context           Context passed to NotifyUnicastIpChange.
172  * @param[in]  row               Interface that changed, or NULL on the initial callback.
173  * @param[in]  notificationType  Type of change that occurred.
174  */
175 static void CALLBACK IpAddressChangeCallback(void *context,
176                                              MIB_UNICASTIPADDRESS_ROW *row,
177                                              MIB_NOTIFICATION_TYPE notificationType)
178 {
179     OC_UNUSED(notificationType);
180     OC_UNUSED(row);
181     OC_UNUSED(context);
182
183     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
184
185     // Fetch new network address info.
186     u_arraylist_t *newList = GetInterfaceInformation(0);
187     size_t newLen = u_arraylist_length(newList);
188
189     u_arraylist_t *oldList = g_CAIPNetworkMonitorAddressList;
190     size_t oldLen = u_arraylist_length(oldList);
191
192     if (caglobals.ip.addressChangeEvent)
193     {
194         // Check whether any addresses went away.
195         for (size_t i = 0; i < oldLen; i++)
196         {
197             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(oldList, i);
198             if (!CACmpNetworkList(ifitem->index, ifitem->family, ifitem->addr, newList))
199             {
200                 g_CAIPNetworkMonitorSomeAddressWentAway = true;
201                 break;
202             }
203         }
204
205         // Check whether any new addresses are available.
206         for (size_t i = 0; i < newLen; i++)
207         {
208             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(newList, i);
209             if (!CACmpNetworkList(ifitem->index, ifitem->family, ifitem->addr, oldList))
210             {
211                 // Create a new CAInterface_t to add to the queue to indicate to the higher
212                 // layer.  We cannot simply invoke the callback here currently, since the
213                 // higher layer is not thread-safe.
214                 CAInterface_t *dup = AllocateCAInterface(ifitem->index, ifitem->name,
215                                                          ifitem->family, ifitem->addr,
216                                                          ifitem->flags);
217                 CANewAddress_t *change = (CANewAddress_t *)OICCalloc(1, sizeof(*change));
218                 if (change)
219                 {
220                     change->ipAddressInfo = dup;
221                     DL_APPEND(g_CAIPNetworkMonitorNewAddressQueue, change);
222                 }
223                 else
224                 {
225                     OIC_LOG(WARNING, TAG, "Couldn't allocate memory for CANewAddress_t");
226                 }
227             }
228         }
229
230         // If the new address queue is not empty, signal the transport server that it needs
231         // to call CAFindInterfaceChange().  We don't need to set the event if an address
232         // went away, since the higher layer just uses the event to ask for new addresses
233         // in order to join the multicast group on the associated interface and address family.
234         if (g_CAIPNetworkMonitorNewAddressQueue)
235         {
236             // Setting the event should always succeed, since the handle should always be
237             // valid when this code is reached.
238             OC_VERIFY(WSASetEvent(caglobals.ip.addressChangeEvent));
239         }
240     }
241
242     // Replace old cached info.
243     g_CAIPNetworkMonitorAddressList = newList;
244     u_arraylist_destroy(oldList);
245
246     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
247 }
248
249 #ifdef USE_SOCKET_ADDRESS_CHANGE_EVENT
250 static HANDLE g_CAIPNetworkMonitorShutdownEvent = NULL;
251
252 void UnregisterForIpAddressChange()
253 {
254     if (g_CAIPNetworkMonitorShutdownEvent != NULL)
255     {
256         // Cancel the worker thread.
257         OC_VERIFY(SetEvent(g_CAIPNetworkMonitorShutdownEvent));
258         OC_VERIFY(WaitForSingleObject(g_CAIPNetworkMonitorNotificationHandle,
259                                       INFINITE) == WAIT_OBJECT_0);
260         OC_VERIFY(CloseHandle(g_CAIPNetworkMonitorShutdownEvent));
261         g_CAIPNetworkMonitorShutdownEvent = NULL;
262     }
263     if (g_CAIPNetworkMonitorNotificationHandle != NULL)
264     {
265         OC_VERIFY(CloseHandle(g_CAIPNetworkMonitorNotificationHandle));
266         g_CAIPNetworkMonitorNotificationHandle = NULL;
267     }
268 }
269
270 DWORD WINAPI IpNetworkMonitorWorker(PVOID context)
271 {
272     OVERLAPPED overlapped = {0};
273
274     WORD wVersionRequested = MAKEWORD(2, 2);
275     WSADATA wsaData = {.wVersion = 0};
276     int err = WSAStartup(wVersionRequested, &wsaData);
277     if (err != NO_ERROR)
278     {
279         return err;
280     }
281
282     SOCKET nwmSocket = WSASocketW(
283         AF_INET6,
284         SOCK_DGRAM,
285         0, // Default proto.
286         NULL, // No other protocol info.
287         0, // Ignore group.
288         WSA_FLAG_OVERLAPPED);
289     if (INVALID_SOCKET == nwmSocket)
290     {
291         err = WSAGetLastError();
292         goto done;
293     }
294
295     // Put socket into dual IPv4/IPv6 mode.
296     BOOL ipv6Only = FALSE;
297     if (SOCKET_ERROR == setsockopt(nwmSocket,
298                                    IPPROTO_IPV6,
299                                    IPV6_V6ONLY,
300                                    (char*)&ipv6Only,
301                                    sizeof(ipv6Only)))
302     {
303         err = WSAGetLastError();
304         goto done;
305     }
306
307     overlapped.hEvent = CreateEvent(
308         NULL, // No security descriptor.
309         TRUE, // Manual reset event.
310         FALSE, // Start not signaled.
311         NULL); // No name.
312     if (NULL == overlapped.hEvent)
313     {
314         err = GetLastError();
315         goto done;
316     }
317
318     WSAEVENT eventList[2] = { overlapped.hEvent,
319                               g_CAIPNetworkMonitorShutdownEvent,
320                             };
321     DWORD bytesReturned = 0;
322     for (;;)
323     {
324         if (SOCKET_ERROR == WSAIoctl(nwmSocket,
325                                      SIO_ADDRESS_LIST_CHANGE,
326                                      NULL, // No input buffer.
327                                      0,
328                                      NULL, // No outupt buffer.
329                                      0,
330                                      &bytesReturned,
331                                      &overlapped,
332                                      NULL)) // No completion routine.
333         {
334             err = WSAGetLastError();
335             if (err != ERROR_IO_PENDING)
336             {
337                 break;
338             }
339             else
340             {
341                 // Wait for an address change or a request to cancel the thread.
342                 DWORD waitStatus = WSAWaitForMultipleEvents(_countof(eventList),
343                                                             eventList,
344                                                             FALSE, // Wait for any one to fire.
345                                                             WSA_INFINITE,
346                                                             FALSE); // No I/O completion routines.
347
348                 if (waitStatus != WSA_WAIT_EVENT_0)
349                 {
350                     // The cancel event was signaled.  There is no need to call CancelIo
351                     // here, because we will close the socket handle below, causing any
352                     // pending I/O to be canceled then.
353                     assert(waitStatus == WSA_WAIT_EVENT_0 + 1);
354                     break;
355                 }
356
357                 OC_VERIFY(WSAResetEvent(overlapped.hEvent));
358             }
359         }
360
361         // We have a change to process.  The address change callback ignores
362         // the parameters, so we just pass default values.
363         IpAddressChangeCallback(context, NULL, MibInitialNotification);
364     }
365
366 done:
367     if (nwmSocket != INVALID_SOCKET)
368     {
369         closesocket(nwmSocket);
370         nwmSocket = INVALID_SOCKET;
371     }
372     if (overlapped.hEvent != NULL)
373     {
374         OC_VERIFY(CloseHandle(overlapped.hEvent));
375         overlapped.hEvent = NULL;
376     }
377     WSACleanup();
378     return err;
379 }
380
381 BOOL RegisterForIpAddressChange()
382 {
383     assert(g_CAIPNetworkMonitorNotificationHandle == NULL);
384
385     g_CAIPNetworkMonitorShutdownEvent = CreateEvent(
386         NULL, // No security descriptor.
387         TRUE, // Manual reset event.
388         FALSE, // Start not signaled.
389         NULL); // No name.
390     if (g_CAIPNetworkMonitorShutdownEvent == NULL)
391     {
392         return false;
393     }
394
395     g_CAIPNetworkMonitorNotificationHandle = CreateThread(
396         NULL, // Default security attributes.
397         0, // Default stack size.
398         IpNetworkMonitorWorker,
399         NULL, // No context.
400         0, // Run immediately.
401         NULL); // We don't need the thread id.
402
403     if (g_CAIPNetworkMonitorNotificationHandle == NULL)
404     {
405         OC_VERIFY(CloseHandle(g_CAIPNetworkMonitorShutdownEvent));
406         g_CAIPNetworkMonitorShutdownEvent = NULL;
407         return false;
408     }
409
410     // Signal the callback to query the initial state.  The address change callback ignores
411     // the parameters, so we just pass default values.
412     IpAddressChangeCallback(NULL, NULL, MibInitialNotification);
413
414     return true;
415 }
416 #endif
417
418 /**
419  * Start network monitor.
420  *
421  * @param[in]  callback     Callback to be notified when IP/TCP adapter connection state changes.
422  * @param[in]  adapter      Transport adapter.
423  * @return ::CA_STATUS_OK or an appropriate error code.
424  */
425 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
426                                    CATransportAdapter_t adapter)
427 {
428     if (g_CAIPNetworkMonitorNotificationHandle != NULL)
429     {
430         // The monitor has already been started. This can happen when using both the
431         // IP and TCP transport adapters.
432         return CA_STATUS_OK;
433     }
434
435     CAResult_t res = CAIPInitializeNetworkMonitorList();
436     if (res != CA_STATUS_OK)
437     {
438         return res;
439     }
440
441     res = CAIPSetNetworkMonitorCallback(callback, adapter);
442     if (res != CA_STATUS_OK)
443     {
444         CAIPDestroyNetworkMonitorList();
445         return res;
446     }
447
448 #ifdef USE_SOCKET_ADDRESS_CHANGE_EVENT
449     if (!RegisterForIpAddressChange())
450     {
451         CAIPDestroyNetworkMonitorList();
452         CAIPUnSetNetworkMonitorCallback(adapter);
453         return CA_STATUS_FAILED;
454     }
455 #else
456     int err = NotifyUnicastIpAddressChange(AF_UNSPEC, IpAddressChangeCallback, NULL,
457                                            true,
458                                            &g_CAIPNetworkMonitorNotificationHandle);
459     if (err != NO_ERROR)
460     {
461         CAIPDestroyNetworkMonitorList();
462         CAIPUnSetNetworkMonitorCallback(adapter);
463         return CA_STATUS_FAILED;
464     }
465 #endif
466     return CA_STATUS_OK;
467 }
468
469 /**
470  * Stops network monitor.
471  *
472  * @param[in]  adapter      Transport adapter.
473  * @return ::CA_STATUS_OK or an appropriate error code.
474  */
475 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
476 {
477     if (g_CAIPNetworkMonitorNotificationHandle != NULL)
478     {
479 #ifdef USE_SOCKET_ADDRESS_CHANGE_EVENT
480         UnregisterForIpAddressChange();
481 #else
482         int err = CancelMibChangeNotify2(g_CAIPNetworkMonitorNotificationHandle);
483         assert(err == NO_ERROR);
484         g_CAIPNetworkMonitorNotificationHandle = NULL;
485 #endif
486     }
487
488     CAIPDestroyNetworkMonitorList();
489     return CAIPUnSetNetworkMonitorCallback(adapter);
490 }
491
492 /**
493  * Let the network monitor update the polling interval.
494  * @param[in] interval Current polling interval, in seconds
495  *
496  * @return  desired polling interval
497  */
498 int CAGetPollingInterval(int interval)
499 {
500     // Don't change the polling interval.
501     return interval;
502 }
503
504 /**
505  * Pass the changed network status through the stored callback.
506  * Note that the current API doesn't allow us to specify which address changed,
507  * the caller has to look at the return from CAFindInterfaceChange() to learn about
508  * each new address, and look through CAIPGetInterfaceInformation() to see what's
509  * missing to detect any removed addresses.
510  *
511  * @param[in] status Network status to pass to the callback.
512  */
513 static void CAIPPassNetworkChangesToTransportAdapter(CANetworkStatus_t status)
514 {
515     CAIPCBData_t *cbitem = NULL;
516     LL_FOREACH(g_CAIPNetworkMonitorAdapterCallbackList, cbitem)
517     {
518         if (cbitem && cbitem->adapter)
519         {
520             cbitem->callback(cbitem->adapter, status);
521         }
522     }
523 }
524
525 /**
526  * Set callback for receiving local IP/TCP adapter connection status.
527  *
528  * @param[in]  callback     Callback to be notified when IP/TCP adapter connection state changes.
529  * @param[in]  adapter      Transport adapter.
530  * @return ::CA_STATUS_OK or an appropriate error code.
531  */
532 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
533                                          CATransportAdapter_t adapter)
534 {
535     if (!callback)
536     {
537         OIC_LOG(ERROR, TAG, "callback is null");
538         return CA_STATUS_INVALID_PARAM;
539     }
540
541     CAIPCBData_t *cbitem = NULL;
542     LL_FOREACH(g_CAIPNetworkMonitorAdapterCallbackList, cbitem)
543     {
544         if ((adapter == cbitem->adapter) && (callback == cbitem->callback))
545         {
546             OIC_LOG(DEBUG, TAG, "this callback is already added");
547             return CA_STATUS_OK;
548         }
549     }
550
551     cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
552     if (!cbitem)
553     {
554         OIC_LOG(ERROR, TAG, "Malloc failed");
555         return CA_STATUS_FAILED;
556     }
557
558     cbitem->adapter = adapter;
559     cbitem->callback = callback;
560     LL_APPEND(g_CAIPNetworkMonitorAdapterCallbackList, cbitem);
561
562     return CA_STATUS_OK;
563 }
564
565 /**
566  * Unset callback for receiving local IP/TCP adapter connection status.
567  *
568  * @param[in]  adapter      Transport adapter.
569  * @return CA_STATUS_OK.
570  */
571 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
572 {
573     CAIPCBData_t *cbitem = NULL;
574     CAIPCBData_t *tmpCbitem = NULL;
575     LL_FOREACH_SAFE(g_CAIPNetworkMonitorAdapterCallbackList, cbitem, tmpCbitem)
576     {
577         if (cbitem && adapter == cbitem->adapter)
578         {
579             OIC_LOG(DEBUG, TAG, "remove specific callback");
580             LL_DELETE(g_CAIPNetworkMonitorAdapterCallbackList, cbitem);
581             OICFree(cbitem);
582             return CA_STATUS_OK;
583         }
584     }
585     return CA_STATUS_OK;
586 }
587
588 /**
589  * Allocate a new CAInterface_t entry for a given IP address.
590  */
591 static CAInterface_t *AllocateCAInterface(int index, const char *name, uint16_t family,
592                                           const char *addr, int flags)
593 {
594     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(*ifitem));
595     if (!ifitem)
596     {
597         OIC_LOG(ERROR, TAG, "Allocating memory for a CAInterface_t failed");
598         return NULL;
599     }
600
601     OICStrcpy(ifitem->name, sizeof(ifitem->name), name);
602     ifitem->index = index;
603     ifitem->family = family;
604     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
605     ifitem->flags = flags;
606
607     return ifitem;
608 }
609
610 /**
611  * Find a new IP address.
612  * The caller is responsible for freeing the pointer returned via u_arraylist_destroy().
613  *
614  * @return  Dynamically allocated IP address list, or NULL if no change.
615  */
616 u_arraylist_t  *CAFindInterfaceChange()
617 {
618     u_arraylist_t *iflist = u_arraylist_create();
619     if (!iflist)
620     {
621         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
622         return NULL;
623     }
624
625     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
626
627     bool someAddressWentAway = g_CAIPNetworkMonitorSomeAddressWentAway;
628     g_CAIPNetworkMonitorSomeAddressWentAway = false;
629
630     bool newAddress = false;
631
632     // Pop whole new address in list.
633     while (g_CAIPNetworkMonitorNewAddressQueue)
634     {
635         CANewAddress_t *change = g_CAIPNetworkMonitorNewAddressQueue;
636
637         bool result = u_arraylist_add(iflist, change->ipAddressInfo);
638         if (!result)
639         {
640             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
641             break;
642         }
643         else
644         {
645             DL_DELETE(g_CAIPNetworkMonitorNewAddressQueue, change);
646             OICFree(change);
647             newAddress = true;
648         }
649     }
650
651     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
652
653     if (someAddressWentAway)
654     {
655         CAIPPassNetworkChangesToTransportAdapter(CA_INTERFACE_DOWN);
656     }
657     if (newAddress)
658     {
659         CAIPPassNetworkChangesToTransportAdapter(CA_INTERFACE_UP);
660     }
661
662     return iflist;
663 }
664
665 static bool IsValidNetworkAdapter(PIP_ADAPTER_ADDRESSES pAdapterAddr, int desiredIndex)
666 {
667     bool valid = true;
668
669     // If desiredIndex is non-zero, then only retrieve adapter corresponding to desiredIndex.
670     // If desiredIndex is zero, then retrieve all adapters.
671     if (desiredIndex && ((int)pAdapterAddr->IfIndex != desiredIndex))
672     {
673         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i not interesting.", pAdapterAddr->IfIndex);
674         valid = false;
675     }
676
677     if (pAdapterAddr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
678     {
679         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i is loopback.", pAdapterAddr->IfIndex);
680         valid = false;
681     }
682
683     if ((pAdapterAddr->OperStatus & IfOperStatusUp) == 0)
684     {
685         OIC_LOG_V(DEBUG, TAG, "\t\tInterface %i is not operational.", pAdapterAddr->IfIndex);
686         valid = false;
687     }
688     return valid;
689 }
690
691 /*
692  * Allocate a new CAInterface_t structure and add it to a given list.  A new entry is added
693  * for each address.
694  *
695  * @param[in,out] iflist  List to add to.
696  * @param[in]     name    Interface name.
697  * @param[in]     index   Interface index.
698  * @param[in]     family  Address family.
699  * @param[in]     addr    Address.
700  * @return Pointer to entry added, or NULL on failure.
701  */
702 CAInterface_t *AddCAInterface(u_arraylist_t *iflist, const char *name, uint32_t index,
703                               uint16_t family, const char *addr)
704 {
705     CAInterface_t *ifitem = AllocateCAInterface(index, name, family, addr, IFF_UP);
706     if (ifitem == NULL)
707     {
708         return NULL;
709     }
710
711     if (!u_arraylist_add(iflist, ifitem))
712     {
713         OIC_LOG(ERROR, TAG, "u_arraylist_add failed");
714         OICFree(ifitem);
715         return NULL;
716     }
717
718     return ifitem;
719 }
720
721 bool IsValidAddress(PIP_ADAPTER_UNICAST_ADDRESS pAddress)
722 {
723     if (pAddress->Address.lpSockaddr->sa_family != AF_INET6)
724     {
725         // All IPv4 addresses are valid.
726         return true;
727     }
728
729     PSOCKADDR_IN6 sockAddr = (PSOCKADDR_IN6)pAddress->Address.lpSockaddr;
730     if (Ipv6UnicastAddressScope(sockAddr->sin6_addr.s6_addr) == ScopeLevelLink)
731     {
732         // IPv6 link local addresses are valid.
733         return true;
734     }
735
736     // Other IPv6 addresses are valid if they are DNS eligible.
737     // That is, ignore temporary addresses.
738     return ((pAddress->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE) != 0);
739 }
740
741 bool AddAddresses(PIP_ADAPTER_ADDRESSES pAdapterAddr, u_arraylist_t *iflist, int desiredIndex)
742 {
743     bool bSucceeded = true;
744     for (PIP_ADAPTER_ADDRESSES pCurAdapterAddr = pAdapterAddr;
745          pCurAdapterAddr != NULL; pCurAdapterAddr = pCurAdapterAddr->Next)
746     {
747         OIC_LOG_V(DEBUG, TAG, "\tInterface Index: %u", pCurAdapterAddr->IfIndex);
748         OIC_LOG_V(DEBUG, TAG, "\tInterface  name: %s", pCurAdapterAddr->AdapterName);
749
750         if (!IsValidNetworkAdapter(pCurAdapterAddr, desiredIndex))
751         {
752             continue;
753         }
754
755         for (PIP_ADAPTER_UNICAST_ADDRESS pAddress = pCurAdapterAddr->FirstUnicastAddress;
756              pAddress != NULL;
757              pAddress = pAddress->Next)
758         {
759             if (!IsValidAddress(pAddress))
760             {
761                 continue;
762             }
763
764             char addr[INET6_ADDRSTRLEN];
765             if (!inet_ntop(pAddress->Address.lpSockaddr->sa_family,
766                            INETADDR_ADDRESS(pAddress->Address.lpSockaddr),
767                            addr,
768                            sizeof(addr)))
769             {
770                 continue;
771             }
772
773             CAInterface_t *ipAddressInfo = AddCAInterface(iflist, pCurAdapterAddr->AdapterName,
774                                                           pCurAdapterAddr->IfIndex,
775                                                           pAddress->Address.lpSockaddr->sa_family,
776                                                           addr);
777             if (!ipAddressInfo)
778             {
779                 OIC_LOG_V(ERROR, TAG, "\tAdding address on interface %i failed",
780                           pCurAdapterAddr->IfIndex);
781                 bSucceeded = false;
782                 break;
783             }
784
785             OIC_LOG_V(DEBUG, TAG, "\t\tAdded address %s", ipAddressInfo->addr);
786         }
787     }
788     return bSucceeded;
789 }
790
791 /*
792  * Get the set of IP_ADAPTER_ADDRESSES structures.  The caller is responsible for
793  * freeng the set using OICFree on the pointer returned.
794  *
795  * @return List of network adapters.
796  */
797 PIP_ADAPTER_ADDRESSES GetAdapters()
798 {
799     ULONG ulOutBufLen = 0;
800     PIP_ADAPTER_ADDRESSES pAdapterAddr = NULL;
801
802     // We don't need most of the default information, so optimize this call by not
803     // asking for them.
804     ULONG flags = GAA_FLAG_SKIP_ANYCAST |
805                   GAA_FLAG_SKIP_MULTICAST |
806                   GAA_FLAG_SKIP_DNS_SERVER |
807                   GAA_FLAG_SKIP_FRIENDLY_NAME;
808
809     // Call up to 3 times: once to get the size, once to get the data, and once more
810     // just in case there was an increase in length in between the first two. If the
811     // length is still increasing due to more addresses being added, even this may fail
812     // and we'll have to wait for the next IP address change notification.
813     for (int i = 0; i < 3; i++)
814     {
815         ULONG ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapterAddr, &ulOutBufLen);
816         if (ERROR_BUFFER_OVERFLOW == ret)
817         {
818             // Redo with updated length.
819             if (pAdapterAddr != NULL)
820             {
821                 OICFree(pAdapterAddr);
822             }
823             pAdapterAddr = (PIP_ADAPTER_ADDRESSES) OICMalloc(ulOutBufLen);
824             if (pAdapterAddr == NULL) {
825                 OIC_LOG(ERROR, TAG, "Allocating memory for GetAdaptersAddresses() failed");
826                 break;
827             }
828             continue;
829         }
830         if (NO_ERROR != ret)
831         {
832             OIC_LOG(ERROR, TAG, "GetAdaptersAddresses() failed");
833             break;
834         }
835
836         // Succeeded getting adapters
837         return pAdapterAddr;
838     }
839
840     if (pAdapterAddr != NULL)
841     {
842         OICFree(pAdapterAddr);
843     }
844     return NULL;
845 }
846
847 /**
848  * Get the list of CAInterface_t items.  Currently only 0 is passed as the desiredIndex by any
849  * caller.
850  *
851  * @param[in]  desiredIndex      Network interface index, or 0 for all.
852  * @return  List of CAInterface_t items.
853  */
854 static u_arraylist_t *GetInterfaceInformation(int desiredIndex)
855 {
856     if (desiredIndex < 0)
857     {
858         OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
859         return NULL;
860     }
861
862     u_arraylist_t *iflist = u_arraylist_create();
863     if (!iflist)
864     {
865         OIC_LOG(ERROR, TAG, "Failed to create iflist");
866         return NULL;
867     }
868
869     PIP_ADAPTER_ADDRESSES pAdapterAddr = GetAdapters();
870     if (!pAdapterAddr)
871     {
872         OIC_LOG(ERROR, TAG, "Enumerating Adapters failed");
873         u_arraylist_destroy(iflist);
874         return NULL;
875     }
876
877     // Cycle through network adapters.
878     // Add valid network addresses to the address list.
879     bool ret = AddAddresses(pAdapterAddr, iflist, desiredIndex);
880     if (false == ret)
881     {
882         OIC_LOG(ERROR, TAG, "AddAddresses() failed");
883         u_arraylist_destroy(iflist);
884         iflist = NULL;
885     }
886
887     // Finished with network adapter list.
888     OICFree(pAdapterAddr);
889
890     return iflist;
891 }
892
893 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
894 {
895     OC_UNUSED(desiredIndex);
896
897     u_arraylist_t *iflist = u_arraylist_create();
898     if (!iflist)
899     {
900         OIC_LOG(ERROR, TAG, "Failed to create iflist");
901         return NULL;
902     }
903
904     // Avoid extra kernel calls by just duplicating what's in our cache.
905     oc_mutex_lock(g_CAIPNetworkMonitorMutex);
906
907     size_t list_length = u_arraylist_length(g_CAIPNetworkMonitorAddressList);
908     for (size_t list_index = 0; list_index < list_length; list_index++)
909     {
910         CAInterface_t *currItem = (CAInterface_t *)u_arraylist_get(g_CAIPNetworkMonitorAddressList,
911                                                                    list_index);
912         if (!AddCAInterface(iflist, currItem->name, currItem->index, currItem->family,
913                             currItem->addr))
914         {
915             OIC_LOG(ERROR, TAG, "AddCAInterface() failed");
916             u_arraylist_destroy(iflist);
917             iflist = NULL;
918             break;
919         }
920     }
921
922     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
923
924     return iflist;
925 }
926
927 CAResult_t CAGetLinkLocalZoneIdInternal(uint32_t ifindex, char **zoneId)
928 {
929     if (!zoneId || (*zoneId != NULL))
930     {
931         return CA_STATUS_INVALID_PARAM;
932     }
933
934     PIP_ADAPTER_ADDRESSES pAdapters = GetAdapters();
935
936     if (!pAdapters)
937     {
938         OICFree(pAdapters);
939         return CA_STATUS_FAILED;
940     }
941
942     PIP_ADAPTER_ADDRESSES pCurrAdapter = NULL;
943     pCurrAdapter = pAdapters;
944
945     while (pCurrAdapter)
946     {
947         if (ifindex == pCurrAdapter->IfIndex)
948         {
949             OIC_LOG_V(DEBUG, TAG, "Given ifindex is %d parsed zoneId is %d",
950                       ifindex, pCurrAdapter->ZoneIndices[ScopeLevelLink]);
951             *zoneId = (char *)OICCalloc(IF_NAMESIZE, sizeof(char));
952             _ultoa(pCurrAdapter->ZoneIndices[ScopeLevelLink], *zoneId, 10);
953             break;
954         }
955         pCurrAdapter = pCurrAdapter->Next;
956     }
957
958     OICFree(pAdapters);
959
960     if (!*zoneId)
961     {
962         return CA_STATUS_FAILED;
963     }
964
965     return CA_STATUS_OK;
966 }