2 * Copyright (c) 2002-2007, 2011, 2013 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@
25 * Modification History
27 * August 5, 2002 Allan Nathanson <ajn@apple.com>
36 #define s6_addr16 __u6_addr.__u6_addr16
39 #ifndef kSCPropNetIPv6ScopeID
40 #define kSCPropNetIPv6ScopeID SCSTR("ScopeID")
46 appendAddress(CFMutableDictionaryRef dict
, CFStringRef key
, struct sockaddr_in6
*sin6
)
50 CFMutableArrayRef newAddrs
;
53 addrs
= CFDictionaryGetValue(dict
, key
);
55 newAddrs
= CFArrayCreateMutableCopy(NULL
, 0, addrs
);
57 newAddrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
60 if (inet_ntop(AF_INET6
, (const void *)&sin6
->sin6_addr
, str
, sizeof(str
)) == NULL
) {
61 SCLog(TRUE
, LOG_ERR
, CFSTR("inet_ntop() failed: %s"), strerror(errno
));
65 addr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%s"), str
);
66 CFArrayAppendValue(newAddrs
, addr
);
69 CFDictionarySetValue(dict
, key
, newAddrs
);
76 appendFlags(CFMutableDictionaryRef dict
, int flags6
)
79 CFMutableArrayRef newFlags
;
82 flags
= CFDictionaryGetValue(dict
, kSCPropNetIPv6Flags
);
84 newFlags
= CFArrayCreateMutableCopy(NULL
, 0, flags
);
86 newFlags
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
89 v6Flags
= CFNumberCreate(NULL
, kCFNumberIntType
, &flags6
);
90 CFArrayAppendValue(newFlags
, v6Flags
);
93 CFDictionarySetValue(dict
, kSCPropNetIPv6Flags
, newFlags
);
100 appendPrefixLen(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
102 register u_int8_t
*name
= &sin6
->sin6_addr
.s6_addr
[0];
103 CFNumberRef prefixLen
;
104 CFArrayRef prefixLens
;
105 CFMutableArrayRef newPrefixLens
;
111 for (byte
= 0; byte
< sizeof(struct in6_addr
); byte
++, plen
+= 8) {
112 if (name
[byte
] != 0xff) {
117 if (byte
== sizeof(struct in6_addr
)) {
121 for (bit
= 7; bit
!= 0; bit
--, plen
++) {
122 if (!(name
[byte
] & (1 << bit
))) {
127 for (; bit
!= 0; bit
--) {
128 if (name
[byte
] & (1 << bit
)) {
135 for (; byte
< sizeof(struct in6_addr
); byte
++) {
144 prefixLens
= CFDictionaryGetValue(dict
, kSCPropNetIPv6PrefixLength
);
146 newPrefixLens
= CFArrayCreateMutableCopy(NULL
, 0, prefixLens
);
148 newPrefixLens
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
151 prefixLen
= CFNumberCreate(NULL
, kCFNumberIntType
, &plen
);
152 CFArrayAppendValue(newPrefixLens
, prefixLen
);
153 CFRelease(prefixLen
);
155 CFDictionarySetValue(dict
, kSCPropNetIPv6PrefixLength
, newPrefixLens
);
156 CFRelease(newPrefixLens
);
163 appendScopeID(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
167 CFMutableArrayRef newScopes
;
169 scopes
= CFDictionaryGetValue(dict
, kSCPropNetIPv6ScopeID
);
171 newScopes
= CFArrayCreateMutableCopy(NULL
, 0, scopes
);
173 newScopes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
176 scope
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &sin6
->sin6_scope_id
);
177 CFArrayAppendValue(newScopes
, scope
);
180 CFDictionarySetValue(dict
, kSCPropNetIPv6ScopeID
, newScopes
);
181 CFRelease(newScopes
);
187 static CFMutableDictionaryRef
188 copyIF(CFStringRef key
, CFMutableDictionaryRef oldIFs
, CFMutableDictionaryRef newIFs
)
190 CFDictionaryRef dict
= NULL
;
191 CFMutableDictionaryRef newDict
= NULL
;
193 if (CFDictionaryGetValueIfPresent(newIFs
, key
, (const void **)&dict
)) {
194 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
196 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
198 CFDictionarySetValue(oldIFs
, key
, dict
);
199 if (isA_CFDictionary(dict
)) {
200 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
201 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Addresses
);
202 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6DestAddresses
);
203 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Flags
);
204 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6PrefixLength
);
206 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6ScopeID
);
214 newDict
= CFDictionaryCreateMutable(NULL
,
216 &kCFTypeDictionaryKeyCallBacks
,
217 &kCFTypeDictionaryValueCallBacks
);
225 updateStore(const void *key
, const void *value
, void *context
)
227 CFDictionaryRef dict
;
228 CFDictionaryRef newDict
= (CFDictionaryRef
)value
;
229 CFDictionaryRef oldIFs
= (CFDictionaryRef
)context
;
231 dict
= CFDictionaryGetValue(oldIFs
, key
);
233 if (!dict
|| !CFEqual(dict
, newDict
)) {
234 if (CFDictionaryGetCount(newDict
) > 0) {
235 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
237 cache_SCDynamicStoreRemoveValue(store
, key
);
239 network_changed
= TRUE
;
248 interface_update_ipv6(struct ifaddrs
*ifap
, const char *if_name
)
251 struct ifaddrs
*ifap_temp
= NULL
;
252 CFStringRef interface
;
253 boolean_t interfaceFound
= FALSE
;
254 CFStringRef key
= NULL
;
255 CFMutableDictionaryRef oldIFs
;
256 CFMutableDictionaryRef newDict
= NULL
;
257 CFMutableDictionaryRef newIFs
;
260 oldIFs
= CFDictionaryCreateMutable(NULL
,
262 &kCFTypeDictionaryKeyCallBacks
,
263 &kCFTypeDictionaryValueCallBacks
);
264 newIFs
= CFDictionaryCreateMutable(NULL
,
266 &kCFTypeDictionaryKeyCallBacks
,
267 &kCFTypeDictionaryValueCallBacks
);
270 if (getifaddrs(&ifap_temp
) == -1) {
271 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
277 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
278 struct in6_ifreq ifr6
;
279 #define flags6 ifr6.ifr_ifru.ifru_flags6
280 struct sockaddr_in6
*sin6
;
282 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
) {
283 continue; /* sorry, not interested */
286 /* check if this is the requested interface */
288 if (strncmp(if_name
, ifa
->ifa_name
, IFNAMSIZ
) == 0) {
289 interfaceFound
= TRUE
; /* yes, this is the one I want */
291 continue; /* sorry, not interested */
296 sock
= dgram_socket(AF_INET6
);
298 SCLog(TRUE
, LOG_NOTICE
, CFSTR("interface_update_ipv6: socket open failed, %s"), strerror(errno
));
303 /* get the current cache information */
304 interface
= CFStringCreateWithCString(NULL
, ifa
->ifa_name
, kCFStringEncodingMacRoman
);
305 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
306 kSCDynamicStoreDomainState
,
309 CFRelease(interface
);
311 newDict
= copyIF(key
, oldIFs
, newIFs
);
313 /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
314 sin6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_addr
;
316 /* XXX: embedded link local addr check */
317 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6
->sin6_addr
)) {
320 index
= sin6
->sin6_addr
.s6_addr16
[1];
322 sin6
->sin6_addr
.s6_addr16
[1] = 0;
323 if (sin6
->sin6_scope_id
== 0) {
324 sin6
->sin6_scope_id
= ntohs(index
);
329 bzero((char *)&ifr6
, sizeof(ifr6
));
330 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
331 ifr6
.ifr_addr
= *sin6
;
332 if (ioctl(sock
, SIOCGIFAFLAG_IN6
, &ifr6
) == -1) {
333 /* if flags not available for this address */
335 (errno
!= EADDRNOTAVAIL
) ? LOG_NOTICE
: LOG_DEBUG
,
336 CFSTR("interface_update_ipv6: ioctl failed, %s"),
340 appendAddress (newDict
, kSCPropNetIPv6Addresses
, sin6
);
342 appendScopeID (newDict
, sin6
);
344 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
345 * appendPrefixLen expect byte alignment */
346 appendPrefixLen(newDict
, (struct sockaddr_in6
*)(void *)ifa
->ifa_netmask
);
347 appendFlags (newDict
, flags6
);
350 if (ifa
->ifa_flags
& IFF_POINTOPOINT
351 && ifa
->ifa_dstaddr
!= NULL
) {
352 struct sockaddr_in6
*dst6
;
354 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
355 dst6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_dstaddr
;
357 /* XXX: embedded link local addr check */
358 if (IN6_IS_ADDR_LINKLOCAL(&dst6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6
->sin6_addr
)) {
361 index
= dst6
->sin6_addr
.s6_addr16
[1];
363 dst6
->sin6_addr
.s6_addr16
[1] = 0;
364 if (dst6
->sin6_scope_id
== 0) {
365 dst6
->sin6_scope_id
= ntohs(index
);
370 appendAddress(newDict
, kSCPropNetIPv6DestAddresses
, dst6
);
373 CFDictionarySetValue(newIFs
, key
, newDict
);
378 /* if the last address[es] were removed from the target interface */
379 if (if_name
&& !interfaceFound
) {
380 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
381 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
382 kSCDynamicStoreDomainState
,
385 CFRelease(interface
);
387 newDict
= copyIF(key
, oldIFs
, newIFs
);
389 CFDictionarySetValue(newIFs
, key
, newDict
);
394 CFDictionaryApplyFunction(newIFs
, updateStore
, oldIFs
);
398 if (ifap_temp
) freeifaddrs(ifap_temp
);
399 if (sock
!= -1) close(sock
);