2 * Copyright (c) 2011-2018 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
;
502 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_CLAT46
) != 0) {
503 flags
|= NWI_IFSTATE_FLAGS_HAS_CLAT46
;
506 flags
|= flags_from_af(alias
->af
);
507 if ((alias
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
508 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
510 if ((alias
->flags
& NWI_IFSTATE_FLAGS_HAS_CLAT46
) != 0) {
511 flags
|= NWI_IFSTATE_FLAGS_HAS_CLAT46
;
518 * Function: nwi_state_get_first_ifstate
520 * Returns the first and highest priority interface that has connectivity
521 * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6.
522 * The connectivity provided is for general networking. To get information
523 * about an interface that isn't available for general networking, use
524 * nwi_state_get_ifstate().
526 * Use nwi_ifstate_get_next() to get the next, lower priority interface
529 * Returns NULL if no connectivity for the specified address family is
533 nwi_state_get_first_ifstate(nwi_state_t state
, int af
)
535 nwi_ifstate_t ifstate
;
541 ifstate
= nwi_state_get_ifstate_with_index(state
, af
, 0);
542 if (ifstate
== NULL
) {
545 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
555 * Function: nwi_state_get_ifstate
557 * Return information for the specified interface 'ifname'.
559 * This API directly returns the ifstate for the specified interface.
560 * This is the only way to access information about an interface that isn't
561 * available for general networking.
563 * Returns NULL if no information is available for that interface.
566 nwi_state_get_ifstate(nwi_state_t state
, const char * ifname
)
568 nwi_ifstate_t ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET
, ifname
);
569 if (ifstate
== NULL
) {
570 ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET6
, ifname
);
577 * Function: nwi_ifstate_get_next
579 * Returns the next, lower priority nwi_ifstate_t after the specified
580 * 'ifstate' for the protocol family 'af'.
582 * Returns NULL when the end of the list is reached, or we reach an
583 * item that is not in the list.
586 nwi_ifstate_get_next(nwi_ifstate_t ifstate
, int af
)
588 ifstate
= nwi_ifstate_get_alias(ifstate
, af
);
591 & (NWI_IFSTATE_FLAGS_NOT_IN_LIST
592 | NWI_IFSTATE_FLAGS_LAST_ITEM
))
597 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0) {
604 * Function: nwi_ifstate_compare_rank
606 * Compare the relative rank of two nwi_ifstate_t objects.
608 * The "rank" indicates the importance of the underlying interface.
611 * 0 if ifstate1 and ifstate2 are ranked equally
612 * -1 if ifstate1 is ranked ahead of ifstate2
613 * 1 if ifstate2 is ranked ahead of ifstate1
616 nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1
, nwi_ifstate_t ifstate2
)
618 return RankCompare(ifstate1
->rank
, ifstate2
->rank
);
622 * nwi_state_get_reachability_flags
624 * returns the global reachability flags for a given address family.
625 * If no address family is passed in, it returns the global reachability
626 * flags for either families.
628 * The reachability flags returned follow the definition of
629 * SCNetworkReachabilityFlags.
631 * If the flags are zero (i.e. do not contain kSCNetworkReachabilityFlagsReachable), there is no connectivity.
633 * Otherwise, at least kSCNetworkReachabilityFlagsReachable is set:
635 * No other connection flags are set.
636 * Reachable and no ConnectionRequired
637 * If we have connectivity for the specified address family (and we'd
638 * be returning the reachability flags associated with the default route)
639 * Reachable and ConnectionRequired
640 * If we do not currently have an active/primary network but we may
641 * be able to establish connectivity.
642 * Reachable and OnDemand
643 * If we do not currently have an active/primary network but we may
644 * be able to establish connective on demand.
645 * Reachable and TransientConnection
646 * This connection is transient.
648 * This connection will be going over the cellular network.
651 nwi_state_get_reachability_flags(nwi_state_t nwi_state
, int af
)
653 if (nwi_state
== NULL
) {
656 if (af
== AF_INET
|| af
== AF_INET6
) {
657 nwi_ifstate_t ifstate
;
659 ifstate
= nwi_state_get_first_ifstate(nwi_state
, af
);
661 if (ifstate
!= NULL
) {
662 return ifstate
->reach_flags
;
665 return (af
== AF_INET
) ? nwi_state
->reach_flags_v4
: nwi_state
->reach_flags_v6
;
667 nwi_ifstate_t ifstate_v4
;
668 nwi_ifstate_t ifstate_v6
;
670 ifstate_v4
= nwi_state_get_first_ifstate(nwi_state
, AF_INET
);
671 ifstate_v6
= nwi_state_get_first_ifstate(nwi_state
, AF_INET6
);
673 if (ifstate_v4
!= NULL
) {
674 if (ifstate_v6
!= NULL
) {
675 if (nwi_ifstate_compare_rank(ifstate_v4
, ifstate_v6
) > 0) {
676 return ifstate_v6
->reach_flags
;
678 return ifstate_v4
->reach_flags
;
681 return ifstate_v4
->reach_flags
;
684 if (ifstate_v6
!= NULL
) {
685 return ifstate_v6
->reach_flags
;
689 if (nwi_state
->reach_flags_v4
!= 0) {
690 return nwi_state
->reach_flags_v4
;
692 // This is the case where both ifstate are NULL.
693 return nwi_state
->reach_flags_v6
;
698 * nwi_ifstate_get_vpn_server
700 * returns a sockaddr representation of the vpn server address.
701 * NULL if PPP/VPN/IPSec server address does not exist.
703 const struct sockaddr
*
704 nwi_ifstate_get_vpn_server(nwi_ifstate_t ifstate
)
706 const struct sockaddr
* vpn_server_addr
;
708 vpn_server_addr
= (const struct sockaddr
*)(void *)
709 &ifstate
->vpn_server_address
;
711 if (vpn_server_addr
->sa_family
== 0) {
714 return vpn_server_addr
;
718 * nwi_ifstate_get_reachability_flags
720 * returns the reachability flags for the interface given an address family.
721 * The flags returned are those determined outside of
722 * the routing table. [None, ConnectionRequired, OnDemand,
723 * Transient Connection, WWAN].
726 nwi_ifstate_get_reachability_flags(nwi_ifstate_t ifstate
)
728 return ifstate
->reach_flags
;
732 * nwi_ifstate_get_signature
734 * returns the signature and its length for an ifstate given an address family.
735 * If AF_UNSPEC is passed in, the signature for a given ifstate is returned.
737 * If the signature does not exist, NULL is returned.
740 nwi_ifstate_get_signature(nwi_ifstate_t ifstate
, int af
, int * length
)
742 nwi_ifstate_t i_state
= NULL
;
750 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
757 if (i_state
!= NULL
) {
758 if ((i_state
->flags
& NWI_IFSTATE_FLAGS_HAS_SIGNATURE
) != 0) {
759 *length
= sizeof(i_state
->signature
);
760 return (i_state
->signature
);
770 _nwi_ifstate_is_in_list(nwi_ifstate_t ifstate
, int af
)
772 nwi_ifstate_t i_state
;
774 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
775 if (i_state
== NULL
) {
779 if ((nwi_ifstate_get_flags(i_state
) & NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
788 * nwi_ifstate_get_dns_signature
790 * returns the signature and its length for given
791 * ifstate with a valid dns configuration.
793 * If the signature does not exist, NULL is returned.
797 nwi_ifstate_get_dns_signature(nwi_ifstate_t ifstate
, int * length
)
799 const uint8_t * signature
= NULL
;
800 const uint8_t * v4_signature
;
801 int v4_signature_len
;
802 const uint8_t * v6_signature
;
803 int v6_signature_len
;
807 if ((nwi_ifstate_get_flags(ifstate
) & NWI_IFSTATE_FLAGS_HAS_DNS
) == 0) {
811 v4_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET
, &v4_signature_len
);
812 v6_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET6
, &v6_signature_len
);
813 if (v4_signature
== NULL
&& v6_signature
== NULL
) {
817 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET
)) {
818 signature
= v4_signature
;
819 *length
= v4_signature_len
;
821 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET6
) != TRUE
&& v4_signature_len
> 0) {
822 /* v6 is ranked never, v4 is ranked never but has a valid signature */
823 signature
= v4_signature
;
824 *length
= v4_signature_len
;
826 /* v6 is not ranked never or v4 has no signature */
827 signature
= v6_signature
;
828 *length
= v6_signature_len
;
836 nwi_state_get_interface_names(nwi_state_t state
,
837 const char * names
[],
838 unsigned int names_count
)
841 nwi_ifindex_t
* scan
;
843 if (names
== NULL
|| names_count
== 0) {
844 return (state
->if_list_count
);
846 for (i
= 0, scan
= nwi_state_if_list(state
);
847 i
< state
->if_list_count
; i
++, scan
++) {
848 names
[i
] = state
->ifstate_list
[*scan
].ifname
;
850 return (state
->if_list_count
);
854 #pragma mark Network information [nwi] test code
859 #include <arpa/inet.h>
862 const struct sockaddr
* sa
;
863 const struct sockaddr_in
* sin
;
864 const struct sockaddr_in6
* sin6
;
868 my_sockaddr_ntop(const struct sockaddr
* sa
, char * buf
, int buf_len
)
871 const void * addr_ptr
= NULL
;
874 switch (sa
->sa_family
) {
876 addr_ptr
= &addr
.sin
->sin_addr
;
879 addr_ptr
= &addr
.sin6
->sin6_addr
;
885 if (addr_ptr
== NULL
) {
888 return (inet_ntop(addr
.sa
->sa_family
, addr_ptr
, buf
, buf_len
));
892 nwi_ifstate_print(nwi_ifstate_t ifstate
)
894 const char * addr_str
;
896 char addr_ntopbuf
[INET6_ADDRSTRLEN
];
897 const char * diff_str
;
898 char vpn_ntopbuf
[INET6_ADDRSTRLEN
];
899 const struct sockaddr
* vpn_addr
;
900 const char * vpn_addr_str
= NULL
;
902 address
= nwi_ifstate_get_address(ifstate
);
903 addr_str
= inet_ntop(ifstate
->af
, address
,
904 addr_ntopbuf
, sizeof(addr_ntopbuf
));
905 vpn_addr
= nwi_ifstate_get_vpn_server(ifstate
);
906 if (vpn_addr
!= NULL
) {
907 vpn_addr_str
= my_sockaddr_ntop(vpn_addr
, vpn_ntopbuf
,
908 sizeof(vpn_ntopbuf
));
910 diff_str
= nwi_ifstate_get_diff_str(ifstate
);
911 printf("%s%s%s%s%s rank 0x%x iaddr %s%s%s reach_flags 0x%x\n",
914 (ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0
916 (ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_CLAT46
) != 0
918 (ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0
922 (vpn_addr_str
!= NULL
) ? " vpn_server_addr: " : "",
923 (vpn_addr_str
!= NULL
) ? vpn_addr_str
: "",
924 ifstate
->reach_flags
);
929 traverse_ifstates(nwi_state_t state
)
935 scan
= nwi_state_get_first_ifstate(state
, AF_INET
);
936 printf("IPv4 traverse list:\n");
937 for (i
= 0; scan
!= NULL
; i
++) {
938 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
939 nwi_ifstate_print(scan
);
940 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
941 scan
= nwi_ifstate_get_next(scan
, AF_INET
);
943 printf("\t alias is ");
944 nwi_ifstate_print(alias
);
947 printf("IPv6 traverse list:\n");
948 scan
= nwi_state_get_first_ifstate(state
, AF_INET6
);
949 for (i
= 0; scan
!= NULL
; i
++) {
950 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
951 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
952 nwi_ifstate_print(scan
);
953 scan
= nwi_ifstate_get_next(scan
, AF_INET6
);
955 printf("\t alias is ");
956 nwi_ifstate_print(alias
);
962 nwi_state_print_common(nwi_state_t state
, bool diff
)
964 unsigned int count
= 0;
971 printf("nwi_state = { "
972 "gen=%llu max_if=%u #v4=%u #v6=%u "
973 "reach_flags=(v4=0x%x, v6=0x%x) }\n",
974 state
->generation_count
,
978 nwi_state_get_reachability_flags(state
, AF_INET
),
979 nwi_state_get_reachability_flags(state
, AF_INET6
));
980 if (state
->ipv4_count
) {
982 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET
);
983 i
< state
->ipv4_count
; i
++, scan
++) {
985 nwi_ifstate_print(scan
);
988 if (state
->ipv6_count
) {
990 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET6
);
991 i
< state
->ipv6_count
; i
++, scan
++) {
993 nwi_ifstate_print(scan
);
997 count
= nwi_state_get_interface_names(state
, NULL
, 0);
999 const char * names
[count
];
1001 count
= nwi_state_get_interface_names(state
, names
,
1003 printf("%d interfaces%s", count
,
1004 (count
!= 0) ? ": " : "");
1005 for (i
= 0; i
< count
; i
++) {
1006 printf("%s%s", (i
== 0) ? "" : ", ", names
[i
]);
1011 printf("0 interfaces\n");
1013 traverse_ifstates(state
);
1015 printf("-----------------------------------\n");
1020 nwi_state_print(nwi_state_t state
)
1022 nwi_state_print_common(state
, FALSE
);
1026 nwi_state_print_diff(nwi_state_t state
)
1029 nwi_state_print_common(state
, TRUE
);
1035 struct in_addr addr
= { 0 };
1036 struct in6_addr addr6
;
1037 nwi_ifstate_t ifstate
;
1039 nwi_state_t diff_state
;
1040 nwi_state_t new_state
;
1041 nwi_state_t old_state
;
1042 nwi_state_t old_state_copy
;
1044 state
= nwi_state_new(NULL
, 0);
1045 nwi_state_print(state
);
1046 state
= nwi_state_new(NULL
, 1);
1047 nwi_state_print(state
);
1048 state
= nwi_state_new(state
, 2);
1049 nwi_state_print(state
);
1050 state
= nwi_state_new(state
, 10);
1051 nwi_state_print(state
);
1053 bzero(&addr6
, sizeof(addr6
));
1054 /* populate old_state */
1055 old_state
= nwi_state_new(NULL
, 5);
1056 for (int i
= 0; i
< 5; i
++) {
1057 char ifname
[IFNAMSIZ
];
1059 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1060 addr
.s_addr
= htonl((i
% 2) ? i
: (i
+ 1));
1061 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET
, 0,
1062 (i
% 2) ? (i
- 1) : (i
+ 1),
1066 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1067 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET6
, 0,
1068 (i
% 2) ? (10 - i
) : i
,
1073 nwi_state_finalize(old_state
);
1074 nwi_state_print(old_state
);
1076 diff_state
= nwi_state_diff(NULL
, old_state
);
1077 nwi_state_print_diff(diff_state
);
1078 nwi_state_free(diff_state
);
1080 /* remember the old state */
1081 old_state_copy
= nwi_state_make_copy(old_state
);
1083 /* create new state */
1084 new_state
= nwi_state_new(old_state
, 10);
1085 nwi_state_print(new_state
);
1087 for (int i
= 0; i
< 10; i
++) {
1088 char ifname
[IFNAMSIZ
];
1091 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1092 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
1093 flags
= (i
> 6) ? NWI_IFSTATE_FLAGS_NOT_IN_LIST
: 0;
1094 ifstate
= nwi_state_add_ifstate(new_state
, ifname
, AF_INET6
,
1101 for (int i
= 9; i
>= 0; i
--) {
1102 char ifname
[IFNAMSIZ
];
1104 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
1105 addr
.s_addr
= htonl(i
);
1107 ifstate
= nwi_state_add_ifstate(new_state
,
1116 nwi_state_finalize(new_state
);
1117 nwi_state_print(new_state
);
1119 diff_state
= nwi_state_diff(old_state_copy
, new_state
);
1120 nwi_state_print_diff(diff_state
);
1121 nwi_state_free(diff_state
);
1123 diff_state
= nwi_state_diff(new_state
, old_state_copy
);
1124 nwi_state_print_diff(diff_state
);
1125 nwi_state_free(diff_state
);
1127 nwi_state_free(old_state_copy
);
1128 nwi_state_free(new_state
);
1140 #endif /* TEST_NWI */
1142 #ifdef TEST_NWI_STATE
1145 main(int argc
, char * argv
[])
1147 nwi_state_t state
= nwi_state_copy();