]> git.saurik.com Git - apple/configd.git/blob - IPMonitorControl/IPMonitorControl.c
configd-963.200.27.tar.gz
[apple/configd.git] / IPMonitorControl / IPMonitorControl.c
1 /*
2 * Copyright (c) 2013-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 * IPMonitorControl.c
26 * - IPC channel to IPMonitor
27 * - used to create interface rank assertions
28 */
29
30 /*
31 * Modification History
32 *
33 * December 16, 2013 Dieter Siegmund (dieter@apple.com)
34 * - initial revision
35 */
36
37 #include "IPMonitorControl.h"
38 #include "IPMonitorControlPrivate.h"
39 #include "symbol_scope.h"
40 #include <CoreFoundation/CFRuntime.h>
41 #include <net/if.h>
42 #include <xpc/xpc.h>
43 #include <xpc/private.h>
44 #include <SystemConfiguration/SCPrivate.h>
45
46 #ifdef TEST_IPMONITOR_CONTROL
47
48 #define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
49
50 #else /* TEST_IPMONITOR_CONTROL */
51
52 #define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__)
53
54 #endif /* TEST_IPMONITOR_CONTROL */
55
56 /**
57 ** IPMonitorControl CF object glue
58 **/
59
60 struct IPMonitorControl {
61 CFRuntimeBase cf_base;
62
63 dispatch_queue_t queue;
64 xpc_connection_t connection;
65
66 CFMutableDictionaryRef assertions; /* ifname<string> = rank<number> */
67 CFMutableDictionaryRef advisories; /* ifname<string> = adv<number> */
68 };
69
70 STATIC CFStringRef __IPMonitorControlCopyDebugDesc(CFTypeRef cf);
71 STATIC void __IPMonitorControlDeallocate(CFTypeRef cf);
72
73 STATIC CFTypeID __kIPMonitorControlTypeID = _kCFRuntimeNotATypeID;
74
75 STATIC const CFRuntimeClass __IPMonitorControlClass = {
76 0, /* version */
77 "IPMonitorControl", /* className */
78 NULL, /* init */
79 NULL, /* copy */
80 __IPMonitorControlDeallocate, /* deallocate */
81 NULL, /* equal */
82 NULL, /* hash */
83 NULL, /* copyFormattingDesc */
84 __IPMonitorControlCopyDebugDesc /* copyDebugDesc */
85 };
86
87 STATIC CFStringRef
88 __IPMonitorControlCopyDebugDesc(CFTypeRef cf)
89 {
90 CFAllocatorRef allocator = CFGetAllocator(cf);
91 IPMonitorControlRef control = (IPMonitorControlRef)cf;
92
93 return (CFStringCreateWithFormat(allocator, NULL,
94 CFSTR("<IPMonitorControl %p>"),
95 control));
96 }
97
98 STATIC void
99 __IPMonitorControlDeallocate(CFTypeRef cf)
100 {
101 IPMonitorControlRef control = (IPMonitorControlRef)cf;
102
103 if (control->connection != NULL) {
104 xpc_release(control->connection);
105 }
106 if (control->queue != NULL) {
107 dispatch_release(control->queue);
108 }
109 my_CFRelease(&control->advisories);
110 my_CFRelease(&control->assertions);
111 return;
112 }
113
114 /**
115 ** IPMonitorControl support functions
116 **/
117 STATIC void
118 __IPMonitorControlRegisterClass(void)
119 {
120 STATIC dispatch_once_t once;
121
122 dispatch_once(&once, ^{
123 __kIPMonitorControlTypeID
124 = _CFRuntimeRegisterClass(&__IPMonitorControlClass);
125 });
126 return;
127 }
128
129 STATIC IPMonitorControlRef
130 __IPMonitorControlAllocate(CFAllocatorRef allocator)
131 {
132 IPMonitorControlRef control;
133 int size;
134
135 __IPMonitorControlRegisterClass();
136 size = sizeof(*control) - sizeof(CFRuntimeBase);
137 control = (IPMonitorControlRef)
138 _CFRuntimeCreateInstance(allocator,
139 __kIPMonitorControlTypeID, size, NULL);
140 return (control);
141 }
142
143 STATIC xpc_object_t
144 create_request_dictionary(void)
145 {
146 const char * progname;
147 xpc_object_t request;
148
149 request = xpc_dictionary_create(NULL, NULL, 0);
150 progname = getprogname();
151 if (progname != NULL) {
152 xpc_dictionary_set_string(request,
153 kIPMonitorControlRequestKeyProcessName,
154 progname);
155 }
156 return (request);
157 }
158
159 STATIC Boolean
160 IPMonitorControlHandleResponse(xpc_object_t event, Boolean async,
161 Boolean * retry_p)
162 {
163 Boolean retry = FALSE;
164 Boolean success = FALSE;
165 xpc_type_t type;
166
167 type = xpc_get_type(event);
168 if (type == XPC_TYPE_DICTIONARY) {
169 if (async) {
170 /* we don't expect async responses messages */
171 my_log(LOG_NOTICE, "unexpected message");
172 }
173 else {
174 int64_t error;
175
176 error = xpc_dictionary_get_int64(event,
177 kIPMonitorControlResponseKeyError);
178 if (error != 0) {
179 success = FALSE;
180 #ifdef TEST_IPMONITOR_CONTROL
181 my_log(LOG_NOTICE, "failure code %lld", error);
182 #endif /* TEST_IPMONITOR_CONTROL */
183 }
184 else {
185 success = TRUE;
186 }
187 }
188 }
189 else if (type == XPC_TYPE_ERROR) {
190 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
191 #ifdef TEST_IPMONITOR_CONTROL
192 my_log(LOG_NOTICE, "can retry");
193 #endif /* TEST_IPMONITOR_CONTROL */
194 retry = TRUE;
195 }
196 else {
197 const char * desc;
198
199 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
200 my_log(LOG_NOTICE, "%s", desc);
201 }
202 }
203 else {
204 my_log(LOG_NOTICE, "unknown event type : %p", type);
205 }
206 if (retry_p != NULL) {
207 *retry_p = retry;
208 }
209 return (success);
210 }
211
212
213 STATIC void
214 _IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control,
215 CFStringRef ifname_cf,
216 SCNetworkServicePrimaryRank rank)
217 {
218 if (control->assertions == NULL) {
219 if (rank == kSCNetworkServicePrimaryRankDefault) {
220 /* no assertions, no need to store rank */
221 return;
222 }
223 control->assertions
224 = CFDictionaryCreateMutable(NULL, 0,
225 &kCFTypeDictionaryKeyCallBacks,
226 &kCFTypeDictionaryValueCallBacks);
227 }
228 if (rank == kSCNetworkServicePrimaryRankDefault) {
229 CFDictionaryRemoveValue(control->assertions, ifname_cf);
230 if (CFDictionaryGetCount(control->assertions) == 0) {
231 my_CFRelease(&control->assertions);
232 }
233 }
234 else {
235 CFNumberRef rank_cf;
236
237 rank_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank);
238 CFDictionarySetValue(control->assertions, ifname_cf, rank_cf);
239 CFRelease(rank_cf);
240 }
241 return;
242 }
243
244 STATIC void
245 ApplyInterfaceRank(const void * key, const void * value, void * context)
246 {
247 xpc_connection_t connection = (xpc_connection_t)context;
248 char ifname[IF_NAMESIZE];
249 SCNetworkServicePrimaryRank rank;
250 xpc_object_t request;
251
252 if (!CFStringGetCString(key, ifname, sizeof(ifname),
253 kCFStringEncodingUTF8)) {
254 return;
255 }
256 if (!CFNumberGetValue(value, kCFNumberSInt32Type, &rank)) {
257 return;
258 }
259 request = create_request_dictionary();
260 xpc_dictionary_set_uint64(request,
261 kIPMonitorControlRequestKeyType,
262 kIPMonitorControlRequestTypeSetInterfaceRank);
263 xpc_dictionary_set_string(request,
264 kIPMonitorControlRequestKeyInterfaceName,
265 ifname);
266 xpc_dictionary_set_uint64(request,
267 kIPMonitorControlRequestKeyPrimaryRank,
268 rank);
269 xpc_connection_send_message(connection, request);
270 xpc_release(request);
271 return;
272 }
273
274
275 STATIC void
276 _IPMonitorControlSetInterfaceAdvisory(IPMonitorControlRef control,
277 CFStringRef ifname_cf,
278 SCNetworkInterfaceAdvisory advisory)
279 {
280 if (control->advisories == NULL) {
281 if (advisory == kSCNetworkInterfaceAdvisoryNone) {
282 /* no advisories, no need to store advisory */
283 return;
284 }
285 control->advisories
286 = CFDictionaryCreateMutable(NULL, 0,
287 &kCFTypeDictionaryKeyCallBacks,
288 &kCFTypeDictionaryValueCallBacks);
289 }
290 if (advisory == kSCNetworkInterfaceAdvisoryNone) {
291 CFDictionaryRemoveValue(control->advisories, ifname_cf);
292 if (CFDictionaryGetCount(control->advisories) == 0) {
293 my_CFRelease(&control->advisories);
294 }
295 }
296 else {
297 CFNumberRef advisory_cf;
298
299 advisory_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &advisory);
300 CFDictionarySetValue(control->advisories, ifname_cf, advisory_cf);
301 CFRelease(advisory_cf);
302 }
303 return;
304 }
305
306 STATIC void
307 ApplyInterfaceAdvisory(const void * key, const void * value, void * context)
308 {
309 xpc_connection_t connection = (xpc_connection_t)context;
310 char ifname[IF_NAMESIZE];
311 SCNetworkInterfaceAdvisory advisory;
312 xpc_object_t request;
313
314 if (!CFStringGetCString(key, ifname, sizeof(ifname),
315 kCFStringEncodingUTF8)) {
316 return;
317 }
318 if (!CFNumberGetValue(value, kCFNumberSInt32Type, &advisory)) {
319 return;
320 }
321 request = create_request_dictionary();
322 xpc_dictionary_set_uint64(request,
323 kIPMonitorControlRequestKeyType,
324 kIPMonitorControlRequestTypeSetInterfaceAdvisory);
325 xpc_dictionary_set_string(request,
326 kIPMonitorControlRequestKeyInterfaceName,
327 ifname);
328 xpc_dictionary_set_uint64(request,
329 kIPMonitorControlRequestKeyAdvisory,
330 advisory);
331 xpc_connection_send_message(connection, request);
332 xpc_release(request);
333 return;
334 }
335
336
337 /**
338 ** IPMonitorControl SPI
339 **/
340 PRIVATE_EXTERN IPMonitorControlRef
341 IPMonitorControlCreate(void)
342 {
343 xpc_connection_t connection;
344 IPMonitorControlRef control;
345 uint64_t flags = XPC_CONNECTION_MACH_SERVICE_PRIVILEGED;
346 xpc_handler_t handler;
347 dispatch_queue_t queue;
348
349 control = __IPMonitorControlAllocate(NULL);
350 queue = dispatch_queue_create("IPMonitorControl", NULL);
351 connection
352 = xpc_connection_create_mach_service(kIPMonitorControlServerName,
353 queue, flags);
354 handler = ^(xpc_object_t event) {
355 Boolean retry;
356
357 (void)IPMonitorControlHandleResponse(event, TRUE, &retry);
358 if (retry) {
359 if (control->assertions != NULL) {
360 CFDictionaryApplyFunction(control->assertions,
361 ApplyInterfaceRank,
362 control->connection);
363 }
364 if (control->advisories != NULL) {
365 CFDictionaryApplyFunction(control->advisories,
366 ApplyInterfaceAdvisory,
367 control->connection);
368 }
369 }
370 };
371 xpc_connection_set_event_handler(connection, handler);
372 control->connection = connection;
373 control->queue = queue;
374 xpc_connection_resume(connection);
375 return (control);
376 }
377
378 STATIC xpc_object_t
379 IPMonitorControlSendRequest(IPMonitorControlRef control,
380 xpc_object_t request)
381 {
382 xpc_object_t reply;
383
384 while (TRUE) {
385 Boolean retry_on_error = FALSE;
386 Boolean success;
387
388 reply = xpc_connection_send_message_with_reply_sync(control->connection,
389 request);
390 if (reply == NULL) {
391 my_log(LOG_NOTICE, "failed to send message");
392 break;
393 }
394 success = IPMonitorControlHandleResponse(reply, FALSE,
395 &retry_on_error);
396 if (success) {
397 break;
398 }
399 xpc_release(reply);
400 reply = NULL;
401 if (retry_on_error) {
402 continue;
403 }
404 my_log(LOG_NOTICE, "fatal error");
405 break;
406 }
407 return (reply);
408 }
409
410 PRIVATE_EXTERN Boolean
411 IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control,
412 CFStringRef ifname_cf,
413 SCNetworkServicePrimaryRank rank)
414 {
415 char ifname[IF_NAMESIZE];
416 xpc_object_t reply;
417 xpc_object_t request;
418 Boolean success = FALSE;
419
420 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname),
421 kCFStringEncodingUTF8)) {
422 return (FALSE);
423 }
424
425 request = create_request_dictionary();
426 xpc_dictionary_set_uint64(request,
427 kIPMonitorControlRequestKeyType,
428 kIPMonitorControlRequestTypeSetInterfaceRank);
429 xpc_dictionary_set_string(request,
430 kIPMonitorControlRequestKeyInterfaceName,
431 ifname);
432 xpc_dictionary_set_uint64(request,
433 kIPMonitorControlRequestKeyPrimaryRank,
434 rank);
435 reply = IPMonitorControlSendRequest(control, request);
436 xpc_release(request);
437 if (reply != NULL) {
438 success = TRUE;
439 xpc_release(reply);
440
441 /* sync our state */
442 CFRetain(ifname_cf);
443 CFRetain(control);
444 dispatch_async(control->queue,
445 ^{
446 _IPMonitorControlSetInterfacePrimaryRank(control,
447 ifname_cf,
448 rank);
449 CFRelease(ifname_cf);
450 CFRelease(control);
451 });
452 }
453 return (success);
454 }
455
456 PRIVATE_EXTERN SCNetworkServicePrimaryRank
457 IPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control,
458 CFStringRef ifname_cf)
459 {
460 char ifname[IF_NAMESIZE];
461 SCNetworkServicePrimaryRank rank;
462 xpc_object_t reply;
463 xpc_object_t request;
464
465 rank = kSCNetworkServicePrimaryRankDefault;
466 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname),
467 kCFStringEncodingUTF8)) {
468 return rank;
469 }
470
471 request = create_request_dictionary();
472 xpc_dictionary_set_uint64(request,
473 kIPMonitorControlRequestKeyType,
474 kIPMonitorControlRequestTypeGetInterfaceRank);
475 xpc_dictionary_set_string(request,
476 kIPMonitorControlRequestKeyInterfaceName,
477 ifname);
478 reply = IPMonitorControlSendRequest(control, request);
479 if (reply != NULL) {
480 rank = (SCNetworkServicePrimaryRank)
481 xpc_dictionary_get_uint64(reply,
482 kIPMonitorControlResponseKeyPrimaryRank);
483 xpc_release(reply);
484 }
485 xpc_release(request);
486 return (rank);
487 }
488
489 PRIVATE_EXTERN Boolean
490 IPMonitorControlSetInterfaceAdvisory(IPMonitorControlRef control,
491 CFStringRef ifname_cf,
492 SCNetworkInterfaceAdvisory advisory,
493 CFStringRef reason)
494 {
495 char ifname[IF_NAMESIZE];
496 char * reason_str = NULL;
497 xpc_object_t reply;
498 xpc_object_t request;
499 Boolean success = FALSE;
500
501 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname),
502 kCFStringEncodingUTF8)) {
503 return (FALSE);
504 }
505 if (reason != NULL) {
506 reason_str
507 = _SC_cfstring_to_cstring(reason, NULL, 0, kCFStringEncodingUTF8);
508 }
509 request = create_request_dictionary();
510 xpc_dictionary_set_uint64(request,
511 kIPMonitorControlRequestKeyType,
512 kIPMonitorControlRequestTypeSetInterfaceAdvisory);
513 xpc_dictionary_set_string(request,
514 kIPMonitorControlRequestKeyInterfaceName,
515 ifname);
516 xpc_dictionary_set_uint64(request,
517 kIPMonitorControlRequestKeyAdvisory,
518 advisory);
519 if (reason_str != NULL) {
520 xpc_dictionary_set_string(request,
521 kIPMonitorControlRequestKeyReason,
522 reason_str);
523 CFAllocatorDeallocate(NULL, reason_str);
524 }
525 reply = IPMonitorControlSendRequest(control, request);
526 xpc_release(request);
527 if (reply != NULL) {
528 xpc_release(reply);
529 success = TRUE;
530
531 /* sync our state */
532 CFRetain(ifname_cf);
533 CFRetain(control);
534 dispatch_async(control->queue,
535 ^{
536 _IPMonitorControlSetInterfaceAdvisory(control,
537 ifname_cf,
538 advisory);
539 CFRelease(ifname_cf);
540 CFRelease(control);
541 });
542 }
543 return (success);
544 }
545
546 PRIVATE_EXTERN Boolean
547 IPMonitorControlInterfaceAdvisoryIsSet(IPMonitorControlRef control,
548 CFStringRef ifname_cf)
549 {
550 char ifname[IF_NAMESIZE];
551 xpc_object_t reply;
552 xpc_object_t request;
553 Boolean is_set = FALSE;
554
555 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname),
556 kCFStringEncodingUTF8)) {
557 return (FALSE);
558 }
559 request = create_request_dictionary();
560 xpc_dictionary_set_uint64(request,
561 kIPMonitorControlRequestKeyType,
562 kIPMonitorControlRequestTypeInterfaceAdvisoryIsSet);
563 xpc_dictionary_set_string(request,
564 kIPMonitorControlRequestKeyInterfaceName,
565 ifname);
566 reply = IPMonitorControlSendRequest(control, request);
567 xpc_release(request);
568 if (reply != NULL) {
569 if (xpc_dictionary_get_bool(reply,
570 kIPMonitorControlResponseKeyAdvisoryIsSet)) {
571 is_set = TRUE;
572 }
573 xpc_release(reply);
574 }
575 return (is_set);
576 }
577
578 PRIVATE_EXTERN Boolean
579 IPMonitorControlAnyInterfaceAdvisoryIsSet(IPMonitorControlRef control)
580 {
581 xpc_object_t reply;
582 xpc_object_t request;
583 Boolean is_set = FALSE;
584
585 request = create_request_dictionary();
586 xpc_dictionary_set_uint64(request,
587 kIPMonitorControlRequestKeyType,
588 kIPMonitorControlRequestTypeAnyInterfaceAdvisoryIsSet);
589 reply = IPMonitorControlSendRequest(control, request);
590 xpc_release(request);
591 if (reply != NULL) {
592 if (xpc_dictionary_get_bool(reply,
593 kIPMonitorControlResponseKeyAdvisoryIsSet)) {
594 is_set = TRUE;
595 }
596 xpc_release(reply);
597 }
598 return (is_set);
599 }
600
601 PRIVATE_EXTERN CFStringRef
602 IPMonitorControlCopyInterfaceAdvisoryNotificationKey(CFStringRef ifname)
603 {
604 return (_IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifname));
605 }