2 * Copyright (c) 2011-2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
29 #include <sys/socket.h>
30 #include <dispatch/dispatch.h>
31 #ifdef VERBOSE_ACTIVITY_LOGGING
32 #include <os/activity.h>
33 #endif // VERBOSE_ACTIVITY_LOGGING
37 #include "libSystemConfiguration_client.h"
38 #include "network_information.h"
39 #include "network_state_information_priv.h"
41 #if !TARGET_OS_SIMULATOR
42 #include "network_config_agent_info_priv.h"
43 #include "configAgentDefines.h"
44 #endif // !TARGET_OS_SIMULATOR
46 static nwi_state_t G_nwi_state
= NULL
;
47 static pthread_mutex_t nwi_store_lock
= PTHREAD_MUTEX_INITIALIZER
;
48 static boolean_t nwi_store_token_valid
= FALSE
;
50 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
51 static int nwi_store_token
;
53 static boolean_t nwi_store_force_refresh
= FALSE
;
54 static const char * client_proc_name
= NULL
;
57 #pragma mark Network information [nwi] client support
60 // Note: protected by __nwi_client_queue()
61 static int nwi_active
= 0;
62 static libSC_info_client_t
*nwi_client
= NULL
;
65 #ifdef VERBOSE_ACTIVITY_LOGGING
67 __nwi_client_activity()
69 static os_activity_t activity
;
70 static dispatch_once_t once
;
72 dispatch_once(&once
, ^{
73 activity
= os_activity_create("accessing network information",
75 OS_ACTIVITY_FLAG_DEFAULT
);
80 #endif // VERBOSE_ACTIVITY_LOGGING
83 static dispatch_queue_t
86 static dispatch_once_t once
;
87 static dispatch_queue_t q
;
89 dispatch_once(&once
, ^{
90 q
= dispatch_queue_create(NWI_SERVICE_NAME
, NULL
);
98 _nwi_state_initialize(void)
100 const char *nwi_key
= nwi_state_get_notify_key();
101 uint32_t status
= notify_register_check(nwi_key
,
104 if (status
!= NOTIFY_STATUS_OK
) {
105 fprintf(stderr
, "nwi_state: registration failed (%u)\n", status
);
108 nwi_store_token_valid
= TRUE
;
113 #pragma mark Network information [nwi] APIs
117 * Function: nwi_state_get_notify_key
119 * Returns the BSD notify key to use to monitor when the state changes.
122 * The nwi_state_copy API uses this notify key to monitor when the state
123 * changes, so each invocation of nwi_state_copy returns the current
127 nwi_state_get_notify_key()
129 return "com.apple.system.SystemConfiguration.nwi";
132 #define ATOMIC_CMPXCHG(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
133 #define ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++);
134 #define ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n);
137 _nwi_state_force_refresh()
139 ATOMIC_CMPXCHG(&nwi_store_force_refresh
, FALSE
, TRUE
);
143 nwi_state_retain(nwi_state_t state
)
145 ATOMIC_INC(&state
->ref
);
150 _nwi_client_release()
152 // release connection reference on 1-->0 transition
153 dispatch_sync(__nwi_client_queue(), ^{
154 if (--nwi_active
== 0) {
155 // if last reference, drop connection
156 libSC_info_client_release(nwi_client
);
165 dispatch_sync(__nwi_client_queue(), ^{
166 if ((nwi_active
++ == 0) || (nwi_client
== NULL
)) {
167 static dispatch_once_t once
;
168 static const char *service_name
= NWI_SERVICE_NAME
;
170 dispatch_once(&once
, ^{
174 // get [XPC] service name
175 name
= getenv(service_name
);
177 service_name
= strdup(name
);
182 client_proc_name
= getprogname();
186 libSC_info_client_create(__nwi_client_queue(), // dispatch queue
187 service_name
, // XPC service name
188 "Network information"); // service description
189 if (nwi_client
== NULL
) {
197 * Function: nwi_state_release
199 * Release the memory associated with the network state.
202 nwi_state_release(nwi_state_t state
)
204 if (ATOMIC_DEC(&state
->ref
) > 0) {
205 // if not last reference
209 _nwi_client_release();
212 nwi_state_free(state
);
218 _nwi_state_copy_data()
220 nwi_state_t nwi_state
= NULL
;
221 xpc_object_t reqdict
;
224 if (!libSC_info_available()) {
225 os_log(OS_LOG_DEFAULT
, "*** network information requested between fork() and exec()");
231 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
232 // if network information server not available
236 #ifdef VERBOSE_ACTIVITY_LOGGING
237 // scope NWI activity
238 os_activity_scope(__nwi_client_activity());
239 #endif // VERBOSE_ACTIVITY_LOGGING
242 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
245 if (client_proc_name
!= NULL
) {
246 xpc_dictionary_set_string(reqdict
, NWI_PROC_NAME
, client_proc_name
);
250 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_STATE_REQUEST_COPY
);
252 // send request to the DNS configuration server
253 reply
= libSC_send_message_with_reply_sync(nwi_client
, reqdict
);
254 xpc_release(reqdict
);
260 dataRef
= xpc_dictionary_get_data(reply
, NWI_CONFIGURATION
, &dataLen
);
261 if (dataRef
!= NULL
) {
262 nwi_state
= malloc(dataLen
);
263 bcopy((void *)dataRef
, nwi_state
, dataLen
);
264 if (nwi_state
->version
!= NWI_STATE_VERSION
) {
265 /* make sure the version matches */
266 nwi_state_free(nwi_state
);
280 #if !TARGET_OS_SIMULATOR
282 * Function: _nwi_config_agent_copy_data
284 * Copy the config agent data and the data length.
285 * Caller must free the buffer.
288 _nwi_config_agent_copy_data(const struct netagent
*agent
, uint64_t *length
)
290 const void *buffer
= NULL
;
291 xpc_object_t reqdict
;
294 if ((agent
== NULL
) || (length
== NULL
)) {
300 #ifdef VERBOSE_ACTIVITY_LOGGING
301 // scope NWI activity
302 os_activity_scope(__nwi_client_activity());
303 #endif // VERBOSE_ACTIVITY_LOGGING
305 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
307 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_CONFIG_AGENT_REQUEST_COPY
);
308 if (client_proc_name
!= NULL
) {
309 xpc_dictionary_set_string(reqdict
, NWI_PROC_NAME
, client_proc_name
);
312 xpc_dictionary_set_uuid(reqdict
, kConfigAgentAgentUUID
, agent
->netagent_uuid
);
313 xpc_dictionary_set_string(reqdict
, kConfigAgentType
, agent
->netagent_type
);
315 // send request to the NWI configuration server
316 reply
= libSC_send_message_with_reply_sync(nwi_client
, reqdict
);
317 xpc_release(reqdict
);
320 const void *xpc_buffer
= NULL
;
321 unsigned long len
= 0;
323 xpc_buffer
= xpc_dictionary_get_data(reply
, kConfigAgentAgentData
, &len
);
324 if ((xpc_buffer
!= NULL
) && (len
> 0)) {
325 buffer
= malloc(len
);
327 bcopy((void *)xpc_buffer
, (void *)buffer
, len
);
332 _nwi_client_release();
336 #endif // !TARGET_OS_SIMULATOR
339 * Function: nwi_state_copy
341 * Returns the current network state information.
342 * Release after use by calling nwi_state_release().
347 boolean_t force_refresh
;
348 nwi_state_t nwi_state
= NULL
;
349 nwi_state_t old_state
= NULL
;
351 pthread_once(&initialized
, _nwi_state_initialize
);
352 pthread_mutex_lock(&nwi_store_lock
);
354 force_refresh
= ATOMIC_CMPXCHG(&nwi_store_force_refresh
, TRUE
, FALSE
);
356 if (G_nwi_state
!= NULL
) {
360 if (!nwi_store_token_valid
) {
361 /* have to throw cached copy away every time */
365 status
= notify_check(nwi_store_token
, &check
);
366 if (status
!= NOTIFY_STATUS_OK
) {
367 fprintf(stderr
, "nwi notify_check: failed with %u\n",
369 /* assume that it changed, throw cached copy away */
373 if (check
!= 0 || force_refresh
) {
374 /* new need snapshot */
375 old_state
= G_nwi_state
;
379 /* Let's populate the cache if it's empty */
380 if (G_nwi_state
== NULL
) {
381 G_nwi_state
= _nwi_state_copy_data();
382 if (G_nwi_state
!= NULL
) {
383 /* one reference for G_nwi_state */
384 nwi_state_retain(G_nwi_state
);
387 if (G_nwi_state
!= NULL
) {
388 /* another reference for this caller */
389 nwi_state_retain(G_nwi_state
);
391 nwi_state
= G_nwi_state
;
392 pthread_mutex_unlock(&nwi_store_lock
);
394 if (old_state
!= NULL
) {
395 /* get rid of G_nwi_state reference */
396 nwi_state_release(old_state
);
402 * Function: _nwi_state_ack
404 * Acknowledge receipt and any changes associated with the [new or
405 * updated] network state.
408 _nwi_state_ack(nwi_state_t state
, const char *bundle_id
)
410 #pragma unused(bundle_id)
411 xpc_object_t reqdict
;
417 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
418 // if network information server not available
422 dispatch_sync(__nwi_client_queue(), ^{
423 nwi_active
++; // keep connection active (for the life of the process)
427 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
430 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_STATE_REQUEST_ACKNOWLEDGE
);
433 xpc_dictionary_set_uint64(reqdict
, NWI_GENERATION
, state
->generation_count
);
435 // send acknowledgement to the DNS configuration server
436 xpc_connection_send_message(nwi_client
->connection
, reqdict
);
438 xpc_release(reqdict
);
443 * Function: nwi_state_get_generation
445 * Returns the generation (mach_time) of the nwi_state data.
446 * Every time the data is updated due to changes
447 * in the network, this value will change.
450 nwi_state_get_generation(nwi_state_t state
)
452 return (state
->generation_count
);
456 * Function: nwi_ifstate_get_generation
458 * Returns the generation (mach_time) of the nwi_ifstate data.
461 nwi_ifstate_get_generation(nwi_ifstate_t ifstate
)
463 return (ifstate
->if_generation_count
);
467 * Function: nwi_ifstate_get_ifname
469 * Return the interface name of the specified ifstate.
472 nwi_ifstate_get_ifname(nwi_ifstate_t ifstate
)
474 return ((ifstate
!= NULL
) ? ifstate
->ifname
: NULL
);
478 flags_from_af(int af
)
480 return ((af
== AF_INET
)
481 ? NWI_IFSTATE_FLAGS_HAS_IPV4
482 : NWI_IFSTATE_FLAGS_HAS_IPV6
);
485 * Function: nwi_ifstate_get_flags
487 * Return the flags for the given ifstate (see above for bit definitions).
490 nwi_ifstate_get_flags(nwi_ifstate_t ifstate
)
492 nwi_ifstate_t alias
= NULL
;
493 nwi_ifstate_flags flags
= 0ULL;
495 if (ifstate
->af_alias_offset
!= 0) {
496 alias
= ifstate
+ ifstate
->af_alias_offset
;
498 flags
|= flags_from_af(ifstate
->af
);
499 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
500 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
504 flags
|= flags_from_af(alias
->af
);
505 if ((alias
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
506 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
513 * Function: nwi_state_get_first_ifstate
515 * Returns the first and highest priority interface that has connectivity
516 * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6.
517 * The connectivity provided is for general networking. To get information
518 * about an interface that isn't available for general networking, use
519 * nwi_state_get_ifstate().
521 * Use nwi_ifstate_get_next() to get the next, lower priority interface
524 * Returns NULL if no connectivity for the specified address family is
528 nwi_state_get_first_ifstate(nwi_state_t state
, int af
)
530 nwi_ifstate_t ifstate
;
536 ifstate
= nwi_state_get_ifstate_with_index(state
, af
, 0);
537 if (ifstate
== NULL
) {
540 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
550 * Function: nwi_state_get_ifstate
552 * Return information for the specified interface 'ifname'.
554 * This API directly returns the ifstate for the specified interface.
555 * This is the only way to access information about an interface that isn't
556 * available for general networking.
558 * Returns NULL if no information is available for that interface.
561 nwi_state_get_ifstate(nwi_state_t state
, const char * ifname
)
563 nwi_ifstate_t ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET
, ifname
);
564 if (ifstate
== NULL
) {
565 ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET6
, ifname
);
572 * Function: nwi_ifstate_get_next
574 * Returns the next, lower priority nwi_ifstate_t after the specified
575 * 'ifstate' for the protocol family 'af'.
577 * Returns NULL when the end of the list is reached, or we reach an
578 * item that is not in the list.
581 nwi_ifstate_get_next(nwi_ifstate_t ifstate
, int af
)
583 ifstate
= nwi_ifstate_get_alias(ifstate
, af
);
586 & (NWI_IFSTATE_FLAGS_NOT_IN_LIST
587 | NWI_IFSTATE_FLAGS_LAST_ITEM
))
592 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0) {
599 * Function: nwi_ifstate_compare_rank
601 * Compare the relative rank of two nwi_ifstate_t objects.
603 * The "rank" indicates the importance of the underlying interface.
606 * 0 if ifstate1 and ifstate2 are ranked equally
607 * -1 if ifstate1 is ranked ahead of ifstate2
608 * 1 if ifstate2 is ranked ahead of ifstate1
611 nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1
, nwi_ifstate_t ifstate2
)
613 return RankCompare(ifstate1
->rank
, ifstate2
->rank
);
617 * nwi_state_get_reachability_flags
619 * returns the global reachability flags for a given address family.
620 * If no address family is passed in, it returns the global reachability
621 * flags for either families.
623 * The reachability flags returned follow the definition of
624 * SCNetworkReachabilityFlags.
626 * If the flags are zero (i.e. do not contain kSCNetworkReachabilityFlagsReachable), there is no connectivity.
628 * Otherwise, at least kSCNetworkReachabilityFlagsReachable is set:
630 * No other connection flags are set.
631 * Reachable and no ConnectionRequired
632 * If we have connectivity for the specified address family (and we'd
633 * be returning the reachability flags associated with the default route)
634 * Reachable and ConnectionRequired
635 * If we do not currently have an active/primary network but we may
636 * be able to establish connectivity.
637 * Reachable and OnDemand
638 * If we do not currently have an active/primary network but we may
639 * be able to establish connective on demand.
640 * Reachable and TransientConnection
641 * This connection is transient.
643 * This connection will be going over the cellular network.
646 nwi_state_get_reachability_flags(nwi_state_t nwi_state
, int af
)
648 if (nwi_state
== NULL
) {
651 if (af
== AF_INET
|| af
== AF_INET6
) {
652 nwi_ifstate_t ifstate
;
654 ifstate
= nwi_state_get_first_ifstate(nwi_state
, af
);
656 if (ifstate
!= NULL
) {
657 return ifstate
->reach_flags
;
660 return (af
== AF_INET
) ? nwi_state
->reach_flags_v4
: nwi_state
->reach_flags_v6
;
662 nwi_ifstate_t ifstate_v4
;
663 nwi_ifstate_t ifstate_v6
;
665 ifstate_v4
= nwi_state_get_first_ifstate(nwi_state
, AF_INET
);
666 ifstate_v6
= nwi_state_get_first_ifstate(nwi_state
, AF_INET6
);
668 if (ifstate_v4
!= NULL
) {
669 if (ifstate_v6
!= NULL
) {
670 if (nwi_ifstate_compare_rank(ifstate_v4
, ifstate_v6
) > 0) {
671 return ifstate_v6
->reach_flags
;
673 return ifstate_v4
->reach_flags
;
676 return ifstate_v4
->reach_flags
;
679 if (ifstate_v6
!= NULL
) {
680 return ifstate_v6
->reach_flags
;
684 if (nwi_state
->reach_flags_v4
!= 0) {
685 return nwi_state
->reach_flags_v4
;
687 // This is the case where both ifstate are NULL.
688 return nwi_state
->reach_flags_v6
;
693 * nwi_ifstate_get_vpn_server
695 * returns a sockaddr representation of the vpn server address.
696 * NULL if PPP/VPN/IPSec server address does not exist.
698 const struct sockaddr
*
699 nwi_ifstate_get_vpn_server(nwi_ifstate_t ifstate
)
701 const struct sockaddr
* vpn_server_addr
;
703 vpn_server_addr
= (const struct sockaddr
*)(void *)
704 &ifstate
->vpn_server_address
;
706 if (vpn_server_addr
->sa_family
== 0) {
709 return vpn_server_addr
;
713 * nwi_ifstate_get_reachability_flags
715 * returns the reachability flags for the interface given an address family.
716 * The flags returned are those determined outside of
717 * the routing table. [None, ConnectionRequired, OnDemand,
718 * Transient Connection, WWAN].
721 nwi_ifstate_get_reachability_flags(nwi_ifstate_t ifstate
)
723 return ifstate
->reach_flags
;
727 * nwi_ifstate_get_signature
729 * returns the signature and its length for an ifstate given an address family.
730 * If AF_UNSPEC is passed in, the signature for a given ifstate is returned.
732 * If the signature does not exist, NULL is returned.
735 nwi_ifstate_get_signature(nwi_ifstate_t ifstate
, int af
, int * length
)
737 nwi_ifstate_t i_state
= NULL
;
745 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
752 if (i_state
!= NULL
) {
753 if ((i_state
->flags
& NWI_IFSTATE_FLAGS_HAS_SIGNATURE
) != 0) {
754 *length
= sizeof(i_state
->signature
);
755 return (i_state
->signature
);
765 _nwi_ifstate_is_in_list(nwi_ifstate_t ifstate
, int af
)
767 nwi_ifstate_t i_state
;
769 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
770 if (i_state
== NULL
) {
774 if ((nwi_ifstate_get_flags(i_state
) & NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
783 * nwi_ifstate_get_dns_signature
785 * returns the signature and its length for given
786 * ifstate with a valid dns configuration.
788 * If the signature does not exist, NULL is returned.
792 nwi_ifstate_get_dns_signature(nwi_ifstate_t ifstate
, int * length
)
794 const uint8_t * signature
= NULL
;
795 const uint8_t * v4_signature
;
796 int v4_signature_len
;
797 const uint8_t * v6_signature
;
798 int v6_signature_len
;
802 if ((nwi_ifstate_get_flags(ifstate
) & NWI_IFSTATE_FLAGS_HAS_DNS
) == 0) {
806 v4_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET
, &v4_signature_len
);
807 v6_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET6
, &v6_signature_len
);
808 if (v4_signature
== NULL
&& v6_signature
== NULL
) {
812 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET
)) {
813 signature
= v4_signature
;
814 *length
= v4_signature_len
;
816 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET6
) != TRUE
&& v4_signature_len
> 0) {
817 /* v6 is ranked never, v4 is ranked never but has a valid signature */
818 signature
= v4_signature
;
819 *length
= v4_signature_len
;
821 /* v6 is not ranked never or v4 has no signature */
822 signature
= v6_signature
;
823 *length
= v6_signature_len
;
831 nwi_state_get_interface_names(nwi_state_t state
,
832 const char * names
[],
833 unsigned int names_count
)
836 nwi_ifindex_t
* scan
;
838 if (names
== NULL
|| names_count
== 0) {
839 return (state
->if_list_count
);
841 for (i
= 0, scan
= nwi_state_if_list(state
);
842 i
< state
->if_list_count
; i
++, scan
++) {
843 names
[i
] = state
->ifstate_list
[*scan
].ifname
;
845 return (state
->if_list_count
);
849 #pragma mark Network information [nwi] test code
854 #include <arpa/inet.h>
857 const struct sockaddr
* sa
;
858 const struct sockaddr_in
* sin
;
859 const struct sockaddr_in6
* sin6
;
863 my_sockaddr_ntop(const struct sockaddr
* sa
, char * buf
, int buf_len
)
866 const void * addr_ptr
= NULL
;
869 switch (sa
->sa_family
) {
871 addr_ptr
= &addr
.sin
->sin_addr
;
874 addr_ptr
= &addr
.sin6
->sin6_addr
;
880 if (addr_ptr
== NULL
) {
883 return (inet_ntop(addr
.sa
->sa_family
, addr_ptr
, buf
, buf_len
));
887 nwi_ifstate_print(nwi_ifstate_t ifstate
)
889 const char * addr_str
;
891 char addr_ntopbuf
[INET6_ADDRSTRLEN
];
892 const char * diff_str
;
893 char vpn_ntopbuf
[INET6_ADDRSTRLEN
];
894 const struct sockaddr
* vpn_addr
;
895 const char * vpn_addr_str
= NULL
;
897 address
= nwi_ifstate_get_address(ifstate
);
898 addr_str
= inet_ntop(ifstate
->af
, address
,
899 addr_ntopbuf
, sizeof(addr_ntopbuf
));
900 vpn_addr
= nwi_ifstate_get_vpn_server(ifstate
);
901 if (vpn_addr
!= NULL
) {
902 vpn_addr_str
= my_sockaddr_ntop(vpn_addr
, vpn_ntopbuf
,
903 sizeof(vpn_ntopbuf
));
905 diff_str
= nwi_ifstate_get_diff_str(ifstate
);
906 printf("%s%s%s%s rank 0x%x iaddr %s%s%s reach_flags 0x%x\n",
909 (ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0
911 (ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0
915 (vpn_addr_str
!= NULL
) ? " vpn_server_addr: " : "",
916 (vpn_addr_str
!= NULL
) ? vpn_addr_str
: "",
917 ifstate
->reach_flags
);
922 traverse_ifstates(nwi_state_t state
)
928 scan
= nwi_state_get_first_ifstate(state
, AF_INET
);
929 printf("IPv4 traverse list:\n");
930 for (i
= 0; scan
!= NULL
; i
++) {
931 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
932 nwi_ifstate_print(scan
);
933 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
934 scan
= nwi_ifstate_get_next(scan
, AF_INET
);
936 printf("\t alias is ");
937 nwi_ifstate_print(alias
);
940 printf("IPv6 traverse list:\n");
941 scan
= nwi_state_get_first_ifstate(state
, AF_INET6
);
942 for (i
= 0; scan
!= NULL
; i
++) {
943 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
944 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
945 nwi_ifstate_print(scan
);
946 scan
= nwi_ifstate_get_next(scan
, AF_INET6
);
948 printf("\t alias is ");
949 nwi_ifstate_print(alias
);
955 nwi_state_print_common(nwi_state_t state
, bool diff
)
957 unsigned int count
= 0;
964 printf("nwi_state = { "
965 "gen=%llu max_if=%u #v4=%u #v6=%u "
966 "reach_flags=(v4=0x%x, v6=0x%x) }\n",
967 state
->generation_count
,
971 nwi_state_get_reachability_flags(state
, AF_INET
),
972 nwi_state_get_reachability_flags(state
, AF_INET6
));
973 if (state
->ipv4_count
) {
975 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET
);
976 i
< state
->ipv4_count
; i
++, scan
++) {
978 nwi_ifstate_print(scan
);
981 if (state
->ipv6_count
) {
983 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET6
);
984 i
< state
->ipv6_count
; i
++, scan
++) {
986 nwi_ifstate_print(scan
);
990 count
= nwi_state_get_interface_names(state
, NULL
, 0);
992 const char * names
[count
];
994 count
= nwi_state_get_interface_names(state
, names
,
996 printf("%d interfaces%s", count
,
997 (count
!= 0) ? ": " : "");
998 for (i
= 0; i
< count
; i
++) {
999 printf("%s%s", (i
== 0) ? "" : ", ", names
[i
]);
1004 printf("0 interfaces\n");
1006 traverse_ifstates(state
);
1008 printf("-----------------------------------\n");
1013 nwi_state_print(nwi_state_t state
)
1015 nwi_state_print_common(state
, FALSE
);
1019 nwi_state_print_diff(nwi_state_t state
)
1022 nwi_state_print_common(state
, TRUE
);
1028 struct in_addr addr
= { 0 };
1029 struct in6_addr addr6
;
1030 nwi_ifstate_t ifstate
;
1032 nwi_state_t diff_state
;
1033 nwi_state_t new_state
;
1034 nwi_state_t old_state
;
1035 nwi_state_t old_state_copy
;
1037 state
= nwi_state_new(NULL
, 0);
1038 nwi_state_print(state
);
1039 state
= nwi_state_new(NULL
, 1);
1040 nwi_state_print(state
);
1041 state
= nwi_state_new(state
, 2);
1042 nwi_state_print(state
);
1043 state
= nwi_state_new(state
, 10);
1044 nwi_state_print(state
);
1046 bzero(&addr6
, sizeof(addr6
));
1047 /* populate old_state */
1048 old_state
= nwi_state_new(NULL
, 5);
1049 for (int i
= 0; i
< 5; i
++) {
1050 char ifname
[IFNAMSIZ
];
1052 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1053 addr
.s_addr
= htonl((i
% 2) ? i
: (i
+ 1));
1054 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET
, 0,
1055 (i
% 2) ? (i
- 1) : (i
+ 1),
1059 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1060 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET6
, 0,
1061 (i
% 2) ? (10 - i
) : i
,
1066 nwi_state_finalize(old_state
);
1067 nwi_state_print(old_state
);
1069 diff_state
= nwi_state_diff(NULL
, old_state
);
1070 nwi_state_print_diff(diff_state
);
1071 nwi_state_free(diff_state
);
1073 /* remember the old state */
1074 old_state_copy
= nwi_state_make_copy(old_state
);
1076 /* create new state */
1077 new_state
= nwi_state_new(old_state
, 10);
1078 nwi_state_print(new_state
);
1080 for (int i
= 0; i
< 10; i
++) {
1081 char ifname
[IFNAMSIZ
];
1084 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1085 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1086 flags
= (i
> 6) ? NWI_IFSTATE_FLAGS_NOT_IN_LIST
: 0;
1087 ifstate
= nwi_state_add_ifstate(new_state
, ifname
, AF_INET6
,
1094 for (int i
= 9; i
>= 0; i
--) {
1095 char ifname
[IFNAMSIZ
];
1097 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1098 addr
.s_addr
= htonl(i
);
1100 ifstate
= nwi_state_add_ifstate(new_state
,
1109 nwi_state_finalize(new_state
);
1110 nwi_state_print(new_state
);
1112 diff_state
= nwi_state_diff(old_state_copy
, new_state
);
1113 nwi_state_print_diff(diff_state
);
1114 nwi_state_free(diff_state
);
1116 diff_state
= nwi_state_diff(new_state
, old_state_copy
);
1117 nwi_state_print_diff(diff_state
);
1118 nwi_state_free(diff_state
);
1120 nwi_state_free(old_state_copy
);
1121 nwi_state_free(new_state
);
1133 #endif /* TEST_NWI */
1135 #ifdef TEST_NWI_STATE
1138 main(int argc
, char * argv
[])
1140 nwi_state_t state
= nwi_state_copy();