2 * Copyright (c) 2011-2016 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 #include <os/activity.h>
35 #include "libSystemConfiguration_client.h"
36 #include "network_information.h"
37 #include "network_state_information_priv.h"
39 #if !TARGET_OS_SIMULATOR
40 #include "network_config_agent_info_priv.h"
41 #include "configAgentDefines.h"
42 #endif // !TARGET_OS_SIMULATOR
44 static nwi_state_t G_nwi_state
= NULL
;
45 static pthread_mutex_t nwi_store_lock
= PTHREAD_MUTEX_INITIALIZER
;
46 static boolean_t nwi_store_token_valid
= FALSE
;
48 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
49 static int nwi_store_token
;
51 static boolean_t nwi_store_force_refresh
= FALSE
;
52 static const char * client_proc_name
= NULL
;
55 #pragma mark Network information [nwi] client support
58 // Note: protected by __nwi_client_queue()
59 static int nwi_active
= 0;
60 static libSC_info_client_t
*nwi_client
= NULL
;
64 __nwi_client_activity()
66 static os_activity_t activity
;
67 static dispatch_once_t once
;
69 dispatch_once(&once
, ^{
70 activity
= os_activity_create("accessing network information",
72 OS_ACTIVITY_FLAG_DEFAULT
);
79 static dispatch_queue_t
82 static dispatch_once_t once
;
83 static dispatch_queue_t q
;
85 dispatch_once(&once
, ^{
86 q
= dispatch_queue_create(NWI_SERVICE_NAME
, NULL
);
94 _nwi_state_initialize(void)
96 const char *nwi_key
= nwi_state_get_notify_key();
97 uint32_t status
= notify_register_check(nwi_key
,
100 if (status
!= NOTIFY_STATUS_OK
) {
101 fprintf(stderr
, "nwi_state: registration failed (%u)\n", status
);
104 nwi_store_token_valid
= TRUE
;
109 #pragma mark Network information [nwi] APIs
113 * Function: nwi_state_get_notify_key
115 * Returns the BSD notify key to use to monitor when the state changes.
118 * The nwi_state_copy API uses this notify key to monitor when the state
119 * changes, so each invocation of nwi_state_copy returns the current
123 nwi_state_get_notify_key()
125 return "com.apple.system.SystemConfiguration.nwi";
128 #define ATOMIC_CMPXCHG(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
129 #define ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++);
130 #define ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n);
133 _nwi_state_force_refresh()
135 ATOMIC_CMPXCHG(&nwi_store_force_refresh
, FALSE
, TRUE
);
139 nwi_state_retain(nwi_state_t state
)
141 ATOMIC_INC(&state
->ref
);
146 _nwi_client_release()
148 // release connection reference on 1-->0 transition
149 dispatch_sync(__nwi_client_queue(), ^{
150 if (--nwi_active
== 0) {
151 // if last reference, drop connection
152 libSC_info_client_release(nwi_client
);
161 dispatch_sync(__nwi_client_queue(), ^{
162 if ((nwi_active
++ == 0) || (nwi_client
== NULL
)) {
163 static dispatch_once_t once
;
164 static const char *service_name
= NWI_SERVICE_NAME
;
166 dispatch_once(&once
, ^{
170 // get [XPC] service name
171 name
= getenv(service_name
);
173 service_name
= strdup(name
);
178 client_proc_name
= getprogname();
182 libSC_info_client_create(__nwi_client_queue(), // dispatch queue
183 service_name
, // XPC service name
184 "Network information"); // service description
185 if (nwi_client
== NULL
) {
193 * Function: nwi_state_release
195 * Release the memory associated with the network state.
198 nwi_state_release(nwi_state_t state
)
200 if (ATOMIC_DEC(&state
->ref
) > 0) {
201 // if not last reference
205 _nwi_client_release();
208 nwi_state_free(state
);
214 _nwi_state_copy_data()
216 nwi_state_t nwi_state
= NULL
;
217 xpc_object_t reqdict
;
220 if (!libSC_info_available()) {
221 os_log(OS_LOG_DEFAULT
, "*** network information requested between fork() and exec()");
227 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
228 // if network information server not available
232 // scope NWI activity
233 os_activity_scope(__nwi_client_activity());
236 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
239 if (client_proc_name
!= NULL
) {
240 xpc_dictionary_set_string(reqdict
, NWI_PROC_NAME
, client_proc_name
);
244 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_STATE_REQUEST_COPY
);
246 // send request to the DNS configuration server
247 reply
= libSC_send_message_with_reply_sync(nwi_client
, reqdict
);
248 xpc_release(reqdict
);
254 dataRef
= xpc_dictionary_get_data(reply
, NWI_CONFIGURATION
, &dataLen
);
255 if (dataRef
!= NULL
) {
256 nwi_state
= malloc(dataLen
);
257 bcopy((void *)dataRef
, nwi_state
, dataLen
);
258 if (nwi_state
->version
!= NWI_STATE_VERSION
) {
259 /* make sure the version matches */
260 nwi_state_free(nwi_state
);
274 #if !TARGET_OS_SIMULATOR
276 * Function: _nwi_config_agent_copy_data
278 * Copy the config agent data and the data length.
279 * Caller must free the buffer.
282 _nwi_config_agent_copy_data(const struct netagent
*agent
, uint64_t *length
)
284 const void *buffer
= NULL
;
285 xpc_object_t reqdict
;
288 if ((agent
== NULL
) || (length
== NULL
)) {
294 // scope NWI activity
295 os_activity_scope(__nwi_client_activity());
297 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
299 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_CONFIG_AGENT_REQUEST_COPY
);
300 if (client_proc_name
!= NULL
) {
301 xpc_dictionary_set_string(reqdict
, NWI_PROC_NAME
, client_proc_name
);
304 xpc_dictionary_set_uuid(reqdict
, kConfigAgentAgentUUID
, agent
->netagent_uuid
);
305 xpc_dictionary_set_string(reqdict
, kConfigAgentType
, agent
->netagent_type
);
307 // send request to the NWI configuration server
308 reply
= libSC_send_message_with_reply_sync(nwi_client
, reqdict
);
309 xpc_release(reqdict
);
312 const void *xpc_buffer
= NULL
;
313 unsigned long len
= 0;
315 xpc_buffer
= xpc_dictionary_get_data(reply
, kConfigAgentAgentData
, &len
);
316 if ((xpc_buffer
!= NULL
) && (len
> 0)) {
317 buffer
= malloc(len
);
319 bcopy((void *)xpc_buffer
, (void *)buffer
, len
);
324 _nwi_client_release();
328 #endif // !TARGET_OS_SIMULATOR
331 * Function: nwi_state_copy
333 * Returns the current network state information.
334 * Release after use by calling nwi_state_release().
339 boolean_t force_refresh
;
340 nwi_state_t nwi_state
= NULL
;
341 nwi_state_t old_state
= NULL
;
343 pthread_once(&initialized
, _nwi_state_initialize
);
344 pthread_mutex_lock(&nwi_store_lock
);
346 force_refresh
= ATOMIC_CMPXCHG(&nwi_store_force_refresh
, TRUE
, FALSE
);
348 if (G_nwi_state
!= NULL
) {
352 if (!nwi_store_token_valid
) {
353 /* have to throw cached copy away every time */
357 status
= notify_check(nwi_store_token
, &check
);
358 if (status
!= NOTIFY_STATUS_OK
) {
359 fprintf(stderr
, "nwi notify_check: failed with %u\n",
361 /* assume that it changed, throw cached copy away */
365 if (check
!= 0 || force_refresh
) {
366 /* new need snapshot */
367 old_state
= G_nwi_state
;
371 /* Let's populate the cache if it's empty */
372 if (G_nwi_state
== NULL
) {
373 G_nwi_state
= _nwi_state_copy_data();
374 if (G_nwi_state
!= NULL
) {
375 /* one reference for G_nwi_state */
376 nwi_state_retain(G_nwi_state
);
379 if (G_nwi_state
!= NULL
) {
380 /* another reference for this caller */
381 nwi_state_retain(G_nwi_state
);
383 nwi_state
= G_nwi_state
;
384 pthread_mutex_unlock(&nwi_store_lock
);
386 if (old_state
!= NULL
) {
387 /* get rid of G_nwi_state reference */
388 nwi_state_release(old_state
);
394 * Function: _nwi_state_ack
396 * Acknowledge receipt and any changes associated with the [new or
397 * updated] network state.
400 _nwi_state_ack(nwi_state_t state
, const char *bundle_id
)
402 xpc_object_t reqdict
;
408 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
409 // if network information server not available
413 dispatch_sync(__nwi_client_queue(), ^{
414 nwi_active
++; // keep connection active (for the life of the process)
418 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
421 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_STATE_REQUEST_ACKNOWLEDGE
);
424 xpc_dictionary_set_uint64(reqdict
, NWI_GENERATION
, state
->generation_count
);
426 // send acknowledgement to the DNS configuration server
427 xpc_connection_send_message(nwi_client
->connection
, reqdict
);
429 xpc_release(reqdict
);
434 * Function: nwi_state_get_generation
436 * Returns the generation (mach_time) of the nwi_state data.
437 * Every time the data is updated due to changes
438 * in the network, this value will change.
441 nwi_state_get_generation(nwi_state_t state
)
443 return (state
->generation_count
);
447 * Function: nwi_ifstate_get_generation
449 * Returns the generation (mach_time) of the nwi_ifstate data.
452 nwi_ifstate_get_generation(nwi_ifstate_t ifstate
)
454 return (ifstate
->if_generation_count
);
458 * Function: nwi_ifstate_get_ifname
460 * Return the interface name of the specified ifstate.
463 nwi_ifstate_get_ifname(nwi_ifstate_t ifstate
)
465 return ((ifstate
!= NULL
) ? ifstate
->ifname
: NULL
);
469 flags_from_af(int af
)
471 return ((af
== AF_INET
)
472 ? NWI_IFSTATE_FLAGS_HAS_IPV4
473 : NWI_IFSTATE_FLAGS_HAS_IPV6
);
476 * Function: nwi_ifstate_get_flags
478 * Return the flags for the given ifstate (see above for bit definitions).
481 nwi_ifstate_get_flags(nwi_ifstate_t ifstate
)
483 nwi_ifstate_t alias
= NULL
;
484 nwi_ifstate_flags flags
= 0ULL;
486 if (ifstate
->af_alias_offset
!= 0) {
487 alias
= ifstate
+ ifstate
->af_alias_offset
;
489 flags
|= flags_from_af(ifstate
->af
);
490 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
491 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
495 flags
|= flags_from_af(alias
->af
);
496 if ((alias
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
497 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
504 * Function: nwi_state_get_first_ifstate
506 * Returns the first and highest priority interface that has connectivity
507 * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6.
508 * The connectivity provided is for general networking. To get information
509 * about an interface that isn't available for general networking, use
510 * nwi_state_get_ifstate().
512 * Use nwi_ifstate_get_next() to get the next, lower priority interface
515 * Returns NULL if no connectivity for the specified address family is
519 nwi_state_get_first_ifstate(nwi_state_t state
, int af
)
521 nwi_ifstate_t ifstate
;
527 ifstate
= nwi_state_get_ifstate_with_index(state
, af
, 0);
528 if (ifstate
== NULL
) {
531 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
541 * Function: nwi_state_get_ifstate
543 * Return information for the specified interface 'ifname'.
545 * This API directly returns the ifstate for the specified interface.
546 * This is the only way to access information about an interface that isn't
547 * available for general networking.
549 * Returns NULL if no information is available for that interface.
552 nwi_state_get_ifstate(nwi_state_t state
, const char * ifname
)
554 nwi_ifstate_t ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET
, ifname
);
555 if (ifstate
== NULL
) {
556 ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET6
, ifname
);
563 * Function: nwi_ifstate_get_next
565 * Returns the next, lower priority nwi_ifstate_t after the specified
566 * 'ifstate' for the protocol family 'af'.
568 * Returns NULL when the end of the list is reached, or we reach an
569 * item that is not in the list.
572 nwi_ifstate_get_next(nwi_ifstate_t ifstate
, int af
)
574 ifstate
= nwi_ifstate_get_alias(ifstate
, af
);
577 & (NWI_IFSTATE_FLAGS_NOT_IN_LIST
578 | NWI_IFSTATE_FLAGS_LAST_ITEM
))
583 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0) {
590 * Function: nwi_ifstate_compare_rank
592 * Compare the relative rank of two nwi_ifstate_t objects.
594 * The "rank" indicates the importance of the underlying interface.
597 * 0 if ifstate1 and ifstate2 are ranked equally
598 * -1 if ifstate1 is ranked ahead of ifstate2
599 * 1 if ifstate2 is ranked ahead of ifstate1
602 nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1
, nwi_ifstate_t ifstate2
)
604 return RankCompare(ifstate1
->rank
, ifstate2
->rank
);
608 * nwi_state_get_reachability_flags
610 * returns the global reachability flags for a given address family.
611 * If no address family is passed in, it returns the global reachability
612 * flags for either families.
614 * The reachability flags returned follow the definition of
615 * SCNetworkReachabilityFlags.
617 * If the flags are zero (i.e. do not contain kSCNetworkReachabilityFlagsReachable), there is no connectivity.
619 * Otherwise, at least kSCNetworkReachabilityFlagsReachable is set:
621 * No other connection flags are set.
622 * Reachable and no ConnectionRequired
623 * If we have connectivity for the specified address family (and we'd
624 * be returning the reachability flags associated with the default route)
625 * Reachable and ConnectionRequired
626 * If we do not currently have an active/primary network but we may
627 * be able to establish connectivity.
628 * Reachable and OnDemand
629 * If we do not currently have an active/primary network but we may
630 * be able to establish connective on demand.
631 * Reachable and TransientConnection
632 * This connection is transient.
634 * This connection will be going over the cellular network.
637 nwi_state_get_reachability_flags(nwi_state_t nwi_state
, int af
)
639 if (nwi_state
== NULL
) {
642 if (af
== AF_INET
|| af
== AF_INET6
) {
643 nwi_ifstate_t ifstate
;
645 ifstate
= nwi_state_get_first_ifstate(nwi_state
, af
);
647 if (ifstate
!= NULL
) {
648 return ifstate
->reach_flags
;
651 return (af
== AF_INET
) ? nwi_state
->reach_flags_v4
: nwi_state
->reach_flags_v6
;
653 nwi_ifstate_t ifstate_v4
;
654 nwi_ifstate_t ifstate_v6
;
656 ifstate_v4
= nwi_state_get_first_ifstate(nwi_state
, AF_INET
);
657 ifstate_v6
= nwi_state_get_first_ifstate(nwi_state
, AF_INET6
);
659 if (ifstate_v4
!= NULL
) {
660 if (ifstate_v6
!= NULL
) {
661 if (nwi_ifstate_compare_rank(ifstate_v4
, ifstate_v6
) > 0) {
662 return ifstate_v6
->reach_flags
;
664 return ifstate_v4
->reach_flags
;
667 return ifstate_v4
->reach_flags
;
670 if (ifstate_v6
!= NULL
) {
671 return ifstate_v6
->reach_flags
;
675 if (nwi_state
->reach_flags_v4
!= 0) {
676 return nwi_state
->reach_flags_v4
;
678 // This is the case where both ifstate are NULL.
679 return nwi_state
->reach_flags_v6
;
684 * nwi_ifstate_get_vpn_server
686 * returns a sockaddr representation of the vpn server address.
687 * NULL if PPP/VPN/IPSec server address does not exist.
689 const struct sockaddr
*
690 nwi_ifstate_get_vpn_server(nwi_ifstate_t ifstate
)
692 const struct sockaddr
* vpn_server_addr
;
694 vpn_server_addr
= (const struct sockaddr
*)(void *)
695 &ifstate
->vpn_server_address
;
697 if (vpn_server_addr
->sa_family
== 0) {
700 return vpn_server_addr
;
704 * nwi_ifstate_get_reachability_flags
706 * returns the reachability flags for the interface given an address family.
707 * The flags returned are those determined outside of
708 * the routing table. [None, ConnectionRequired, OnDemand,
709 * Transient Connection, WWAN].
712 nwi_ifstate_get_reachability_flags(nwi_ifstate_t ifstate
)
714 return ifstate
->reach_flags
;
718 * nwi_ifstate_get_signature
720 * returns the signature and its length for an ifstate given an address family.
721 * If AF_UNSPEC is passed in, the signature for a given ifstate is returned.
723 * If the signature does not exist, NULL is returned.
726 nwi_ifstate_get_signature(nwi_ifstate_t ifstate
, int af
, int * length
)
728 nwi_ifstate_t i_state
= NULL
;
736 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
743 if (i_state
!= NULL
) {
744 if ((i_state
->flags
& NWI_IFSTATE_FLAGS_HAS_SIGNATURE
) != 0) {
745 *length
= sizeof(i_state
->signature
);
746 return (i_state
->signature
);
756 _nwi_ifstate_is_in_list(nwi_ifstate_t ifstate
, int af
)
758 nwi_ifstate_t i_state
;
760 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
761 if (i_state
== NULL
) {
765 if ((nwi_ifstate_get_flags(i_state
) & NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
774 * nwi_ifstate_get_dns_signature
776 * returns the signature and its length for given
777 * ifstate with a valid dns configuration.
779 * If the signature does not exist, NULL is returned.
783 nwi_ifstate_get_dns_signature(nwi_ifstate_t ifstate
, int * length
)
785 const uint8_t * signature
= NULL
;
786 const uint8_t * v4_signature
;
787 int v4_signature_len
;
788 const uint8_t * v6_signature
;
789 int v6_signature_len
;
793 if ((nwi_ifstate_get_flags(ifstate
) & NWI_IFSTATE_FLAGS_HAS_DNS
) == 0) {
797 v4_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET
, &v4_signature_len
);
798 v6_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET6
, &v6_signature_len
);
799 if (v4_signature
== NULL
&& v6_signature
== NULL
) {
803 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET
)) {
804 signature
= v4_signature
;
805 *length
= v4_signature_len
;
807 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET6
) != TRUE
&& v4_signature_len
> 0) {
808 /* v6 is ranked never, v4 is ranked never but has a valid signature */
809 signature
= v4_signature
;
810 *length
= v4_signature_len
;
812 /* v6 is not ranked never or v4 has no signature */
813 signature
= v6_signature
;
814 *length
= v6_signature_len
;
822 nwi_state_get_interface_names(nwi_state_t state
,
823 const char * names
[],
824 unsigned int names_count
)
827 nwi_ifindex_t
* scan
;
829 if (names
== NULL
|| names_count
== 0) {
830 return (state
->if_list_count
);
832 for (i
= 0, scan
= nwi_state_if_list(state
);
833 i
< state
->if_list_count
; i
++, scan
++) {
834 names
[i
] = state
->ifstate_list
[*scan
].ifname
;
836 return (state
->if_list_count
);
840 #pragma mark Network information [nwi] test code
845 #include <arpa/inet.h>
848 const struct sockaddr
* sa
;
849 const struct sockaddr_in
* sin
;
850 const struct sockaddr_in6
* sin6
;
854 my_sockaddr_ntop(const struct sockaddr
* sa
, char * buf
, int buf_len
)
857 const void * addr_ptr
= NULL
;
860 switch (sa
->sa_family
) {
862 addr_ptr
= &addr
.sin
->sin_addr
;
865 addr_ptr
= &addr
.sin6
->sin6_addr
;
871 if (addr_ptr
== NULL
) {
874 return (inet_ntop(addr
.sa
->sa_family
, addr_ptr
, buf
, buf_len
));
878 nwi_ifstate_print(nwi_ifstate_t ifstate
)
880 const char * addr_str
;
882 char addr_ntopbuf
[INET6_ADDRSTRLEN
];
883 const char * diff_str
;
884 char vpn_ntopbuf
[INET6_ADDRSTRLEN
];
885 const struct sockaddr
* vpn_addr
;
886 const char * vpn_addr_str
= NULL
;
888 address
= nwi_ifstate_get_address(ifstate
);
889 addr_str
= inet_ntop(ifstate
->af
, address
,
890 addr_ntopbuf
, sizeof(addr_ntopbuf
));
891 vpn_addr
= nwi_ifstate_get_vpn_server(ifstate
);
892 if (vpn_addr
!= NULL
) {
893 vpn_addr_str
= my_sockaddr_ntop(vpn_addr
, vpn_ntopbuf
,
894 sizeof(vpn_ntopbuf
));
896 diff_str
= nwi_ifstate_get_diff_str(ifstate
);
897 printf("%s%s%s%s rank 0x%x iaddr %s%s%s reach_flags 0x%x\n",
900 (ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0
902 (ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0
906 (vpn_addr_str
!= NULL
) ? " vpn_server_addr: " : "",
907 (vpn_addr_str
!= NULL
) ? vpn_addr_str
: "",
908 ifstate
->reach_flags
);
913 traverse_ifstates(nwi_state_t state
)
919 scan
= nwi_state_get_first_ifstate(state
, AF_INET
);
920 printf("IPv4 traverse list:\n");
921 for (i
= 0; scan
!= NULL
; i
++) {
922 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
923 nwi_ifstate_print(scan
);
924 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
925 scan
= nwi_ifstate_get_next(scan
, AF_INET
);
927 printf("\t alias is ");
928 nwi_ifstate_print(alias
);
931 printf("IPv6 traverse list:\n");
932 scan
= nwi_state_get_first_ifstate(state
, AF_INET6
);
933 for (i
= 0; scan
!= NULL
; i
++) {
934 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
935 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
936 nwi_ifstate_print(scan
);
937 scan
= nwi_ifstate_get_next(scan
, AF_INET6
);
939 printf("\t alias is ");
940 nwi_ifstate_print(alias
);
946 nwi_state_print_common(nwi_state_t state
, bool diff
)
948 unsigned int count
= 0;
955 printf("nwi_state = { "
956 "gen=%llu max_if=%u #v4=%u #v6=%u "
957 "reach_flags=(v4=0x%x, v6=0x%x) }\n",
958 state
->generation_count
,
962 nwi_state_get_reachability_flags(state
, AF_INET
),
963 nwi_state_get_reachability_flags(state
, AF_INET6
));
964 if (state
->ipv4_count
) {
966 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET
);
967 i
< state
->ipv4_count
; i
++, scan
++) {
969 nwi_ifstate_print(scan
);
972 if (state
->ipv6_count
) {
974 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET6
);
975 i
< state
->ipv6_count
; i
++, scan
++) {
977 nwi_ifstate_print(scan
);
981 count
= nwi_state_get_interface_names(state
, NULL
, 0);
983 const char * names
[count
];
985 count
= nwi_state_get_interface_names(state
, names
,
987 printf("%d interfaces%s", count
,
988 (count
!= 0) ? ": " : "");
989 for (i
= 0; i
< count
; i
++) {
990 printf("%s%s", (i
== 0) ? "" : ", ", names
[i
]);
995 printf("0 interfaces\n");
997 traverse_ifstates(state
);
999 printf("-----------------------------------\n");
1004 nwi_state_print(nwi_state_t state
)
1006 nwi_state_print_common(state
, FALSE
);
1010 nwi_state_print_diff(nwi_state_t state
)
1013 nwi_state_print_common(state
, TRUE
);
1019 struct in_addr addr
= { 0 };
1020 struct in6_addr addr6
;
1021 nwi_ifstate_t ifstate
;
1023 nwi_state_t diff_state
;
1024 nwi_state_t new_state
;
1025 nwi_state_t old_state
;
1026 nwi_state_t old_state_copy
;
1028 state
= nwi_state_new(NULL
, 0);
1029 nwi_state_print(state
);
1030 state
= nwi_state_new(NULL
, 1);
1031 nwi_state_print(state
);
1032 state
= nwi_state_new(state
, 2);
1033 nwi_state_print(state
);
1034 state
= nwi_state_new(state
, 10);
1035 nwi_state_print(state
);
1037 bzero(&addr6
, sizeof(addr6
));
1038 /* populate old_state */
1039 old_state
= nwi_state_new(NULL
, 5);
1040 for (int i
= 0; i
< 5; i
++) {
1041 char ifname
[IFNAMSIZ
];
1043 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1044 addr
.s_addr
= htonl((i
% 2) ? i
: (i
+ 1));
1045 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET
, 0,
1046 (i
% 2) ? (i
- 1) : (i
+ 1),
1050 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1051 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET6
, 0,
1052 (i
% 2) ? (10 - i
) : i
,
1057 nwi_state_finalize(old_state
);
1058 nwi_state_print(old_state
);
1060 diff_state
= nwi_state_diff(NULL
, old_state
);
1061 nwi_state_print_diff(diff_state
);
1062 nwi_state_free(diff_state
);
1064 /* remember the old state */
1065 old_state_copy
= nwi_state_make_copy(old_state
);
1067 /* create new state */
1068 new_state
= nwi_state_new(old_state
, 10);
1069 nwi_state_print(new_state
);
1071 for (int i
= 0; i
< 10; i
++) {
1072 char ifname
[IFNAMSIZ
];
1075 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1076 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1077 flags
= (i
> 6) ? NWI_IFSTATE_FLAGS_NOT_IN_LIST
: 0;
1078 ifstate
= nwi_state_add_ifstate(new_state
, ifname
, AF_INET6
,
1085 for (int i
= 9; i
>= 0; i
--) {
1086 char ifname
[IFNAMSIZ
];
1088 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1089 addr
.s_addr
= htonl(i
);
1091 ifstate
= nwi_state_add_ifstate(new_state
,
1100 nwi_state_finalize(new_state
);
1101 nwi_state_print(new_state
);
1103 diff_state
= nwi_state_diff(old_state_copy
, new_state
);
1104 nwi_state_print_diff(diff_state
);
1105 nwi_state_free(diff_state
);
1107 diff_state
= nwi_state_diff(new_state
, old_state_copy
);
1108 nwi_state_print_diff(diff_state
);
1109 nwi_state_free(diff_state
);
1111 nwi_state_free(old_state_copy
);
1112 nwi_state_free(new_state
);
1124 #endif /* TEST_NWI */
1126 #ifdef TEST_NWI_STATE
1129 main(int argc
, char * argv
[])
1131 nwi_state_t state
= nwi_state_copy();