2 * Copyright (c) 2010-2011 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 * March 1, 2010 Christophe Allie <callie@apple.com>
29 * February 8, 2011 Kevin Wells <kcw@apple.com>
30 * - added "select" command
41 static SCNetworkConnectionRef connectionRef
= NULL
;
42 static int n_callback
= 0;
45 /* -----------------------------------------------------------------------------
46 ----------------------------------------------------------------------------- */
50 void * * obj
= (void * *)t
;
58 /* -----------------------------------------------------------------------------
59 ----------------------------------------------------------------------------- */
61 nc_copy_serviceID(int argc
, char **argv
)
63 CFStringRef serviceIDRef
= NULL
;
66 serviceIDRef
= _copyStringFromSTDIN();
68 serviceIDRef
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
74 /* -----------------------------------------------------------------------------
75 ----------------------------------------------------------------------------- */
76 static SCNetworkServiceRef
77 nc_copy_service(SCNetworkSetRef set
, CFStringRef identifier
)
81 SCNetworkServiceRef selected
= NULL
;
84 services
= SCNetworkConnectionCopyAvailableServices(set
);
85 if (services
== NULL
) {
89 n
= CFArrayGetCount(services
);
91 // try to select the service by its serviceID
92 for (i
= 0; i
< n
; i
++) {
93 SCNetworkServiceRef service
= NULL
;
94 CFStringRef serviceID
;
96 service
= CFArrayGetValueAtIndex(services
, i
);
97 serviceID
= SCNetworkServiceGetServiceID(service
);
98 if (CFEqual(identifier
, serviceID
)) {
104 // try to select the service by service name
105 for (i
= 0; i
< n
; i
++) {
106 SCNetworkServiceRef service
= NULL
;
107 CFStringRef serviceName
;
109 service
= CFArrayGetValueAtIndex(services
, i
);
110 serviceName
= SCNetworkServiceGetName(service
);
111 if ((serviceName
!= NULL
) && CFEqual(identifier
, serviceName
)) {
112 if (selected
== NULL
) {
115 // if multiple services match
117 SCPrint(TRUE
, stdout
, CFSTR("multiple services match\n"));
125 if (selected
!= NULL
) CFRetain(selected
);
126 if (services
!= NULL
) CFRelease(services
);
131 /* -----------------------------------------------------------------------------
132 ----------------------------------------------------------------------------- */
134 nc_status_string(SCNetworkConnectionStatus status
)
137 case kSCNetworkConnectionInvalid
:
139 case kSCNetworkConnectionDisconnected
:
140 return "Disconnected";
141 case kSCNetworkConnectionConnecting
:
143 case kSCNetworkConnectionConnected
:
145 case kSCNetworkConnectionDisconnecting
:
146 return "Disconnecting";
152 nc_callback(SCNetworkConnectionRef connection
, SCNetworkConnectionStatus status
, void *info
)
154 int *n
= (int *)info
;
155 CFDictionaryRef status_dict
;
160 SCPrint(TRUE
, stdout
, CFSTR("Current status = "));
163 struct timeval tv_now
;
165 (void)gettimeofday(&tv_now
, NULL
);
166 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
168 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
172 tv_now
.tv_usec
/ 1000);
173 SCPrint(TRUE
, stdout
, CFSTR("Callback (%d) status = "), *n
);
177 SCPrint(TRUE
, stdout
, CFSTR("%s%s%s\n"),
178 nc_status_string(status
),
179 (status
== kSCNetworkConnectionInvalid
) ? ": " : "",
180 (status
== kSCNetworkConnectionInvalid
) ? SCErrorString(SCError()) : "");
182 // report extended status
183 status_dict
= SCNetworkConnectionCopyExtendedStatus(connection
);
185 SCPrint(TRUE
, stdout
, CFSTR("Extended Status %@\n"), status_dict
);
186 CFRelease(status_dict
);
193 nc_create_connection(int argc
, char **argv
, Boolean exit_on_failure
)
195 SCNetworkConnectionContext context
= { 0, &n_callback
, NULL
, NULL
, NULL
};
196 SCNetworkServiceRef service
;
197 CFStringRef serviceIDRef
;
199 serviceIDRef
= nc_copy_serviceID(argc
, argv
);
200 if (serviceIDRef
== NULL
) {
201 SCPrint(TRUE
, stderr
, CFSTR("No service identifier\n"));
207 service
= nc_copy_service(NULL
, serviceIDRef
);
208 CFRelease(serviceIDRef
);
209 if (service
== NULL
) {
210 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
216 connectionRef
= SCNetworkConnectionCreateWithService(NULL
, service
, nc_callback
, &context
);
217 if (connectionRef
== NULL
) {
218 SCPrint(TRUE
, stderr
, CFSTR("nc_create_connection SCNetworkConnectionCreateWithServiceID() failed to create connectionRef: %s\n"), SCErrorString(SCError()));
225 /* -----------------------------------------------------------------------------
226 ----------------------------------------------------------------------------- */
228 nc_release_connection()
230 my_CFRelease(&connectionRef
);
233 /* -----------------------------------------------------------------------------
234 ----------------------------------------------------------------------------- */
236 nc_start(int argc
, char **argv
)
238 nc_create_connection(argc
, argv
, TRUE
);
240 SCNetworkConnectionStart(connectionRef
, 0, TRUE
);
242 nc_release_connection();
246 /* -----------------------------------------------------------------------------
247 ----------------------------------------------------------------------------- */
249 nc_stop(int argc
, char **argv
)
251 nc_create_connection(argc
, argv
, TRUE
);
253 SCNetworkConnectionStop(connectionRef
, TRUE
);
255 nc_release_connection();
259 /* -----------------------------------------------------------------------------
260 ----------------------------------------------------------------------------- */
262 nc_suspend(int argc
, char **argv
)
264 nc_create_connection(argc
, argv
, TRUE
);
266 SCNetworkConnectionSuspend(connectionRef
);
268 nc_release_connection();
272 /* -----------------------------------------------------------------------------
273 ----------------------------------------------------------------------------- */
275 nc_resume(int argc
, char **argv
)
277 nc_create_connection(argc
, argv
, TRUE
);
279 SCNetworkConnectionResume(connectionRef
);
281 nc_release_connection();
285 /* -----------------------------------------------------------------------------
286 ----------------------------------------------------------------------------- */
288 nc_status(int argc
, char **argv
)
290 SCNetworkConnectionStatus status
;
292 nc_create_connection(argc
, argv
, TRUE
);
294 status
= SCNetworkConnectionGetStatus(connectionRef
);
295 nc_callback(connectionRef
, status
, NULL
);
297 nc_release_connection();
302 nc_watch(int argc
, char **argv
)
304 SCNetworkConnectionStatus status
;
306 nc_create_connection(argc
, argv
, TRUE
);
308 status
= SCNetworkConnectionGetStatus(connectionRef
);
310 // report initial status
312 nc_callback(connectionRef
, status
, &n_callback
);
316 if (!SCNetworkConnectionSetDispatchQueue(connectionRef
, dispatch_get_current_queue())) {
317 printf("SCNetworkConnectionSetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
321 if (!SCNetworkConnectionScheduleWithRunLoop(connectionRef
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
322 printf("SCNetworkConnectinScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
330 nc_release_connection();
334 /* -----------------------------------------------------------------------------
335 ----------------------------------------------------------------------------- */
337 nc_statistics(int argc
, char **argv
)
339 CFDictionaryRef stats_dict
;
341 nc_create_connection(argc
, argv
, TRUE
);
343 stats_dict
= SCNetworkConnectionCopyStatistics(connectionRef
);
346 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), stats_dict
);
348 SCPrint(TRUE
, stdout
, CFSTR("No statistics available\n"));
351 my_CFRelease(&stats_dict
);
353 nc_release_connection();
357 /* -----------------------------------------------------------------------------
358 ----------------------------------------------------------------------------- */
360 nc_ondemand(int argc
, char **argv
)
363 CFStringRef key
= NULL
;
364 CFDictionaryRef ondemand_dict
= NULL
;
365 SCDynamicStoreRef store
;
367 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), NULL
, NULL
);
369 SCPrint(TRUE
, stderr
, CFSTR("do_nc_ondemand SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
373 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetOnDemand
);
375 SCPrint(TRUE
, stderr
, CFSTR("do_nc_ondemand SCDynamicStoreKeyCreateNetworkGlobalEntity() failed: %s\n"), SCErrorString(SCError()));
379 ondemand_dict
= SCDynamicStoreCopyValue(store
, key
);
381 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), kSCEntNetOnDemand
, ondemand_dict
);
383 SCPrint(TRUE
, stdout
, CFSTR("%@ not configured\n"), kSCEntNetOnDemand
);
388 my_CFRelease(&ondemand_dict
);
390 my_CFRelease(&store
);
394 /* -----------------------------------------------------------------------------
395 Given a string 'key' and a string prefix 'prefix',
396 return the next component in the slash '/' separated
397 key. If no slash follows the prefix, return NULL.
400 1. key = "a/b/c" prefix = "a/" returns "b"
401 2. key = "a/b/c" prefix = "a/b/" returns NULL
402 ----------------------------------------------------------------------------- */
403 CFStringRef
parse_component(CFStringRef key
, CFStringRef prefix
)
405 CFMutableStringRef comp
;
408 if (!CFStringHasPrefix(key
, prefix
))
411 comp
= CFStringCreateMutableCopy(NULL
, 0, key
);
412 CFStringDelete(comp
, CFRangeMake(0, CFStringGetLength(prefix
)));
413 range
= CFStringFind(comp
, CFSTR("/"), 0);
414 if (range
.location
== kCFNotFound
) {
418 range
.length
= CFStringGetLength(comp
) - range
.location
;
419 CFStringDelete(comp
, range
);
424 /* -----------------------------------------------------------------------------
425 ----------------------------------------------------------------------------- */
427 nc_list(int argc
, char **argv
)
432 CFStringRef key
= NULL
;
433 CFMutableDictionaryRef names
= NULL
;
434 CFArrayRef services
= NULL
;
435 CFStringRef setup
= NULL
;
436 SCDynamicStoreRef store
;
438 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), NULL
, NULL
);
440 SCPrint(TRUE
, stderr
, CFSTR("nc_list SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
443 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
445 SCPrint(TRUE
, stderr
, CFSTR("nc_list SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create key string\n"));
448 setup
= SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/"), kSCDynamicStoreDomainSetup
, kSCCompNetwork
, kSCCompService
);
450 SCPrint(TRUE
, stderr
, CFSTR("nc_list SCDynamicStoreKeyCreate() failed to create setup string\n"));
453 names
= CFDictionaryCreateMutable(NULL
,
455 &kCFTypeDictionaryKeyCallBacks
,
456 &kCFTypeDictionaryValueCallBacks
);
458 SCPrint(TRUE
, stderr
, CFSTR("nc_list CFDictionaryCreateMutable() failed to create names dictionary\n"));
461 services
= SCNetworkConnectionCopyAvailableServices(NULL
);
462 if (services
!= NULL
) {
463 count
= CFArrayGetCount(services
);
465 for (i
= 0; i
< count
; i
++) {
466 SCNetworkServiceRef service
;
467 CFStringRef serviceID
;
468 CFStringRef serviceName
;
470 service
= CFArrayGetValueAtIndex(services
, i
);
471 serviceID
= SCNetworkServiceGetServiceID(service
);
472 serviceName
= SCNetworkServiceGetName(service
);
473 if (serviceName
!= NULL
) {
474 CFDictionarySetValue(names
, serviceID
, serviceName
);
481 services
= SCDynamicStoreCopyKeyList(store
, key
);
482 if (services
== NULL
) {
483 SCPrint(TRUE
, stderr
, CFSTR("nc_list SCDynamicStoreCopyKeyList() failed: %s\n"), SCErrorString(SCError()));
487 count
= CFArrayGetCount(services
);
488 for (i
= 0; i
< count
; i
++) {
489 CFStringRef serviceID
;
491 serviceID
= parse_component(CFArrayGetValueAtIndex(services
, i
), setup
);
494 CFStringRef ifsubtype
;
495 CFStringRef interface_key
= NULL
;
496 CFDictionaryRef interface_dict
= NULL
;
497 CFStringRef service_name
;
499 interface_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, kSCEntNetInterface
);
500 if (!interface_key
) {
501 SCPrint(TRUE
, stderr
, CFSTR("nc_list SCDynamicStoreKeyCreateNetworkServiceEntity() failed to interface key string\n"));
505 interface_dict
= SCDynamicStoreCopyValue(store
, interface_key
);
506 if (!interface_dict
) {
507 SCPrint(TRUE
, stderr
, CFSTR("nc_list SCDynamicStoreCopyValue() to copy interface dictionary: %s\n"), SCErrorString(SCError()));
511 iftype
= CFDictionaryGetValue(interface_dict
, kSCPropNetInterfaceType
);
513 // is that an error condition ???
517 if (!CFEqual(iftype
, kSCEntNetPPP
) &&
518 !CFEqual(iftype
, kSCEntNetIPSec
) &&
519 !CFEqual(iftype
, kSCEntNetVPN
))
522 ifsubtype
= CFDictionaryGetValue(interface_dict
, kSCPropNetInterfaceSubType
);
524 service_name
= CFDictionaryGetValue(names
, serviceID
);
526 SCPrint(TRUE
, stdout
, CFSTR("[%@%@%@] %@%s%@\n"),
527 iftype
? iftype
: CFSTR("?"),
528 ifsubtype
? CFSTR("/") : CFSTR(""),
529 ifsubtype
? ifsubtype
: CFSTR(""),
531 service_name
? " : " : "",
532 service_name
? service_name
: CFSTR(""));
535 my_CFRelease(&interface_key
);
536 my_CFRelease(&interface_dict
);
537 my_CFRelease(&serviceID
);
543 my_CFRelease(&services
);
544 my_CFRelease(&names
);
545 my_CFRelease(&setup
);
547 my_CFRelease(&store
);
551 /* -----------------------------------------------------------------------------
552 ----------------------------------------------------------------------------- */
554 nc_show(int argc
, char **argv
)
556 SCDynamicStoreRef store
= NULL
;
558 CFStringRef setup
= NULL
;
559 CFStringRef serviceIDRef
= NULL
;
560 CFArrayRef services
= NULL
;
561 CFStringRef iftype
= NULL
;
562 CFStringRef ifsubtype
= NULL
;
563 CFStringRef interface_key
= NULL
;
564 CFDictionaryRef interface_dict
= NULL
;
565 CFStringRef type_entity_key
= NULL
;
566 CFStringRef subtype_entity_key
= NULL
;
567 CFDictionaryRef type_entity_dict
= NULL
;
568 CFDictionaryRef subtype_entity_dict
= NULL
;
570 serviceIDRef
= nc_copy_serviceID(argc
, argv
);
571 if (serviceIDRef
== NULL
) {
572 SCPrint(TRUE
, stderr
, CFSTR("No service ID\n"));
576 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), NULL
, NULL
);
578 SCPrint(TRUE
, stderr
, CFSTR("nc_show SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
582 interface_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceIDRef
, kSCEntNetInterface
);
583 if (!interface_key
) {
584 SCPrint(TRUE
, stderr
, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create interface key\n"));
588 interface_dict
= SCDynamicStoreCopyValue(store
, interface_key
);
589 if (!interface_dict
) {
590 SCPrint(TRUE
, stdout
, CFSTR("Interface dictionary missing for service ID : %@\n"), serviceIDRef
);
594 iftype
= CFDictionaryGetValue(interface_dict
, kSCPropNetInterfaceType
);
596 SCPrint(TRUE
, stdout
, CFSTR("Interface Type missing for service ID : %@\n"), serviceIDRef
);
600 if (!CFEqual(iftype
, kSCEntNetPPP
) &&
601 !CFEqual(iftype
, kSCEntNetIPSec
) &&
602 !CFEqual(iftype
, kSCEntNetVPN
)) {
603 SCPrint(TRUE
, stdout
, CFSTR("Interface Type [%@] invalid for service ID : %@\n"), iftype
, serviceIDRef
);
607 ifsubtype
= CFDictionaryGetValue(interface_dict
, kSCPropNetInterfaceSubType
);
608 SCPrint(TRUE
, stdout
, CFSTR("[%@%@%@] %@\n"),
609 iftype
? iftype
: CFSTR("?"),
610 ifsubtype
? CFSTR("/") : CFSTR(""),
611 ifsubtype
? ifsubtype
: CFSTR(""),
614 type_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceIDRef
, iftype
);
615 if (!type_entity_key
) {
616 SCPrint(TRUE
, stderr
, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create type entity key\n"));
619 type_entity_dict
= SCDynamicStoreCopyValue(store
, type_entity_key
);
620 if (!type_entity_dict
) {
621 SCPrint(TRUE
, stdout
, CFSTR("%@ dictionary missing for service ID : %@\n"), iftype
, serviceIDRef
);
623 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), iftype
, type_entity_dict
);
627 subtype_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceIDRef
, ifsubtype
);
628 if (!subtype_entity_key
) {
629 SCPrint(TRUE
, stderr
, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create subtype entity key\n"));
632 subtype_entity_dict
= SCDynamicStoreCopyValue(store
, subtype_entity_key
);
633 if (!subtype_entity_dict
) {
637 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), ifsubtype
, subtype_entity_dict
);
644 my_CFRelease(&serviceIDRef
);
645 my_CFRelease(&interface_key
);
646 my_CFRelease(&interface_dict
);
647 my_CFRelease(&type_entity_key
);
648 my_CFRelease(&type_entity_dict
);
649 my_CFRelease(&subtype_entity_key
);
650 my_CFRelease(&subtype_entity_dict
);
651 my_CFRelease(&services
);
652 my_CFRelease(&setup
);
653 my_CFRelease(&store
);
658 /* -----------------------------------------------------------------------------
659 ----------------------------------------------------------------------------- */
661 nc_select(int argc
, char **argv
)
663 SCNetworkSetRef current_set
;
665 SCNetworkServiceRef service
= NULL
;
666 CFStringRef service_id
;
669 service_id
= nc_copy_serviceID(argc
, argv
);
670 if (service_id
== NULL
) {
671 SCPrint(TRUE
, stderr
, CFSTR("No service identifier\n"));
675 do_prefs_init(); /* initialization */
676 do_prefs_open(0, NULL
); /* open default prefs */
678 current_set
= SCNetworkSetCopyCurrent(prefs
);
679 if (current_set
== NULL
) {
680 SCPrint(TRUE
, stdout
, CFSTR("nc_select SCNetworkSetCopyCurrent() failed: %s\n"), SCErrorString(SCError()));
684 service
= nc_copy_service(current_set
, service_id
);
685 if (service
== NULL
) {
686 SCPrint(TRUE
, stdout
, CFSTR("No service\n"));
690 #if !TARGET_OS_IPHONE
691 status
= SCNetworkServiceSetEnabled(service
, TRUE
);
693 SCPrint(TRUE
, stdout
, CFSTR("nc_select SCNetworkServiceSetEnabled() failed: %s\n"), SCErrorString(SCError()));
697 status
= SCNetworkSetSetSelectedVPNService(current_set
, service
);
699 SCPrint(TRUE
, stdout
, CFSTR("nc_select SCNetworkSetSetSelectedVPNService() failed: %s\n"), SCErrorString(SCError()));
708 my_CFRelease(&service_id
);
709 my_CFRelease(¤t_set
);
714 /* -----------------------------------------------------------------------------
715 ----------------------------------------------------------------------------- */
716 typedef void (*nc_func
) (int argc
, char **argv
);
718 static const struct {
723 { "ondemand", nc_ondemand
},
724 { "resume", nc_resume
},
725 { "select", nc_select
},
727 { "start", nc_start
},
728 { "statistics", nc_statistics
},
729 { "status", nc_status
},
731 { "suspend", nc_suspend
},
733 #define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0]))
736 /* -----------------------------------------------------------------------------
737 ----------------------------------------------------------------------------- */
739 find_nc_cmd(char *cmd
)
743 for (i
= 0; i
< (int)N_NC_CMNDS
; i
++) {
744 if (strcmp(cmd
, nc_cmds
[i
].cmd
) == 0) {
753 /* -----------------------------------------------------------------------------
754 ----------------------------------------------------------------------------- */
756 do_nc_cmd(char *cmd
, int argc
, char **argv
, Boolean watch
)
760 i
= find_nc_cmd(cmd
);
764 func
= nc_cmds
[i
].func
;
765 if (watch
&& (func
== nc_status
)) {