this repo has no description
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
42static void
43my_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
57typedef struct {
58 const void * obj;
59 int32_t retain_count;
60} ObjectWrapper, * ObjectWrapperRef;
61
62static const void *
63ObjectWrapperRetain(const void * info)
64{
65 ObjectWrapperRef wrapper = (ObjectWrapperRef)info;
66
67 (void)OSAtomicIncrement32(&wrapper->retain_count);
68 return (info);
69}
70
71static ObjectWrapperRef
72ObjectWrapperAllocate(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
82static void
83ObjectWrapperRelease(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
98static void
99ObjectWrapperSetObject(ObjectWrapperRef wrapper, const void * obj)
100{
101 wrapper->obj = obj;
102}
103
104static const void *
105ObjectWrapperGetObject(ObjectWrapperRef wrapper)
106{
107 return (wrapper->obj);
108}
109
110static SCDynamicStoreRef
111StoreObjectWrapperAllocate(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 **/
160static CFStringRef __SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf);
161static void __SCNetworkInterfaceProviderDeallocate(CFTypeRef cf);
162
163static CFTypeID __kSCNetworkInterfaceProviderTypeID = _kCFRuntimeNotATypeID;
164
165static 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
177struct __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
193static 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
207static void
208SCNetworkInterfaceProviderDeallocate(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
233static 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 **/
252static 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
266static 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
282static void
283SCNetworkInterfaceProviderCheck(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
304static void
305StoreHandleChanges(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 **/
325SCNetworkInterfaceProviderRef
326SCNetworkInterfaceProviderCreate(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
380void
381SCNetworkInterfaceProviderSetEventHandler(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
408void
409SCNetworkInterfaceProviderResume(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
438static void
439event_handler(SCNetworkInterfaceProviderRef provider,
440 SCNetworkInterfaceProviderEvent event,
441 CFDictionaryRef event_data)
442{
443 printf("<%p> event %d\n", provider, event);
444}
445
446int
447main(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