2 * Copyright (c) 2002-2007, 2011, 2013, 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@
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")
44 #ifndef kSCEntNetIPv6DuplicatedAddress
45 #define kSCEntNetIPv6DuplicatedAddress CFSTR("IPv6DuplicatedAddress")
46 #endif /* kSCEntNetIPv6DuplicatedAddress */
49 appendAddress(CFMutableDictionaryRef dict
, CFStringRef key
, struct sockaddr_in6
*sin6
)
53 CFMutableArrayRef newAddrs
;
54 char str
[INET6_ADDRSTRLEN
];
56 addrs
= CFDictionaryGetValue(dict
, key
);
58 newAddrs
= CFArrayCreateMutableCopy(NULL
, 0, addrs
);
60 newAddrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
63 if (inet_ntop(AF_INET6
, (const void *)&sin6
->sin6_addr
, str
, sizeof(str
)) == NULL
) {
64 SC_log(LOG_INFO
, "inet_ntop() failed: %s", strerror(errno
));
68 addr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%s"), str
);
69 CFArrayAppendValue(newAddrs
, addr
);
72 CFDictionarySetValue(dict
, key
, newAddrs
);
79 appendFlags(CFMutableDictionaryRef dict
, int flags6
)
82 CFMutableArrayRef newFlags
;
85 flags
= CFDictionaryGetValue(dict
, kSCPropNetIPv6Flags
);
87 newFlags
= CFArrayCreateMutableCopy(NULL
, 0, flags
);
89 newFlags
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
92 v6Flags
= CFNumberCreate(NULL
, kCFNumberIntType
, &flags6
);
93 CFArrayAppendValue(newFlags
, v6Flags
);
96 CFDictionarySetValue(dict
, kSCPropNetIPv6Flags
, newFlags
);
103 appendPrefixLen(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
105 register u_int8_t
*name
= &sin6
->sin6_addr
.s6_addr
[0];
106 CFNumberRef prefixLen
;
107 CFArrayRef prefixLens
;
108 CFMutableArrayRef newPrefixLens
;
114 for (byte
= 0; byte
< sizeof(struct in6_addr
); byte
++, plen
+= 8) {
115 if (name
[byte
] != 0xff) {
120 if (byte
== sizeof(struct in6_addr
)) {
124 for (bit
= 7; bit
!= 0; bit
--, plen
++) {
125 if (!(name
[byte
] & (1 << bit
))) {
130 for (; bit
!= 0; bit
--) {
131 if (name
[byte
] & (1 << bit
)) {
138 for (; byte
< sizeof(struct in6_addr
); byte
++) {
147 prefixLens
= CFDictionaryGetValue(dict
, kSCPropNetIPv6PrefixLength
);
149 newPrefixLens
= CFArrayCreateMutableCopy(NULL
, 0, prefixLens
);
151 newPrefixLens
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
154 prefixLen
= CFNumberCreate(NULL
, kCFNumberIntType
, &plen
);
155 CFArrayAppendValue(newPrefixLens
, prefixLen
);
156 CFRelease(prefixLen
);
158 CFDictionarySetValue(dict
, kSCPropNetIPv6PrefixLength
, newPrefixLens
);
159 CFRelease(newPrefixLens
);
166 appendScopeID(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
170 CFMutableArrayRef newScopes
;
172 scopes
= CFDictionaryGetValue(dict
, kSCPropNetIPv6ScopeID
);
174 newScopes
= CFArrayCreateMutableCopy(NULL
, 0, scopes
);
176 newScopes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
179 scope
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &sin6
->sin6_scope_id
);
180 CFArrayAppendValue(newScopes
, scope
);
183 CFDictionarySetValue(dict
, kSCPropNetIPv6ScopeID
, newScopes
);
184 CFRelease(newScopes
);
190 static CFMutableDictionaryRef
191 copyIF(CFStringRef key
, CFMutableDictionaryRef oldIFs
, CFMutableDictionaryRef newIFs
)
193 CFDictionaryRef dict
= NULL
;
194 CFMutableDictionaryRef newDict
= NULL
;
196 if (CFDictionaryGetValueIfPresent(newIFs
, key
, (const void **)&dict
)) {
197 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
199 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
201 CFDictionarySetValue(oldIFs
, key
, dict
);
202 if (isA_CFDictionary(dict
)) {
203 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
204 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Addresses
);
205 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6DestAddresses
);
206 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Flags
);
207 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6PrefixLength
);
209 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6ScopeID
);
217 newDict
= CFDictionaryCreateMutable(NULL
,
219 &kCFTypeDictionaryKeyCallBacks
,
220 &kCFTypeDictionaryValueCallBacks
);
228 updateStore(const void *key
, const void *value
, void *context
)
230 CFDictionaryRef dict
;
231 CFDictionaryRef newDict
= (CFDictionaryRef
)value
;
232 CFDictionaryRef oldIFs
= (CFDictionaryRef
)context
;
234 dict
= CFDictionaryGetValue(oldIFs
, key
);
236 if (!dict
|| !CFEqual(dict
, newDict
)) {
237 if (CFDictionaryGetCount(newDict
) > 0) {
238 SC_log(LOG_DEBUG
, "Update interface configuration: %@: %@", key
, newDict
);
239 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
241 SC_log(LOG_DEBUG
, "Update interface configuration: %@: <removed>", key
);
242 cache_SCDynamicStoreRemoveValue(store
, key
);
244 network_changed
= TRUE
;
253 interface_update_ipv6(struct ifaddrs
*ifap
, const char *if_name
)
256 struct ifaddrs
*ifap_temp
= NULL
;
257 CFStringRef interface
;
258 boolean_t interfaceFound
= FALSE
;
259 CFStringRef key
= NULL
;
260 CFMutableDictionaryRef oldIFs
;
261 CFMutableDictionaryRef newDict
= NULL
;
262 CFMutableDictionaryRef newIFs
;
265 oldIFs
= CFDictionaryCreateMutable(NULL
,
267 &kCFTypeDictionaryKeyCallBacks
,
268 &kCFTypeDictionaryValueCallBacks
);
269 newIFs
= CFDictionaryCreateMutable(NULL
,
271 &kCFTypeDictionaryKeyCallBacks
,
272 &kCFTypeDictionaryValueCallBacks
);
275 if (getifaddrs(&ifap_temp
) == -1) {
276 SC_log(LOG_NOTICE
, "getifaddrs() failed: %s", strerror(errno
));
282 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
283 struct in6_ifreq ifr6
;
284 #define flags6 ifr6.ifr_ifru.ifru_flags6
285 struct sockaddr_in6
*sin6
;
287 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
) {
288 continue; /* sorry, not interested */
291 /* check if this is the requested interface */
293 if (strncmp(if_name
, ifa
->ifa_name
, IFNAMSIZ
) == 0) {
294 interfaceFound
= TRUE
; /* yes, this is the one I want */
296 continue; /* sorry, not interested */
301 sock
= dgram_socket(AF_INET6
);
307 /* get the current cache information */
308 interface
= CFStringCreateWithCString(NULL
, ifa
->ifa_name
, kCFStringEncodingMacRoman
);
309 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
310 kSCDynamicStoreDomainState
,
313 CFRelease(interface
);
315 newDict
= copyIF(key
, oldIFs
, newIFs
);
317 /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
318 sin6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_addr
;
320 /* XXX: embedded link local addr check */
321 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6
->sin6_addr
)) {
324 index
= sin6
->sin6_addr
.s6_addr16
[1];
326 sin6
->sin6_addr
.s6_addr16
[1] = 0;
327 if (sin6
->sin6_scope_id
== 0) {
328 sin6
->sin6_scope_id
= ntohs(index
);
333 bzero((char *)&ifr6
, sizeof(ifr6
));
334 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
335 ifr6
.ifr_addr
= *sin6
;
336 if (ioctl(sock
, SIOCGIFAFLAG_IN6
, &ifr6
) == -1) {
337 /* if flags not available for this address */
338 SC_log((errno
!= EADDRNOTAVAIL
) ? LOG_NOTICE
: LOG_DEBUG
, "ioctl() failed: %s",
342 appendAddress (newDict
, kSCPropNetIPv6Addresses
, sin6
);
344 appendScopeID (newDict
, sin6
);
346 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
347 * appendPrefixLen expect byte alignment */
348 appendPrefixLen(newDict
, (struct sockaddr_in6
*)(void *)ifa
->ifa_netmask
);
349 appendFlags (newDict
, flags6
);
352 if (ifa
->ifa_flags
& IFF_POINTOPOINT
353 && ifa
->ifa_dstaddr
!= NULL
) {
354 struct sockaddr_in6
*dst6
;
356 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
357 dst6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_dstaddr
;
359 /* XXX: embedded link local addr check */
360 if (IN6_IS_ADDR_LINKLOCAL(&dst6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6
->sin6_addr
)) {
363 index
= dst6
->sin6_addr
.s6_addr16
[1];
365 dst6
->sin6_addr
.s6_addr16
[1] = 0;
366 if (dst6
->sin6_scope_id
== 0) {
367 dst6
->sin6_scope_id
= ntohs(index
);
372 appendAddress(newDict
, kSCPropNetIPv6DestAddresses
, dst6
);
375 CFDictionarySetValue(newIFs
, key
, newDict
);
380 /* if the last address[es] were removed from the target interface */
381 if (if_name
&& !interfaceFound
) {
382 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
383 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
384 kSCDynamicStoreDomainState
,
387 CFRelease(interface
);
389 newDict
= copyIF(key
, oldIFs
, newIFs
);
391 CFDictionarySetValue(newIFs
, key
, newDict
);
396 CFDictionaryApplyFunction(newIFs
, updateStore
, oldIFs
);
400 if (ifap_temp
) freeifaddrs(ifap_temp
);
401 if (sock
!= -1) close(sock
);
410 ipv6_duplicated_address(const char * if_name
, const struct in6_addr
* addr
,
411 int hw_len
, const void * hw_addr
)
413 uint8_t * hw_addr_bytes
= (uint8_t *)hw_addr
;
415 CFStringRef if_name_cf
;
416 CFMutableStringRef key
;
417 char ntopbuf
[INET6_ADDRSTRLEN
];
420 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
421 kCFStringEncodingASCII
);
422 prefix
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
423 kSCDynamicStoreDomainState
,
425 kSCEntNetIPv6DuplicatedAddress
);
427 (void)inet_ntop(AF_INET6
, addr
, ntopbuf
, sizeof(ntopbuf
));
428 key
= CFStringCreateMutableCopy(NULL
, 0, prefix
);
429 CFStringAppendFormat(key
, NULL
, CFSTR("/%s"), ntopbuf
);
430 for (i
= 0; i
< hw_len
; i
++) {
431 CFStringAppendFormat(key
, NULL
, CFSTR("%s%02x"),
432 (i
== 0) ? "/" : ":", hw_addr_bytes
[i
]);
434 cache_SCDynamicStoreNotifyValue(store
, key
);
437 CFRelease(if_name_cf
);