2 * Copyright (c) 2011-2015 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>
33 #include "libSystemConfiguration_client.h"
34 #include "network_information.h"
35 #include "network_information_priv.h"
37 static nwi_state_t G_nwi_state
= NULL
;
38 static pthread_mutex_t nwi_store_lock
= PTHREAD_MUTEX_INITIALIZER
;
39 static boolean_t nwi_store_token_valid
= FALSE
;
41 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
42 static int nwi_store_token
;
44 static boolean_t nwi_store_force_refresh
= FALSE
;
47 #pragma mark Network information [nwi] client support
50 // Note: protected by __nwi_configuration_queue()
51 static int nwi_active
= 0;
52 static libSC_info_client_t
*nwi_client
= NULL
;
55 static dispatch_queue_t
56 __nwi_configuration_queue()
58 static dispatch_once_t once
;
59 static dispatch_queue_t q
;
61 dispatch_once(&once
, ^{
62 q
= dispatch_queue_create(NWI_SERVICE_NAME
, NULL
);
70 _nwi_state_initialize(void)
72 const char *nwi_key
= nwi_state_get_notify_key();
73 uint32_t status
= notify_register_check(nwi_key
,
76 if (status
!= NOTIFY_STATUS_OK
) {
77 fprintf(stderr
, "nwi_state: registration failed (%u)\n", status
);
80 nwi_store_token_valid
= TRUE
;
85 #pragma mark Network information [nwi] APIs
89 * Function: nwi_state_get_notify_key
91 * Returns the BSD notify key to use to monitor when the state changes.
94 * The nwi_state_copy API uses this notify key to monitor when the state
95 * changes, so each invocation of nwi_state_copy returns the current
99 nwi_state_get_notify_key()
101 return "com.apple.system.SystemConfiguration.nwi";
104 #define ATOMIC_CMPXCHG(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
105 #define ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++);
106 #define ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n);
109 _nwi_state_force_refresh()
111 ATOMIC_CMPXCHG(&nwi_store_force_refresh
, FALSE
, TRUE
);
115 nwi_state_retain(nwi_state_t state
)
117 ATOMIC_INC(&state
->ref
);
122 * Function: nwi_state_release
124 * Release the memory associated with the network state.
127 nwi_state_release(nwi_state_t state
)
129 if (ATOMIC_DEC(&state
->ref
) > 0) {
130 // if not last reference
134 // release connection reference on 1-->0 transition
135 dispatch_sync(__nwi_configuration_queue(), ^{
136 if (--nwi_active
== 0) {
137 // if last reference, drop connection
138 libSC_info_client_release(nwi_client
);
144 nwi_state_free(state
);
150 _nwi_state_copy_data()
152 nwi_state_t nwi_state
= NULL
;
153 static const char *proc_name
= NULL
;
154 xpc_object_t reqdict
;
157 dispatch_sync(__nwi_configuration_queue(), ^{
158 if ((nwi_active
++ == 0) || (nwi_client
== NULL
)) {
159 static dispatch_once_t once
;
160 static const char *service_name
= NWI_SERVICE_NAME
;
162 dispatch_once(&once
, ^{
165 // get [XPC] service name
166 name
= getenv(service_name
);
167 if ((name
!= NULL
) && (issetugid() == 0)) {
168 service_name
= strdup(name
);
172 proc_name
= getprogname();
176 libSC_info_client_create(__nwi_configuration_queue(), // dispatch queue
177 service_name
, // XPC service name
178 "Network information"); // service description
179 if (nwi_client
== NULL
) {
185 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
186 // if network information server not available
191 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
194 if (proc_name
!= NULL
) {
195 xpc_dictionary_set_string(reqdict
, NWI_PROC_NAME
, proc_name
);
199 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_REQUEST_COPY
);
201 // send request to the DNS configuration server
202 reply
= libSC_send_message_with_reply_sync(nwi_client
, reqdict
);
203 xpc_release(reqdict
);
209 dataRef
= xpc_dictionary_get_data(reply
, NWI_CONFIGURATION
, &dataLen
);
210 if (dataRef
!= NULL
) {
211 nwi_state
= malloc(dataLen
);
212 bcopy((void *)dataRef
, nwi_state
, dataLen
);
213 if (nwi_state
->version
!= NWI_STATE_VERSION
) {
214 /* make sure the version matches */
215 nwi_state_free(nwi_state
);
230 * Function: nwi_state_copy
232 * Returns the current network state information.
233 * Release after use by calling nwi_state_release().
238 boolean_t force_refresh
;
239 nwi_state_t nwi_state
= NULL
;
240 nwi_state_t old_state
= NULL
;
242 pthread_once(&initialized
, _nwi_state_initialize
);
243 pthread_mutex_lock(&nwi_store_lock
);
245 force_refresh
= ATOMIC_CMPXCHG(&nwi_store_force_refresh
, TRUE
, FALSE
);
247 if (G_nwi_state
!= NULL
) {
251 if (nwi_store_token_valid
== FALSE
) {
252 /* have to throw cached copy away every time */
256 status
= notify_check(nwi_store_token
, &check
);
257 if (status
!= NOTIFY_STATUS_OK
) {
258 fprintf(stderr
, "nwi notify_check: failed with %u\n",
260 /* assume that it changed, throw cached copy away */
264 if (check
!= 0 || force_refresh
) {
265 /* new need snapshot */
266 old_state
= G_nwi_state
;
270 /* Let's populate the cache if it's empty */
271 if (G_nwi_state
== NULL
) {
272 G_nwi_state
= _nwi_state_copy_data();
273 if (G_nwi_state
!= NULL
) {
274 /* one reference for G_nwi_state */
275 nwi_state_retain(G_nwi_state
);
278 if (G_nwi_state
!= NULL
) {
279 /* another reference for this caller */
280 nwi_state_retain(G_nwi_state
);
282 nwi_state
= G_nwi_state
;
283 pthread_mutex_unlock(&nwi_store_lock
);
285 if (old_state
!= NULL
) {
286 /* get rid of G_nwi_state reference */
287 nwi_state_release(old_state
);
293 * Function: _nwi_state_ack
295 * Acknowledge receipt and any changes associated with the [new or
296 * updated] network state.
299 _nwi_state_ack(nwi_state_t state
, const char *bundle_id
)
301 xpc_object_t reqdict
;
307 if ((nwi_client
== NULL
) || !nwi_client
->active
) {
308 // if network information server not available
312 dispatch_sync(__nwi_configuration_queue(), ^{
313 nwi_active
++; // keep connection active (for the life of the process)
317 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
320 xpc_dictionary_set_int64(reqdict
, NWI_REQUEST
, NWI_REQUEST_ACKNOWLEDGE
);
323 xpc_dictionary_set_uint64(reqdict
, NWI_GENERATION
, state
->generation_count
);
325 // send acknowledgement to the DNS configuration server
326 xpc_connection_send_message(nwi_client
->connection
, reqdict
);
328 xpc_release(reqdict
);
333 * Function: nwi_state_get_generation
335 * Returns the generation (mach_time) of the nwi_state data.
336 * Every time the data is updated due to changes
337 * in the network, this value will change.
340 nwi_state_get_generation(nwi_state_t state
)
342 return (state
->generation_count
);
346 * Function: nwi_ifstate_get_generation
348 * Returns the generation (mach_time) of the nwi_ifstate data.
351 nwi_ifstate_get_generation(nwi_ifstate_t ifstate
)
353 return (ifstate
->if_generation_count
);
357 * Function: nwi_ifstate_get_ifname
359 * Return the interface name of the specified ifstate.
362 nwi_ifstate_get_ifname(nwi_ifstate_t ifstate
)
364 return ((ifstate
!= NULL
) ? ifstate
->ifname
: NULL
);
368 flags_from_af(int af
)
370 return ((af
== AF_INET
)
371 ? NWI_IFSTATE_FLAGS_HAS_IPV4
372 : NWI_IFSTATE_FLAGS_HAS_IPV6
);
375 * Function: nwi_ifstate_get_flags
377 * Return the flags for the given ifstate (see above for bit definitions).
380 nwi_ifstate_get_flags(nwi_ifstate_t ifstate
)
382 nwi_ifstate_t alias
= NULL
;
383 nwi_ifstate_flags flags
= 0ULL;
385 if (ifstate
->af_alias_offset
!= 0) {
386 alias
= ifstate
+ ifstate
->af_alias_offset
;
388 flags
|= flags_from_af(ifstate
->af
);
389 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
390 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
394 flags
|= flags_from_af(alias
->af
);
395 if ((alias
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0) {
396 flags
|= NWI_IFSTATE_FLAGS_HAS_DNS
;
403 * Function: nwi_state_get_first_ifstate
405 * Returns the first and highest priority interface that has connectivity
406 * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6.
407 * The connectivity provided is for general networking. To get information
408 * about an interface that isn't available for general networking, use
409 * nwi_state_get_ifstate().
411 * Use nwi_ifstate_get_next() to get the next, lower priority interface
414 * Returns NULL if no connectivity for the specified address family is
418 nwi_state_get_first_ifstate(nwi_state_t state
, int af
)
420 nwi_ifstate_t ifstate
;
426 ifstate
= nwi_state_get_ifstate_with_index(state
, af
, 0);
427 if (ifstate
== NULL
) {
430 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
440 * Function: nwi_state_get_ifstate
442 * Return information for the specified interface 'ifname'.
444 * This API directly returns the ifstate for the specified interface.
445 * This is the only way to access information about an interface that isn't
446 * available for general networking.
448 * Returns NULL if no information is available for that interface.
451 nwi_state_get_ifstate(nwi_state_t state
, const char * ifname
)
453 nwi_ifstate_t ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET
, ifname
);
454 if (ifstate
== NULL
) {
455 ifstate
= nwi_state_get_ifstate_with_name(state
, AF_INET6
, ifname
);
462 * Function: nwi_ifstate_get_next
464 * Returns the next, lower priority nwi_ifstate_t after the specified
465 * 'ifstate' for the protocol family 'af'.
467 * Returns NULL when the end of the list is reached, or we reach an
468 * item that is not in the list.
471 nwi_ifstate_get_next(nwi_ifstate_t ifstate
, int af
)
473 ifstate
= nwi_ifstate_get_alias(ifstate
, af
);
476 & (NWI_IFSTATE_FLAGS_NOT_IN_LIST
477 | NWI_IFSTATE_FLAGS_LAST_ITEM
))
482 if ((ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0) {
489 * Function: nwi_ifstate_compare_rank
491 * Compare the relative rank of two nwi_ifstate_t objects.
493 * The "rank" indicates the importance of the underlying interface.
496 * 0 if ifstate1 and ifstate2 are ranked equally
497 * -1 if ifstate1 is ranked ahead of ifstate2
498 * 1 if ifstate2 is ranked ahead of ifstate1
501 nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1
, nwi_ifstate_t ifstate2
)
503 return RankCompare(ifstate1
->rank
, ifstate2
->rank
);
507 * nwi_state_get_reachability_flags
509 * returns the global reachability flags for a given address family.
510 * If no address family is passed in, it returns the global reachability
511 * flags for either families.
513 * The reachability flags returned follow the definition of
514 * SCNetworkReachabilityFlags.
516 * If the flags are zero (i.e. do not contain kSCNetworkReachabilityFlagsReachable), there is no connectivity.
518 * Otherwise, at least kSCNetworkReachabilityFlagsReachable is set:
520 * No other connection flags are set.
521 * Reachable and no ConnectionRequired
522 * If we have connectivity for the specified address family (and we'd
523 * be returning the reachability flags associated with the default route)
524 * Reachable and ConnectionRequired
525 * If we do not currently have an active/primary network but we may
526 * be able to establish connectivity.
527 * Reachable and OnDemand
528 * If we do not currently have an active/primary network but we may
529 * be able to establish connective on demand.
530 * Reachable and TransientConnection
531 * This connection is transient.
533 * This connection will be going over the cellular network.
536 nwi_state_get_reachability_flags(nwi_state_t nwi_state
, int af
)
538 if (nwi_state
== NULL
) {
541 if (af
== AF_INET
|| af
== AF_INET6
) {
542 nwi_ifstate_t ifstate
;
544 ifstate
= nwi_state_get_first_ifstate(nwi_state
, af
);
546 if (ifstate
!= NULL
) {
547 return ifstate
->reach_flags
;
550 return (af
== AF_INET
) ? nwi_state
->reach_flags_v4
: nwi_state
->reach_flags_v6
;
552 nwi_ifstate_t ifstate_v4
;
553 nwi_ifstate_t ifstate_v6
;
555 ifstate_v4
= nwi_state_get_first_ifstate(nwi_state
, AF_INET
);
556 ifstate_v6
= nwi_state_get_first_ifstate(nwi_state
, AF_INET6
);
558 if (ifstate_v4
!= NULL
) {
559 if (ifstate_v6
!= NULL
) {
560 if (nwi_ifstate_compare_rank(ifstate_v4
, ifstate_v6
) > 0) {
561 return ifstate_v6
->reach_flags
;
563 return ifstate_v4
->reach_flags
;
566 return ifstate_v4
->reach_flags
;
569 if (ifstate_v6
!= NULL
) {
570 return ifstate_v6
->reach_flags
;
574 if (nwi_state
->reach_flags_v4
!= 0) {
575 return nwi_state
->reach_flags_v4
;
577 // This is the case where both ifstate are NULL.
578 return nwi_state
->reach_flags_v6
;
583 * nwi_ifstate_get_vpn_server
585 * returns a sockaddr representation of the vpn server address.
586 * NULL if PPP/VPN/IPSec server address does not exist.
588 const struct sockaddr
*
589 nwi_ifstate_get_vpn_server(nwi_ifstate_t ifstate
)
591 const struct sockaddr
* vpn_server_addr
;
593 vpn_server_addr
= (const struct sockaddr
*)(void *)
594 &ifstate
->vpn_server_address
;
596 if (vpn_server_addr
->sa_family
== 0) {
599 return vpn_server_addr
;
603 * nwi_ifstate_get_reachability_flags
605 * returns the reachability flags for the interface given an address family.
606 * The flags returned are those determined outside of
607 * the routing table. [None, ConnectionRequired, OnDemand,
608 * Transient Connection, WWAN].
611 nwi_ifstate_get_reachability_flags(nwi_ifstate_t ifstate
)
613 return ifstate
->reach_flags
;
617 * nwi_ifstate_get_signature
619 * returns the signature and its length for an ifstate given an address family.
620 * If AF_UNSPEC is passed in, the signature for a given ifstate is returned.
622 * If the signature does not exist, NULL is returned.
625 nwi_ifstate_get_signature(nwi_ifstate_t ifstate
, int af
, int * length
)
627 nwi_ifstate_t i_state
= NULL
;
635 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
642 if (i_state
!= NULL
) {
643 if ((i_state
->flags
& NWI_IFSTATE_FLAGS_HAS_SIGNATURE
) != 0) {
644 *length
= sizeof(i_state
->signature
);
645 return (i_state
->signature
);
655 _nwi_ifstate_is_in_list(nwi_ifstate_t ifstate
, int af
)
657 nwi_ifstate_t i_state
;
659 i_state
= nwi_ifstate_get_alias(ifstate
, af
);
660 if (i_state
== NULL
) {
664 if ((nwi_ifstate_get_flags(i_state
) & NWI_IFSTATE_FLAGS_NOT_IN_LIST
)
673 * nwi_ifstate_get_dns_signature
675 * returns the signature and its length for given
676 * ifstate with a valid dns configuration.
678 * If the signature does not exist, NULL is returned.
682 nwi_ifstate_get_dns_signature(nwi_ifstate_t ifstate
, int * length
)
684 const uint8_t * signature
= NULL
;
685 const uint8_t * v4_signature
;
686 int v4_signature_len
;
687 const uint8_t * v6_signature
;
688 int v6_signature_len
;
692 if ((nwi_ifstate_get_flags(ifstate
) & NWI_IFSTATE_FLAGS_HAS_DNS
) == 0) {
696 v4_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET
, &v4_signature_len
);
697 v6_signature
= nwi_ifstate_get_signature(ifstate
, AF_INET6
, &v6_signature_len
);
698 if (v4_signature
== NULL
&& v6_signature
== NULL
) {
702 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET
) == TRUE
) {
703 signature
= v4_signature
;
704 *length
= v4_signature_len
;
706 if (_nwi_ifstate_is_in_list(ifstate
, AF_INET6
) != TRUE
&& v4_signature_len
> 0) {
707 /* v6 is ranked never, v4 is ranked never but has a valid signature */
708 signature
= v4_signature
;
709 *length
= v4_signature_len
;
711 /* v6 is not ranked never or v4 has no signature */
712 signature
= v6_signature
;
713 *length
= v6_signature_len
;
721 nwi_state_get_interface_names(nwi_state_t state
,
722 const char * names
[],
723 unsigned int names_count
)
726 nwi_ifindex_t
* scan
;
728 if (names
== NULL
|| names_count
== 0) {
729 return (state
->if_list_count
);
731 for (i
= 0, scan
= nwi_state_if_list(state
);
732 i
< state
->if_list_count
; i
++, scan
++) {
733 names
[i
] = state
->ifstate_list
[*scan
].ifname
;
735 return (state
->if_list_count
);
739 #pragma mark Network information [nwi] test code
744 #include <arpa/inet.h>
747 const struct sockaddr
* sa
;
748 const struct sockaddr_in
* sin
;
749 const struct sockaddr_in6
* sin6
;
753 my_sockaddr_ntop(const struct sockaddr
* sa
, char * buf
, int buf_len
)
756 const void * addr_ptr
= NULL
;
759 switch (sa
->sa_family
) {
761 addr_ptr
= &addr
.sin
->sin_addr
;
764 addr_ptr
= &addr
.sin6
->sin6_addr
;
770 if (addr_ptr
== NULL
) {
773 return (inet_ntop(addr
.sa
->sa_family
, addr_ptr
, buf
, buf_len
));
777 nwi_ifstate_print(nwi_ifstate_t ifstate
)
779 const char * addr_str
;
781 char addr_ntopbuf
[INET6_ADDRSTRLEN
];
782 const char * diff_str
;
783 char vpn_ntopbuf
[INET6_ADDRSTRLEN
];
784 const struct sockaddr
* vpn_addr
;
785 const char * vpn_addr_str
= NULL
;
787 address
= nwi_ifstate_get_address(ifstate
);
788 addr_str
= inet_ntop(ifstate
->af
, address
,
789 addr_ntopbuf
, sizeof(addr_ntopbuf
));
790 vpn_addr
= nwi_ifstate_get_vpn_server(ifstate
);
791 if (vpn_addr
!= NULL
) {
792 vpn_addr_str
= my_sockaddr_ntop(vpn_addr
, vpn_ntopbuf
,
793 sizeof(vpn_ntopbuf
));
795 diff_str
= nwi_ifstate_get_diff_str(ifstate
);
796 printf("%s%s%s%s rank 0x%x iaddr %s%s%s reach_flags 0x%x\n",
799 (ifstate
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0
801 (ifstate
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0
805 (vpn_addr_str
!= NULL
) ? " vpn_server_addr: " : "",
806 (vpn_addr_str
!= NULL
) ? vpn_addr_str
: "",
807 ifstate
->reach_flags
);
812 traverse_ifstates(nwi_state_t state
)
818 scan
= nwi_state_get_first_ifstate(state
, AF_INET
);
819 printf("IPv4 traverse list:\n");
820 for (i
= 0; scan
!= NULL
; i
++) {
821 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
822 nwi_ifstate_print(scan
);
823 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
824 scan
= nwi_ifstate_get_next(scan
, AF_INET
);
826 printf("\t alias is ");
827 nwi_ifstate_print(alias
);
830 printf("IPv6 traverse list:\n");
831 scan
= nwi_state_get_first_ifstate(state
, AF_INET6
);
832 for (i
= 0; scan
!= NULL
; i
++) {
833 printf("[%d] flags=0x%llx ", i
, scan
->flags
);
834 alias
= nwi_ifstate_get_alias(scan
, nwi_other_af(scan
->af
));
835 nwi_ifstate_print(scan
);
836 scan
= nwi_ifstate_get_next(scan
, AF_INET6
);
838 printf("\t alias is ");
839 nwi_ifstate_print(alias
);
845 nwi_state_print_common(nwi_state_t state
, bool diff
)
847 unsigned int count
= 0;
854 printf("nwi_state = { "
855 "gen=%llu max_if=%u #v4=%u #v6=%u "
856 "reach_flags=(v4=0x%x, v6=0x%x) }\n",
857 state
->generation_count
,
861 nwi_state_get_reachability_flags(state
, AF_INET
),
862 nwi_state_get_reachability_flags(state
, AF_INET6
));
863 if (state
->ipv4_count
) {
865 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET
);
866 i
< state
->ipv4_count
; i
++, scan
++) {
868 nwi_ifstate_print(scan
);
871 if (state
->ipv6_count
) {
873 for (i
= 0, scan
= nwi_state_ifstate_list(state
, AF_INET6
);
874 i
< state
->ipv6_count
; i
++, scan
++) {
876 nwi_ifstate_print(scan
);
880 count
= nwi_state_get_interface_names(state
, NULL
, 0);
882 const char * names
[count
];
884 count
= nwi_state_get_interface_names(state
, names
,
886 printf("%d interfaces%s", count
,
887 (count
!= 0) ? ": " : "");
888 for (i
= 0; i
< count
; i
++) {
889 printf("%s%s", (i
== 0) ? "" : ", ", names
[i
]);
894 printf("0 interfaces\n");
896 traverse_ifstates(state
);
898 printf("-----------------------------------\n");
903 nwi_state_print(nwi_state_t state
)
905 nwi_state_print_common(state
, FALSE
);
909 nwi_state_print_diff(nwi_state_t state
)
912 nwi_state_print_common(state
, TRUE
);
918 struct in_addr addr
= { 0 };
919 struct in6_addr addr6
;
920 nwi_ifstate_t ifstate
;
922 nwi_state_t diff_state
;
923 nwi_state_t new_state
;
924 nwi_state_t old_state
;
925 nwi_state_t old_state_copy
;
927 state
= nwi_state_new(NULL
, 0);
928 nwi_state_print(state
);
929 state
= nwi_state_new(NULL
, 1);
930 nwi_state_print(state
);
931 state
= nwi_state_new(state
, 2);
932 nwi_state_print(state
);
933 state
= nwi_state_new(state
, 10);
934 nwi_state_print(state
);
936 bzero(&addr6
, sizeof(addr6
));
937 /* populate old_state */
938 old_state
= nwi_state_new(NULL
, 5);
939 for (int i
= 0; i
< 5; i
++) {
940 char ifname
[IFNAMSIZ
];
942 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
943 addr
.s_addr
= htonl((i
% 2) ? i
: (i
+ 1));
944 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET
, 0,
945 (i
% 2) ? (i
- 1) : (i
+ 1),
949 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
950 ifstate
= nwi_state_add_ifstate(old_state
, ifname
, AF_INET6
, 0,
951 (i
% 2) ? (10 - i
) : i
,
956 nwi_state_finalize(old_state
);
957 nwi_state_print(old_state
);
959 diff_state
= nwi_state_diff(NULL
, old_state
);
960 nwi_state_print_diff(diff_state
);
961 nwi_state_free(diff_state
);
963 /* remember the old state */
964 old_state_copy
= nwi_state_make_copy(old_state
);
966 /* create new state */
967 new_state
= nwi_state_new(old_state
, 10);
968 nwi_state_print(new_state
);
970 for (int i
= 0; i
< 10; i
++) {
971 char ifname
[IFNAMSIZ
];
974 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
975 addr6
.__u6_addr
.__u6_addr32
[0] = htonl(i
);
976 flags
= (i
> 6) ? NWI_IFSTATE_FLAGS_NOT_IN_LIST
: 0;
977 ifstate
= nwi_state_add_ifstate(new_state
, ifname
, AF_INET6
,
984 for (int i
= 9; i
>= 0; i
--) {
985 char ifname
[IFNAMSIZ
];
987 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
988 addr
.s_addr
= htonl(i
);
990 ifstate
= nwi_state_add_ifstate(new_state
,
999 nwi_state_finalize(new_state
);
1000 nwi_state_print(new_state
);
1002 diff_state
= nwi_state_diff(old_state_copy
, new_state
);
1003 nwi_state_print_diff(diff_state
);
1004 nwi_state_free(diff_state
);
1006 diff_state
= nwi_state_diff(new_state
, old_state_copy
);
1007 nwi_state_print_diff(diff_state
);
1008 nwi_state_free(diff_state
);
1010 nwi_state_free(old_state_copy
);
1011 nwi_state_free(new_state
);
1023 #endif /* TEST_NWI */
1025 #ifdef TEST_NWI_STATE
1028 main(int argc
, char * argv
[])
1030 nwi_state_t state
= nwi_state_copy();