2 * Copyright (c) 2011-2019 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>
34 #include "libSystemConfiguration_client.h"
35 #include "network_information.h"
36 #include "network_state_information_priv.h"
38 #if !TARGET_OS_SIMULATOR
39 #include "network_config_agent_info_priv.h"
40 #include "configAgentDefines.h"
41 #endif // !TARGET_OS_SIMULATOR
43 static nwi_state_t G_nwi_state
= NULL
;
44 static pthread_mutex_t nwi_store_lock
= PTHREAD_MUTEX_INITIALIZER
;
45 static boolean_t nwi_store_token_valid
= FALSE
;
47 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
48 static int nwi_store_token
;
50 static boolean_t nwi_store_force_refresh
= FALSE
;
51 static const char * client_proc_name
= NULL
;
54 #pragma mark Network information [nwi] client support
57 // Note: protected by __nwi_client_queue()
58 static int nwi_active
= 0;
59 static libSC_info_client_t
*nwi_client
= NULL
;
62 static dispatch_queue_t
65 static dispatch_once_t once
;
66 static dispatch_queue_t q
;
68 dispatch_once(&once
, ^{
69 q
= dispatch_queue_create(NWI_SERVICE_NAME
, NULL
);
77 _nwi_state_initialize(void)
79 const char *nwi_key
= nwi_state_get_notify_key();
80 uint32_t status
= notify_register_check(nwi_key
,
83 if (status
!= NOTIFY_STATUS_OK
) {
84 fprintf(stderr
, "nwi_state: registration failed (%u)\n", status
);
87 nwi_store_token_valid
= TRUE
;
92 #pragma mark Network information [nwi] APIs
96 * Function: nwi_state_get_notify_key
98 * Returns the BSD notify key to use to monitor when the state changes.
101 * The nwi_state_copy API uses this notify key to monitor when the state
102 * changes, so each invocation of nwi_state_copy returns the current
106 nwi_state_get_notify_key()
108 return "com.apple.system.SystemConfiguration.nwi";
111 #define ATOMIC_CMPXCHG(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
112 #define ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++);
113 #define ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n);
116 _nwi_state_force_refresh()
118 ATOMIC_CMPXCHG(&nwi_store_force_refresh
, FALSE
, TRUE
);
122 nwi_state_retain(nwi_state_t state
)
124 ATOMIC_INC(&state
->ref
);
129 _nwi_client_release()
131 // release connection reference on 1-->0 transition
132 dispatch_sync(__nwi_client_queue(), ^{
133 if (--nwi_active
== 0) {
134 // if last reference, drop connection
135 libSC_info_client_release(nwi_client
);
144 dispatch_sync(__nwi_client_queue(), ^{
145 if ((nwi_active
++ == 0) || (nwi_client
== NULL
)) {
146 static dispatch_once_t once
;
147 static const char *service_name
= NWI_SERVICE_NAME
;
149 dispatch_once(&once
, ^{
153 // get [XPC] service name
154 name
= getenv(service_name
);
156 service_name
= strdup(name
);
161 client_proc_name
= getprogname();
165 libSC_info_client_create(__nwi_client_queue(), // dispatch queue
166 service_name
, // XPC service name
167 "Network information"); // service description
168 if (nwi_client
== NULL
) {
176 * Function: nwi_state_release
178 * Release the memory associated with the network state.
181 nwi_state_release(nwi_state_t state
)
183 if (ATOMIC_DEC(&state
->ref
) > 0) {
184 // if not last reference
188 _nwi_client_release();
191 nwi_state_free(state
);
197 _nwi_state_copy_data()
199 nwi_state_t nwi_state
= NULL
;
200 xpc_object_t reqdict
;
203 if (!libSC_info_available()) {
204 os_log(OS_LOG_DEFAULT
, "*** network information requested between fork() and exec()");
210 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
211 // if network information server not available
216 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
219 if (client_proc_name
!= NULL
) {
220 xpc_dictionary_set_string(reqdict
, NWI_PROC_NAME
, client_proc_name
);
224 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_STATE_REQUEST_COPY
);
226 // send request to the DNS configuration server
227 reply
= libSC_send_message_with_reply_sync(nwi_client
, reqdict
);
228 xpc_release(reqdict
);
234 dataRef
= xpc_dictionary_get_data(reply
, NWI_CONFIGURATION
, &dataLen
);
235 if (dataRef
!= NULL
) {
236 nwi_state
= malloc(dataLen
);
237 memcpy(nwi_state
, (void *)dataRef
, dataLen
);
238 if (nwi_state
->version
!= NWI_STATE_VERSION
) {
239 /* make sure the version matches */
240 nwi_state_free(nwi_state
);
254 #if !TARGET_OS_SIMULATOR
256 * Function: _nwi_config_agent_copy_data
258 * Copy the config agent data and the data length.
259 * Caller must free the buffer.
262 _nwi_config_agent_copy_data(const struct netagent
*agent
, uint64_t *length
)
264 const void *buffer
= NULL
;
265 xpc_object_t reqdict
;
268 if ((agent
== NULL
) || (length
== NULL
)) {
274 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
276 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_CONFIG_AGENT_REQUEST_COPY
);
277 if (client_proc_name
!= NULL
) {
278 xpc_dictionary_set_string(reqdict
, NWI_PROC_NAME
, client_proc_name
);
281 xpc_dictionary_set_uuid(reqdict
, kConfigAgentAgentUUID
, agent
->netagent_uuid
);
282 xpc_dictionary_set_string(reqdict
, kConfigAgentType
, agent
->netagent_type
);
284 // send request to the NWI configuration server
285 reply
= libSC_send_message_with_reply_sync(nwi_client
, reqdict
);
286 xpc_release(reqdict
);
289 const void *xpc_buffer
= NULL
;
290 unsigned long len
= 0;
292 xpc_buffer
= xpc_dictionary_get_data(reply
, kConfigAgentAgentData
, &len
);
293 if ((xpc_buffer
!= NULL
) && (len
> 0)) {
294 buffer
= malloc(len
);
296 memcpy((void *)buffer
, (void *)xpc_buffer
, len
);
301 _nwi_client_release();
305 #endif // !TARGET_OS_SIMULATOR
308 * Function: nwi_state_copy
310 * Returns the current network state information.
311 * Release after use by calling nwi_state_release().
316 boolean_t force_refresh
;
317 nwi_state_t nwi_state
= NULL
;
318 nwi_state_t old_state
= NULL
;
320 pthread_once(&initialized
, _nwi_state_initialize
);
321 pthread_mutex_lock(&nwi_store_lock
);
323 force_refresh
= ATOMIC_CMPXCHG(&nwi_store_force_refresh
, TRUE
, FALSE
);
325 if (G_nwi_state
!= NULL
) {
329 if (!nwi_store_token_valid
) {
330 /* have to throw cached copy away every time */
334 status
= notify_check(nwi_store_token
, &check
);
335 if (status
!= NOTIFY_STATUS_OK
) {
336 fprintf(stderr
, "nwi notify_check: failed with %u\n",
338 /* assume that it changed, throw cached copy away */
342 if (check
!= 0 || force_refresh
) {
343 /* new need snapshot */
344 old_state
= G_nwi_state
;
348 /* Let's populate the cache if it's empty */
349 if (G_nwi_state
== NULL
) {
350 G_nwi_state
= _nwi_state_copy_data();
351 if (G_nwi_state
!= NULL
) {
352 /* one reference for G_nwi_state */
353 nwi_state_retain(G_nwi_state
);
356 if (G_nwi_state
!= NULL
) {
357 /* another reference for this caller */
358 nwi_state_retain(G_nwi_state
);
360 nwi_state
= G_nwi_state
;
361 pthread_mutex_unlock(&nwi_store_lock
);
363 if (old_state
!= NULL
) {
364 /* get rid of G_nwi_state reference */
365 nwi_state_release(old_state
);
371 * Function: _nwi_state_ack
373 * Acknowledge receipt and any changes associated with the [new or
374 * updated] network state.
377 _nwi_state_ack(nwi_state_t state
, const char *bundle_id
)
379 #pragma unused(bundle_id)
380 xpc_object_t reqdict
;
386 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
387 // if network information server not available
391 dispatch_sync(__nwi_client_queue(), ^{
392 nwi_active
++; // keep connection active (for the life of the process)
396 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
399 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_STATE_REQUEST_ACKNOWLEDGE
);
402 xpc_dictionary_set_uint64(reqdict
, NWI_GENERATION
, state
->generation_count
);
404 // send acknowledgement to the DNS configuration server
405 xpc_connection_send_message(nwi_client
->connection
, reqdict
);
407 xpc_release(reqdict
);
412 * Function: nwi_state_get_generation
414 * Returns the generation (mach_time) of the nwi_state data.
415 * Every time the data is updated due to changes
416 * in the network, this value will change.
419 nwi_state_get_generation(nwi_state_t state
)
421 return (state
->generation_count
);
425 * Function: nwi_ifstate_get_generation
427 * Returns the generation (mach_time) of the nwi_ifstate data.
430 nwi_ifstate_get_generation(nwi_ifstate_t ifstate
)
432 return (ifstate
->if_generation_count
);
436 * Function: nwi_ifstate_get_ifname
438 * Return the interface name of the specified ifstate.
441 nwi_ifstate_get_ifname(nwi_ifstate_t ifstate
)
443 return ((ifstate
!= NULL
) ? ifstate
->ifname
: NULL
);
447 flags_from_af(int af
)
449 return ((af
== AF_INET
)
450 ? NWI_IFSTATE_FLAGS_HAS_IPV4
451 : NWI_IFSTATE_FLAGS_HAS_IPV6
);
454 * Function: nwi_ifstate_get_flags
456 * Return the flags for the given ifstate (see above for bit definitions).
459 nwi_ifstate_get_flags(nwi_ifstate_t ifstate
)
461 nwi_ifstate_t alias
= NULL
;
462 nwi_ifstate_flags flags
= 0ULL;
464 if (ifstate
->af_alias_offset
!= 0) {
465 alias
= ifstate
+ ifstate
->af_alias_offset
;
467 flags
|= flags_from_af(ifstate
->af
);
468 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
469 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
471 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_CLAT46
) != 0) {
472 flags
|= NWI_IFSTATE_FLAGS_HAS_CLAT46
;
475 flags
|= flags_from_af(alias
->af
);
476 if ((alias
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
477 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
479 if ((alias
->flags
& NWI_IFSTATE_FLAGS_HAS_CLAT46
) != 0) {
480 flags
|= NWI_IFSTATE_FLAGS_HAS_CLAT46
;
487 * Function: nwi_state_get_first_ifstate
489 * Returns the first and highest priority interface that has connectivity
490 * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6.
491 * The connectivity provided is for general networking. To get information
492 * about an interface that isn't available for general networking, use
493 * nwi_state_get_ifstate().
495 * Use nwi_ifstate_get_next() to get the next, lower priority interface
498 * Returns NULL if no connectivity for the specified address family is
502 nwi_state_get_first_ifstate(nwi_state_t state
, int af
)
504 nwi_ifstate_t ifstate
;
510 ifstate
= nwi_state_get_ifstate_with_index(state
, af
, 0);
511 if (ifstate
== NULL
) {
514 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
524 * Function: nwi_state_get_ifstate
526 * Return information for the specified interface 'ifname'.
528 * This API directly returns the ifstate for the specified interface.
529 * This is the only way to access information about an interface that isn't
530 * available for general networking.
532 * Returns NULL if no information is available for that interface.
535 nwi_state_get_ifstate(nwi_state_t state
, const char * ifname
)
537 nwi_ifstate_t ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET
, ifname
);
538 if (ifstate
== NULL
) {
539 ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET6
, ifname
);
546 * Function: nwi_ifstate_get_next
548 * Returns the next, lower priority nwi_ifstate_t after the specified
549 * 'ifstate' for the protocol family 'af'.
551 * Returns NULL when the end of the list is reached, or we reach an
552 * item that is not in the list.
555 nwi_ifstate_get_next(nwi_ifstate_t ifstate
, int af
)
557 ifstate
= nwi_ifstate_get_alias(ifstate
, af
);
560 & (NWI_IFSTATE_FLAGS_NOT_IN_LIST
561 | NWI_IFSTATE_FLAGS_LAST_ITEM
))
566 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0) {
573 * Function: nwi_ifstate_compare_rank
575 * Compare the relative rank of two nwi_ifstate_t objects.
577 * The "rank" indicates the importance of the underlying interface.
580 * 0 if ifstate1 and ifstate2 are ranked equally
581 * -1 if ifstate1 is ranked ahead of ifstate2
582 * 1 if ifstate2 is ranked ahead of ifstate1
585 nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1
, nwi_ifstate_t ifstate2
)
587 return RankCompare(ifstate1
->rank
, ifstate2
->rank
);
591 * nwi_state_get_reachability_flags
593 * returns the global reachability flags for a given address family.
594 * If no address family is passed in, it returns the global reachability
595 * flags for either families.
597 * The reachability flags returned follow the definition of
598 * SCNetworkReachabilityFlags.
600 * If the flags are zero (i.e. do not contain kSCNetworkReachabilityFlagsReachable), there is no connectivity.
602 * Otherwise, at least kSCNetworkReachabilityFlagsReachable is set:
604 * No other connection flags are set.
605 * Reachable and no ConnectionRequired
606 * If we have connectivity for the specified address family (and we'd
607 * be returning the reachability flags associated with the default route)
608 * Reachable and ConnectionRequired
609 * If we do not currently have an active/primary network but we may
610 * be able to establish connectivity.
611 * Reachable and OnDemand
612 * If we do not currently have an active/primary network but we may
613 * be able to establish connective on demand.
614 * Reachable and TransientConnection
615 * This connection is transient.
617 * This connection will be going over the cellular network.
620 nwi_state_get_reachability_flags(nwi_state_t nwi_state
, int af
)
622 if (nwi_state
== NULL
) {
625 if (af
== AF_INET
|| af
== AF_INET6
) {
626 nwi_ifstate_t ifstate
;
628 ifstate
= nwi_state_get_first_ifstate(nwi_state
, af
);
630 if (ifstate
!= NULL
) {
631 return ifstate
->reach_flags
;
634 return (af
== AF_INET
) ? nwi_state
->reach_flags_v4
: nwi_state
->reach_flags_v6
;
636 nwi_ifstate_t ifstate_v4
;
637 nwi_ifstate_t ifstate_v6
;
639 ifstate_v4
= nwi_state_get_first_ifstate(nwi_state
, AF_INET
);
640 ifstate_v6
= nwi_state_get_first_ifstate(nwi_state
, AF_INET6
);
642 if (ifstate_v4
!= NULL
) {
643 if (ifstate_v6
!= NULL
) {
644 if (nwi_ifstate_compare_rank(ifstate_v4
, ifstate_v6
) > 0) {
645 return ifstate_v6
->reach_flags
;
647 return ifstate_v4
->reach_flags
;
650 return ifstate_v4
->reach_flags
;
653 if (ifstate_v6
!= NULL
) {
654 return ifstate_v6
->reach_flags
;
658 if (nwi_state
->reach_flags_v4
!= 0) {
659 return nwi_state
->reach_flags_v4
;
661 // This is the case where both ifstate are NULL.
662 return nwi_state
->reach_flags_v6
;
667 * nwi_ifstate_get_vpn_server
669 * returns a sockaddr representation of the vpn server address.
670 * NULL if PPP/VPN/IPSec server address does not exist.
672 const struct sockaddr
*
673 nwi_ifstate_get_vpn_server(nwi_ifstate_t ifstate
)
675 const struct sockaddr
* vpn_server_addr
;
677 vpn_server_addr
= (const struct sockaddr
*)(void *)
678 &ifstate
->vpn_server_address
;
680 if (vpn_server_addr
->sa_family
== 0) {
683 return vpn_server_addr
;
687 * nwi_ifstate_get_reachability_flags
689 * returns the reachability flags for the interface given an address family.
690 * The flags returned are those determined outside of
691 * the routing table. [None, ConnectionRequired, OnDemand,
692 * Transient Connection, WWAN].
695 nwi_ifstate_get_reachability_flags(nwi_ifstate_t ifstate
)
697 return ifstate
->reach_flags
;
701 * nwi_ifstate_get_signature
703 * returns the signature and its length for an ifstate given an address family.
704 * If AF_UNSPEC is passed in, the signature for a given ifstate is returned.
706 * If the signature does not exist, NULL is returned.
709 nwi_ifstate_get_signature(nwi_ifstate_t ifstate
, int af
, int * length
)
711 nwi_ifstate_t i_state
= NULL
;
719 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
726 if (i_state
!= NULL
) {
727 if ((i_state
->flags
& NWI_IFSTATE_FLAGS_HAS_SIGNATURE
) != 0) {
728 *length
= sizeof(i_state
->signature
);
729 return (i_state
->signature
);
739 _nwi_ifstate_is_in_list(nwi_ifstate_t ifstate
, int af
)
741 nwi_ifstate_t i_state
;
743 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
744 if (i_state
== NULL
) {
748 if ((nwi_ifstate_get_flags(i_state
) & NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
757 * nwi_ifstate_get_dns_signature
759 * returns the signature and its length for given
760 * ifstate with a valid dns configuration.
762 * If the signature does not exist, NULL is returned.
766 nwi_ifstate_get_dns_signature(nwi_ifstate_t ifstate
, int * length
)
768 const uint8_t * signature
= NULL
;
769 const uint8_t * v4_signature
;
770 int v4_signature_len
;
771 const uint8_t * v6_signature
;
772 int v6_signature_len
;
776 if ((nwi_ifstate_get_flags(ifstate
) & NWI_IFSTATE_FLAGS_HAS_DNS
) == 0) {
780 v4_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET
, &v4_signature_len
);
781 v6_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET6
, &v6_signature_len
);
782 if (v4_signature
== NULL
&& v6_signature
== NULL
) {
786 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET
)) {
787 signature
= v4_signature
;
788 *length
= v4_signature_len
;
790 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET6
) != TRUE
&& v4_signature_len
> 0) {
791 /* v6 is ranked never, v4 is ranked never but has a valid signature */
792 signature
= v4_signature
;
793 *length
= v4_signature_len
;
795 /* v6 is not ranked never or v4 has no signature */
796 signature
= v6_signature
;
797 *length
= v6_signature_len
;
805 nwi_state_get_interface_names(nwi_state_t state
,
806 const char * names
[],
807 unsigned int names_count
)
810 nwi_ifindex_t
* scan
;
812 if (names
== NULL
|| names_count
== 0) {
813 return (state
->if_list_count
);
815 for (i
= 0, scan
= nwi_state_if_list(state
);
816 i
< state
->if_list_count
; i
++, scan
++) {
817 names
[i
] = state
->ifstate_list
[*scan
].ifname
;
819 return (state
->if_list_count
);
823 #pragma mark Network information [nwi] test code
828 #include <arpa/inet.h>
831 const struct sockaddr
* sa
;
832 const struct sockaddr_in
* sin
;
833 const struct sockaddr_in6
* sin6
;
837 my_sockaddr_ntop(const struct sockaddr
* sa
, char * buf
, int buf_len
)
840 const void * addr_ptr
= NULL
;
843 switch (sa
->sa_family
) {
845 addr_ptr
= &addr
.sin
->sin_addr
;
848 addr_ptr
= &addr
.sin6
->sin6_addr
;
854 if (addr_ptr
== NULL
) {
857 return (inet_ntop(addr
.sa
->sa_family
, addr_ptr
, buf
, buf_len
));
861 nwi_ifstate_print(nwi_ifstate_t ifstate
)
863 const char * addr_str
;
865 char addr_ntopbuf
[INET6_ADDRSTRLEN
];
866 const char * diff_str
;
867 char vpn_ntopbuf
[INET6_ADDRSTRLEN
];
868 const struct sockaddr
* vpn_addr
;
869 const char * vpn_addr_str
= NULL
;
871 address
= nwi_ifstate_get_address(ifstate
);
872 addr_str
= inet_ntop(ifstate
->af
, address
,
873 addr_ntopbuf
, sizeof(addr_ntopbuf
));
874 vpn_addr
= nwi_ifstate_get_vpn_server(ifstate
);
875 if (vpn_addr
!= NULL
) {
876 vpn_addr_str
= my_sockaddr_ntop(vpn_addr
, vpn_ntopbuf
,
877 sizeof(vpn_ntopbuf
));
879 diff_str
= nwi_ifstate_get_diff_str(ifstate
);
880 printf("%s%s%s%s%s rank 0x%x iaddr %s%s%s reach_flags 0x%x\n",
883 (ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0
885 (ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_CLAT46
) != 0
887 (ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0
891 (vpn_addr_str
!= NULL
) ? " vpn_server_addr: " : "",
892 (vpn_addr_str
!= NULL
) ? vpn_addr_str
: "",
893 ifstate
->reach_flags
);
898 traverse_ifstates(nwi_state_t state
)
904 scan
= nwi_state_get_first_ifstate(state
, AF_INET
);
905 printf("IPv4 traverse list:\n");
906 for (i
= 0; scan
!= NULL
; i
++) {
907 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
908 nwi_ifstate_print(scan
);
909 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
910 scan
= nwi_ifstate_get_next(scan
, AF_INET
);
912 printf("\t alias is ");
913 nwi_ifstate_print(alias
);
916 printf("IPv6 traverse list:\n");
917 scan
= nwi_state_get_first_ifstate(state
, AF_INET6
);
918 for (i
= 0; scan
!= NULL
; i
++) {
919 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
920 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
921 nwi_ifstate_print(scan
);
922 scan
= nwi_ifstate_get_next(scan
, AF_INET6
);
924 printf("\t alias is ");
925 nwi_ifstate_print(alias
);
931 nwi_state_print_common(nwi_state_t state
, bool diff
)
933 unsigned int count
= 0;
940 printf("nwi_state = { "
941 "gen=%llu max_if=%u #v4=%u #v6=%u "
942 "reach_flags=(v4=0x%x, v6=0x%x) }\n",
943 state
->generation_count
,
947 nwi_state_get_reachability_flags(state
, AF_INET
),
948 nwi_state_get_reachability_flags(state
, AF_INET6
));
949 if (state
->ipv4_count
) {
951 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET
);
952 i
< state
->ipv4_count
; i
++, scan
++) {
954 nwi_ifstate_print(scan
);
957 if (state
->ipv6_count
) {
959 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET6
);
960 i
< state
->ipv6_count
; i
++, scan
++) {
962 nwi_ifstate_print(scan
);
966 count
= nwi_state_get_interface_names(state
, NULL
, 0);
968 const char * names
[count
];
970 count
= nwi_state_get_interface_names(state
, names
,
972 printf("%d interfaces%s", count
,
973 (count
!= 0) ? ": " : "");
974 for (i
= 0; i
< count
; i
++) {
975 printf("%s%s", (i
== 0) ? "" : ", ", names
[i
]);
980 printf("0 interfaces\n");
982 traverse_ifstates(state
);
984 printf("-----------------------------------\n");
989 nwi_state_print(nwi_state_t state
)
991 nwi_state_print_common(state
, FALSE
);
995 nwi_state_print_diff(nwi_state_t state
)
998 nwi_state_print_common(state
, TRUE
);
1004 struct in_addr addr
= { 0 };
1005 struct in6_addr addr6
;
1006 nwi_ifstate_t ifstate
;
1008 nwi_state_t diff_state
;
1009 nwi_state_t new_state
;
1010 nwi_state_t old_state
;
1011 nwi_state_t old_state_copy
;
1013 state
= nwi_state_new(NULL
, 0);
1014 nwi_state_print(state
);
1015 state
= nwi_state_new(NULL
, 1);
1016 nwi_state_print(state
);
1017 state
= nwi_state_new(state
, 2);
1018 nwi_state_print(state
);
1019 state
= nwi_state_new(state
, 10);
1020 nwi_state_print(state
);
1022 memset(&addr6
, 0, sizeof(addr6
));
1023 /* populate old_state */
1024 old_state
= nwi_state_new(NULL
, 5);
1025 for (int i
= 0; i
< 5; i
++) {
1026 char ifname
[IFNAMSIZ
];
1028 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1029 addr
.s_addr
= htonl((i
% 2) ? i
: (i
+ 1));
1030 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET
, 0,
1031 (i
% 2) ? (i
- 1) : (i
+ 1),
1035 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1036 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET6
, 0,
1037 (i
% 2) ? (10 - i
) : i
,
1042 nwi_state_finalize(old_state
);
1043 nwi_state_print(old_state
);
1045 diff_state
= nwi_state_diff(NULL
, old_state
);
1046 nwi_state_print_diff(diff_state
);
1047 nwi_state_free(diff_state
);
1049 /* remember the old state */
1050 old_state_copy
= nwi_state_make_copy(old_state
);
1052 /* create new state */
1053 new_state
= nwi_state_new(old_state
, 10);
1054 nwi_state_print(new_state
);
1056 for (int i
= 0; i
< 10; i
++) {
1057 char ifname
[IFNAMSIZ
];
1060 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1061 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1062 flags
= (i
> 6) ? NWI_IFSTATE_FLAGS_NOT_IN_LIST
: 0;
1063 ifstate
= nwi_state_add_ifstate(new_state
, ifname
, AF_INET6
,
1070 for (int i
= 9; i
>= 0; i
--) {
1071 char ifname
[IFNAMSIZ
];
1073 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1074 addr
.s_addr
= htonl(i
);
1076 ifstate
= nwi_state_add_ifstate(new_state
,
1085 nwi_state_finalize(new_state
);
1086 nwi_state_print(new_state
);
1088 diff_state
= nwi_state_diff(old_state_copy
, new_state
);
1089 nwi_state_print_diff(diff_state
);
1090 nwi_state_free(diff_state
);
1092 diff_state
= nwi_state_diff(new_state
, old_state_copy
);
1093 nwi_state_print_diff(diff_state
);
1094 nwi_state_free(diff_state
);
1096 nwi_state_free(old_state_copy
);
1097 nwi_state_free(new_state
);
1109 #endif /* TEST_NWI */
1111 #ifdef TEST_NWI_STATE
1114 main(int argc
, char * argv
[])
1116 nwi_state_t state
= nwi_state_copy();