]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkInterfaceProvider.c
configd-1109.101.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkInterfaceProvider.c
1 /*
2 * Copyright (c) 2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * January 17, 2018 Dieter Siegmund (dieter@apple.com)
28 * - initial revision
29 */
30
31 /*
32 * SCNetworkInterfaceProvider.c
33 */
34
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <CoreFoundation/CFRuntime.h>
37 #include <libkern/OSAtomic.h>
38 #include "SCNetworkConfigurationPrivate.h"
39 #include "SCNetworkConfigurationInternal.h"
40 #include "SCNetworkInterfaceProvider.h"
41
42 static void
43 my_CFRelease(void * t)
44 {
45 void * * obj = (void * *)t;
46 if (obj && *obj) {
47 CFRelease(*obj);
48 *obj = NULL;
49 }
50 return;
51 }
52
53 /**
54 ** ObjectWrapper
55 **/
56
57 typedef struct {
58 const void * obj;
59 int32_t retain_count;
60 } ObjectWrapper, * ObjectWrapperRef;
61
62 static const void *
63 ObjectWrapperRetain(const void * info)
64 {
65 ObjectWrapperRef wrapper = (ObjectWrapperRef)info;
66
67 (void)OSAtomicIncrement32(&wrapper->retain_count);
68 return (info);
69 }
70
71 static ObjectWrapperRef
72 ObjectWrapperAllocate(const void * obj)
73 {
74 ObjectWrapperRef wrapper;
75
76 wrapper = (ObjectWrapperRef)malloc(sizeof(*wrapper));
77 wrapper->obj = obj;
78 wrapper->retain_count = 1;
79 return (wrapper);
80 }
81
82 static void
83 ObjectWrapperRelease(const void * info)
84 {
85 int32_t new_val;
86 ObjectWrapperRef wrapper = (ObjectWrapperRef)info;
87
88 new_val = OSAtomicDecrement32(&wrapper->retain_count);
89 if (new_val == 0) {
90 free(wrapper);
91 }
92 else {
93 assert(new_val > 0);
94 }
95 return;
96 }
97
98 static void
99 ObjectWrapperSetObject(ObjectWrapperRef wrapper, const void * obj)
100 {
101 wrapper->obj = obj;
102 }
103
104 static const void *
105 ObjectWrapperGetObject(ObjectWrapperRef wrapper)
106 {
107 return (wrapper->obj);
108 }
109
110 static SCDynamicStoreRef
111 StoreObjectWrapperAllocate(const void * obj,
112 CFStringRef name,
113 SCDynamicStoreCallBack handler,
114 CFArrayRef keys,
115 CFArrayRef patterns,
116 dispatch_queue_t queue,
117 ObjectWrapperRef * ret_wrapper)
118 {
119 SCDynamicStoreContext context = {
120 .version = 0,
121 .info = NULL,
122 .retain = ObjectWrapperRetain,
123 .release = ObjectWrapperRelease,
124 .copyDescription = NULL
125 };
126 SCDynamicStoreRef store;
127 ObjectWrapperRef wrapper;
128
129 wrapper = ObjectWrapperAllocate(obj);
130 context.info = wrapper;
131 store = SCDynamicStoreCreate(NULL, name, handler, &context);
132 if (store == NULL) {
133 SC_log(LOG_NOTICE,
134 "%@: SCDynamicStoreCreate failed", name);
135 }
136 else if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) {
137 SC_log(LOG_NOTICE,
138 "%@: SCDynamicStoreSetNoticationKeys failed", name);
139 CFRelease(store);
140 store = NULL;
141 }
142 else if (queue != NULL
143 && !SCDynamicStoreSetDispatchQueue(store, queue)) {
144 SC_log(LOG_NOTICE,
145 "%@: SCDynamicStoreSetDispatchQueue failed", name);
146 CFRelease(store);
147 store = NULL;
148 }
149 if (store == NULL) {
150 ObjectWrapperRelease(wrapper);
151 wrapper = NULL;
152 }
153 *ret_wrapper = wrapper;
154 return (store);
155 }
156
157 /**
158 ** CF object glue code
159 **/
160 static CFStringRef __SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf);
161 static void __SCNetworkInterfaceProviderDeallocate(CFTypeRef cf);
162
163 static CFTypeID __kSCNetworkInterfaceProviderTypeID = _kCFRuntimeNotATypeID;
164
165 static const CFRuntimeClass __SCNetworkInterfaceProviderClass = {
166 0, /* version */
167 "SCNetworkInterfaceProvider", /* className */
168 NULL, /* init */
169 NULL, /* copy */
170 __SCNetworkInterfaceProviderDeallocate, /* deallocate */
171 NULL, /* equal */
172 NULL, /* hash */
173 NULL, /* copyFormattingDesc */
174 __SCNetworkInterfaceProviderCopyDebugDesc /* copyDebugDesc */
175 };
176
177 struct __SCNetworkInterfaceProvider {
178 CFRuntimeBase cf_base;
179
180 IPMonitorControlRef control;
181 SCDynamicStoreRef store;
182 ObjectWrapperRef wrapper;
183 dispatch_queue_t queue;
184
185 SCNetworkInterfaceProviderEventHandler handler;
186 CFStringRef if_name;
187 SCNetworkInterfaceRef if_type;
188 Boolean enabled;
189 Boolean needed;
190 };
191
192
193 static CFStringRef
194 __SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf)
195 {
196 CFAllocatorRef allocator = CFGetAllocator(cf);
197 SCNetworkInterfaceProviderRef provider = (SCNetworkInterfaceProviderRef)cf;
198 CFMutableStringRef result;
199
200 result = CFStringCreateMutable(allocator, 0);
201 CFStringAppendFormat(result, NULL,
202 CFSTR("<SCNetworkInterfaceProvider %@ %@ <%p>"),
203 provider->if_type, provider->if_name, cf);
204 return (result);
205 }
206
207 static void
208 SCNetworkInterfaceProviderDeallocate(SCNetworkInterfaceProviderRef provider)
209 {
210 provider->enabled = FALSE;
211 my_CFRelease(&provider->control);
212 if (provider->wrapper != NULL) {
213 ObjectWrapperSetObject(provider->wrapper, NULL);
214 ObjectWrapperRelease(provider->wrapper);
215 provider->wrapper = NULL;
216 }
217 if (provider->store != NULL) {
218 SCDynamicStoreSetDispatchQueue(provider->store, NULL);
219 my_CFRelease(&provider->store);
220 }
221 if (provider->queue != NULL) {
222 dispatch_release(provider->queue);
223 provider->queue = NULL;
224 }
225 if (provider->handler != NULL) {
226 Block_release(provider->handler);
227 provider->handler = NULL;
228 }
229 my_CFRelease(&provider->if_name);
230 my_CFRelease(&provider->if_type);
231 }
232
233 static void
234 __SCNetworkInterfaceProviderDeallocate(CFTypeRef cf)
235 {
236 SCNetworkInterfaceProviderRef provider = (SCNetworkInterfaceProviderRef)cf;
237
238 if (provider->queue != NULL) {
239 dispatch_sync(provider->queue, ^{
240 SCNetworkInterfaceProviderDeallocate(provider);
241 });
242 }
243 else {
244 SCNetworkInterfaceProviderDeallocate(provider);
245 }
246 return;
247 }
248
249 /**
250 ** Supporting Functions
251 **/
252 static void
253 __SCNetworkInterfaceProviderRegisterClass(void)
254 {
255 static dispatch_once_t once;
256 dispatch_block_t once_block;
257
258 once_block = ^{
259 __kSCNetworkInterfaceProviderTypeID
260 = _CFRuntimeRegisterClass(&__SCNetworkInterfaceProviderClass);
261 };
262 dispatch_once(&once, once_block);
263 return;
264 }
265
266 static SCNetworkInterfaceProviderRef
267 __SCNetworkInterfaceProviderAllocate(CFAllocatorRef allocator)
268 {
269 SCNetworkInterfaceProviderRef provider;
270 int size;
271
272 __SCNetworkInterfaceProviderRegisterClass();
273 size = sizeof(*provider) - sizeof(CFRuntimeBase);
274 provider = (SCNetworkInterfaceProviderRef)
275 _CFRuntimeCreateInstance(allocator,
276 __kSCNetworkInterfaceProviderTypeID,
277 size, NULL);
278 memset(((void *)provider) + sizeof(CFRuntimeBase), 0, size);
279 return (provider);
280 }
281
282 static void
283 SCNetworkInterfaceProviderCheck(SCNetworkInterfaceProviderRef provider)
284 {
285 Boolean advisory_set;
286
287 if (!provider->enabled || provider->handler == NULL) {
288 return;
289 }
290 advisory_set
291 = IPMonitorControlAnyInterfaceAdvisoryIsSet(provider->control);
292 if (provider->needed != advisory_set) {
293 SCNetworkInterfaceProviderEvent event;
294
295 event = advisory_set
296 ? kSCNetworkInterfaceProviderEventActivationRequested
297 : kSCNetworkInterfaceProviderEventActivationNoLongerRequested;
298 (provider->handler)(event, NULL);
299 provider->needed = advisory_set;
300 }
301 return;
302 }
303
304 static void
305 StoreHandleChanges(SCDynamicStoreRef store, CFArrayRef changes, void * info)
306 {
307 #pragma unused(store)
308 #pragma unused(changes)
309 SCNetworkInterfaceProviderRef provider;
310 ObjectWrapperRef wrapper = (ObjectWrapperRef)info;
311
312 provider = (SCNetworkInterfaceProviderRef)ObjectWrapperGetObject(wrapper);
313 if (provider == NULL) {
314 /* provider has been deallocated */
315 return;
316 }
317 SCNetworkInterfaceProviderCheck(provider);
318 return;
319 }
320
321
322 /**
323 ** SCNetworkInterfaceProvider SPI
324 **/
325 SCNetworkInterfaceProviderRef
326 SCNetworkInterfaceProviderCreate(CFStringRef type,
327 CFStringRef ifname,
328 CFDictionaryRef options)
329 {
330 IPMonitorControlRef control;
331 CFStringRef pattern;
332 CFArrayRef patterns;
333 SCNetworkInterfaceProviderRef provider;
334 dispatch_queue_t queue;
335 SCDynamicStoreRef store = NULL;
336 ObjectWrapperRef wrapper = NULL;
337
338 if (options != NULL || ifname == NULL || type == NULL) {
339 _SCErrorSet(kSCStatusInvalidArgument);
340 return (NULL);
341 }
342 control = IPMonitorControlCreate();
343 if (control == NULL) {
344 _SCErrorSet(kSCStatusFailed);
345 return (NULL);
346 }
347 pattern
348 = IPMonitorControlCopyInterfaceAdvisoryNotificationKey(kSCCompAnyRegex);
349 patterns = CFArrayCreate(NULL, (const void * *)&pattern, 1,
350 &kCFTypeArrayCallBacks);
351 CFRelease(pattern);
352 #define OUR_NAME "SCNetworkInterfaceProvider"
353 queue = dispatch_queue_create(OUR_NAME, NULL);
354 provider = __SCNetworkInterfaceProviderAllocate(NULL);
355 store = StoreObjectWrapperAllocate(provider,
356 CFSTR(OUR_NAME),
357 StoreHandleChanges,
358 NULL,
359 patterns,
360 queue,
361 &wrapper);
362 CFRelease(patterns);
363 if (store == NULL) {
364 dispatch_release(queue);
365 CFRelease(provider);
366 provider = NULL;
367 CFRelease(control);
368 }
369 else {
370 provider->control = control;
371 provider->store = store;
372 provider->wrapper = wrapper;
373 provider->queue = queue;
374 provider->if_name = CFRetain(ifname);
375 provider->if_type = CFRetain(type);
376 }
377 return (provider);
378 }
379
380 void
381 SCNetworkInterfaceProviderSetEventHandler(SCNetworkInterfaceProviderRef provider,
382 SCNetworkInterfaceProviderEventHandler handler)
383 {
384 if (handler == NULL) {
385 /* can't clear handler once set */
386 return;
387 }
388 dispatch_sync(provider->queue, ^{
389 if (provider->enabled) {
390 /* enabling before setting the handler isn't allowed */
391 SC_log(LOG_NOTICE,
392 "%s: call SCNetworkInterfaceSetEventHandler before "
393 " SCNetworkInterfaceProviderResume", __FUNCTION__);
394 return;
395 }
396 if (provider->handler != NULL) {
397 /* can't change the handler once set */
398 SC_log(LOG_NOTICE,
399 "%s: ignoring second invocation of "
400 "SCNetworkInterfaceSetEventHandler", __FUNCTION__);
401 return;
402 }
403 provider->handler = Block_copy(handler);
404 });
405 return;
406 }
407
408 void
409 SCNetworkInterfaceProviderResume(SCNetworkInterfaceProviderRef provider)
410 {
411 dispatch_async(provider->queue, ^{
412 if (!provider->enabled) {
413 provider->enabled = TRUE;
414 SCNetworkInterfaceProviderCheck(provider);
415 }
416 });
417 return;
418 }
419
420 #if TEST_SCNetworkInterfaceProvider
421
422 /*
423 xcrun -sdk iphoneos.internal cc -o scnip SCNetworkInterfaceProvider.c -DTEST_SCNetworkInterfaceProvider -framework CoreFoundation -framework SystemConfiguration -arch arm64 -I ../IPMonitorControl ../IPMonitorControl/IPMonitorControl.c -DSC_LOG_HANDLE=__log_SCNetworkInterfaceProvider
424 */
425
426 __private_extern__ os_log_t
427 __log_SCNetworkInterfaceProvider(void)
428 {
429 static os_log_t log = NULL;
430
431 if (log == NULL) {
432 log = os_log_create("com.apple.SystemConfiguration", "SCNetworkConfiguration");
433 }
434
435 return log;
436 }
437
438 static void
439 event_handler(SCNetworkInterfaceProviderRef provider,
440 SCNetworkInterfaceProviderEvent event,
441 CFDictionaryRef event_data)
442 {
443 printf("<%p> event %d\n", provider, event);
444 }
445
446 int
447 main(int argc, char * argv[])
448 {
449 SCNetworkInterfaceProviderEventHandler handler;
450 SCNetworkInterfaceProviderRef provider;
451
452 provider
453 = SCNetworkInterfaceProviderCreate(kSCNetworkInterfaceTypeWWAN,
454 CFSTR("pdp_ip10"),
455 NULL);
456 if (provider == NULL) {
457 fprintf(stderr, "SCNetworkInterfaceProviderCreate failed\n");
458 exit(1);
459 }
460 handler = ^(SCNetworkInterfaceProviderEvent event,
461 CFDictionaryRef event_data) {
462 event_handler(provider, event, event_data);
463 };
464 SCNetworkInterfaceProviderSetEventHandler(provider, handler);
465 SCNetworkInterfaceProviderResume(provider);
466 dispatch_main();
467 exit(0);
468 return (0);
469 }
470 #endif