2 * Copyright (c) 2011 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@
24 #include <arpa/inet.h>
27 #include <sys/socket.h>
31 #include "network_information_priv.h"
34 sa_family_t nwi_af_list
[] = {AF_INET
, AF_INET6
};
36 static __inline__
unsigned int
37 nwi_state_compute_size(unsigned int n
)
39 return (offsetof(nwi_state
, nwi_ifstates
[n
]));
44 nwi_state_copy_priv(nwi_state_t src
)
46 nwi_state_t dest
= NULL
;
52 dest
= malloc(src
->size
);
55 bcopy(src
, dest
, src
->size
);
64 nwi_state_new(nwi_state_t old_state
, int elems
)
66 nwi_state_t state
= NULL
;
69 if (old_state
== NULL
&& elems
== 0) {
73 /* Need to insert a last node for each of the v4/v6 list */
74 new_size
= (elems
!= 0)?
75 (sizeof(nwi_state
) + nwi_state_compute_size((elems
+1) * 2)):0;
77 /* Should we reallocate? */
78 if (old_state
!= NULL
) {
79 if (old_state
->size
>= new_size
) {
84 state
= malloc(new_size
);
89 state
->size
= new_size
;
92 * v4 list is stored 0 to elems,
93 * v6 list is stored elems + 1 to 2 * elems + 2
95 state
->ipv6_start
= elems
+ 1;
97 if (old_state
!= NULL
) {
98 state
->ipv6_count
= old_state
->ipv6_count
;
99 if (state
->ipv6_count
> 0) {
100 bcopy((void*) &old_state
->nwi_ifstates
[old_state
->ipv6_start
],
101 (void*) &state
->nwi_ifstates
[state
->ipv6_start
],
102 old_state
->ipv6_count
* sizeof(nwi_ifstate
));
105 state
->ipv4_count
= old_state
->ipv4_count
;
107 if (state
->ipv4_count
> 0) {
108 bcopy((void*) old_state
->nwi_ifstates
,
109 (void*) state
->nwi_ifstates
,
110 old_state
->ipv4_count
* sizeof(nwi_ifstate
));
115 state
->ipv4_count
= 0;
116 state
->ipv6_count
= 0;
118 nwi_state_set_last(state
, AF_INET
);
119 nwi_state_set_last(state
, AF_INET6
);
126 nwi_ifstate_t
nwi_ifstate_get_last(nwi_state_t state
, int af
, uint32_t** last
)
131 count
= (af
== AF_INET
)
132 ?&state
->ipv4_count
:&state
->ipv6_count
;
134 idx
= (af
== AF_INET
)
135 ?state
->ipv4_count
:(state
->ipv6_start
+ state
->ipv6_count
);
139 return &state
->nwi_ifstates
[idx
];
145 nwi_insert_ifstate(nwi_state_t state
,
146 const char* ifname
, int af
,
147 uint64_t flags
, Rank rank
,
150 nwi_ifstate_t ifstate
;
152 /* Will only insert unique elements in the list */
153 ifstate
= nwi_state_get_ifstate_with_name(state
, af
, ifname
);
155 /* Already present, just ignore it */
156 if (ifstate
!= NULL
) {
157 if (ifstate
->rank
< rank
) {
162 if (ifstate
== NULL
) {
165 /* We need to append it as the last element */
166 ifstate
= nwi_ifstate_get_last(state
, af
, &last
);
167 strcpy(ifstate
->ifname
, ifname
);
168 ifstate
->af_alias
= NULL
;
170 ifstate
->diff_ch
= NULL
;
174 /* We need to update the address/rank/flag fields for the existing/new
179 ifstate
->iaddr
= *((struct in_addr
*) ifa
);
182 ifstate
->iaddr6
= *((struct in6_addr
*) ifa
);
190 ifstate
->rank
= rank
;
191 ifstate
->flags
= flags
;
198 nwi_state_clear(nwi_state_t state
, int af
)
202 count
= (af
== AF_INET
)
203 ?&state
->ipv4_count
:&state
->ipv6_count
;
206 nwi_state_set_last(state
, af
);
213 nwi_state_set_last(nwi_state_t state
, int af
)
221 /* The last element is an element with the flags set as
222 * NWI_IFSTATE_FLAGS_NOT_IN_LIST */
223 last_elem_idx
= (af
== AF_INET
)
225 :(state
->ipv6_start
+ state
->ipv6_count
);
227 state
->nwi_ifstates
[last_elem_idx
].ifname
[0] = '\0';
228 state
->nwi_ifstates
[last_elem_idx
].flags
229 |= NWI_IFSTATE_FLAGS_NOT_IN_LIST
;
234 _nwi_state_dump(int level
, nwi_state_t state
)
236 const char * addr_str
;
239 char ntopbuf
[INET6_ADDRSTRLEN
];
244 syslog(level
, "<empty nwi_state>");
247 syslog(level
, "nwi_state = { gen = %llu size = %u #ipv4 = %u #ipv6 = %u }",
248 state
->generation_count
,
253 if (state
->ipv4_count
) {
254 syslog(level
, "IPv4:");
255 for (i
= 0, scan
= state
->nwi_ifstates
;
256 i
< state
->ipv4_count
; i
++, scan
++) {
257 bool has_dns
= (scan
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0;
258 bool never
= (scan
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0;
260 address
= nwi_ifstate_get_address(scan
);
261 addr_str
= inet_ntop(scan
->af
, address
, ntopbuf
, sizeof(ntopbuf
));
263 syslog(level
, " [%d]: %s%s%s%s rank %u iaddr: %s " ,
264 i
, scan
->ifname
, scan
->diff_ch
!= NULL
?scan
->diff_ch
:"",
265 has_dns
? " dns" : "",
266 never
? " never" : "",
271 if (state
->ipv6_count
) {
272 syslog(level
, "IPv6:");
273 for (i
= 0, scan
= state
->nwi_ifstates
+ state
->ipv6_start
;
274 i
< state
->ipv6_count
; i
++, scan
++) {
275 bool has_dns
= (scan
->flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) != 0;
276 bool never
= (scan
->flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) != 0;
278 address
= nwi_ifstate_get_address(scan
);
279 addr_str
= inet_ntop(scan
->af
, address
, ntopbuf
, sizeof(ntopbuf
));
280 syslog(level
, " [%d]: %s%s%s%s rank %u iaddr6: %s ",
281 i
, scan
->ifname
, scan
->diff_ch
!= NULL
?scan
->diff_ch
:"",
282 has_dns
? " dns" : "",
283 never
? " never" : "",
299 nwi_ifstate_get_address(nwi_ifstate_t ifstate
)
301 return (void *)&ifstate
->iaddr
;
306 nwi_ifstate_get_diff_str(nwi_ifstate_t ifstate
)
308 return ifstate
->diff_ch
;
314 nwi_ifstate_has_changed(nwi_ifstate_t ifstate1
, nwi_ifstate_t ifstate2
)
316 if (ifstate1
->rank
!= ifstate2
->rank
) {
320 if (ifstate1
->flags
!= ifstate2
->flags
) {
324 if (ifstate1
->af
== AF_INET
) {
325 if (memcmp(&ifstate1
->iaddr
, &ifstate2
->iaddr
, sizeof(struct in_addr
)) != 0) {
329 if (memcmp(&ifstate1
->iaddr6
, &ifstate2
->iaddr6
, sizeof(struct in6_addr
)) != 0) {
339 nwi_ifstate_append(nwi_state_t state
, nwi_ifstate_t scan
)
341 nwi_ifstate_t new_ifstate
= NULL
;
344 new_ifstate
= nwi_ifstate_get_last(state
, scan
->af
, &last
);
345 memcpy(new_ifstate
, scan
, sizeof(*scan
));
353 nwi_ifstate_set_diff_str(nwi_ifstate_t ifstate
, const char * ch
)
355 ifstate
->diff_ch
= ch
;
360 nwi_state_merge_added(nwi_state_t state
, nwi_state_t old_state
,
361 nwi_state_t new_state
)
366 /* Iterate through v4 and v6 list and annotate the diff flags */
367 for (idx
= 0; idx
< sizeof(nwi_af_list
)/sizeof(nwi_af_list
[0]); idx
++) {
368 scan
= nwi_state_get_first_ifstate(new_state
, nwi_af_list
[idx
]);
370 while (scan
!= NULL
) {
371 nwi_ifstate_t existing_ifstate
, new_ifstate
;
374 ifname
= nwi_ifstate_get_ifname(scan
);
376 existing_ifstate
= nwi_state_get_ifstate_with_name(old_state
, scan
->af
, ifname
);
378 /* Add the element that is not in the store */
379 new_ifstate
= nwi_ifstate_append(state
, scan
);
381 /* These are potentially "added" elements unless they are
383 nwi_ifstate_set_diff_str(new_ifstate
, added
);
385 if (existing_ifstate
!= NULL
) {
386 if (nwi_ifstate_has_changed(existing_ifstate
, new_ifstate
) == TRUE
) {
387 nwi_ifstate_set_diff_str(new_ifstate
, changed
);
389 nwi_ifstate_set_diff_str(new_ifstate
, unchanged
);
392 scan
= nwi_ifstate_get_next(scan
, scan
->af
);
394 nwi_state_set_last(state
, nwi_af_list
[idx
]);
402 nwi_state_merge_removed(nwi_state_t state
, nwi_state_t old_state
)
407 /* Iterate through v4 and v6 list and annotate the diff flags */
408 for (idx
= 0; idx
< sizeof(nwi_af_list
)/sizeof(nwi_af_list
[0]); idx
++) {
409 scan
= nwi_state_get_first_ifstate(old_state
, nwi_af_list
[idx
]);
411 while (scan
!= NULL
) {
412 nwi_ifstate_t existing_ifstate
;
415 ifname
= nwi_ifstate_get_ifname(scan
);
417 existing_ifstate
= nwi_state_get_ifstate_with_name(state
, scan
->af
, ifname
);
419 /* Any elements that has not been added means that they are removed */
420 if (existing_ifstate
== NULL
) {
421 nwi_ifstate_t new_ifstate
= nwi_ifstate_append(state
, scan
);
422 nwi_ifstate_set_diff_str(new_ifstate
, deleted
);
424 scan
= nwi_ifstate_get_next(scan
, scan
->af
);
426 nwi_state_set_last(state
, nwi_af_list
[idx
]);
434 nwi_state_diff(nwi_state_t old_state
, nwi_state_t new_state
)
439 if (old_state
!= NULL
) {
440 total_count
= old_state
->ipv4_count
+ old_state
->ipv6_count
;
443 if (new_state
!= NULL
) {
444 total_count
+= new_state
->ipv4_count
+ new_state
->ipv6_count
;
447 if (total_count
== 0) {
451 diff
= nwi_state_new(NULL
, total_count
);
453 nwi_state_merge_added(diff
, old_state
, new_state
);
454 nwi_state_merge_removed(diff
, old_state
);
456 /* Diff consists of a nwi_state_t with annotated diff_ch's */