From: Apple <opensource@apple.com>
Date: Wed, 15 Aug 2018 19:39:56 +0000 (+0000)
Subject: configd-963.50.8.tar.gz
X-Git-Tag: macos-10134^0
X-Git-Url: https://git.saurik.com/apple/configd.git/commitdiff_plain/4f125ff561e6fa1bd12b93c65dc5fa8e3323fd9a

configd-963.50.8.tar.gz
---

diff --git a/Plugins/IPMonitor/ip_plugin.c b/Plugins/IPMonitor/ip_plugin.c
index eeec2c2..dcb359d 100644
--- a/Plugins/IPMonitor/ip_plugin.c
+++ b/Plugins/IPMonitor/ip_plugin.c
@@ -7008,6 +7008,9 @@ add_reachability_flags_to_candidate(CandidateRef candidate, CFDictionaryRef serv
     SCNetworkReachabilityFlags	flags = kSCNetworkReachabilityFlagsReachable;
     CFStringRef			vpn_server_address = NULL;
 
+    assert(candidate != NULL);
+    assert(services_info != NULL);
+
     VPNAttributesGet(candidate->serviceID,
 		     services_info,
 		     &flags,
@@ -7052,6 +7055,8 @@ ElectionResultsGetPrimary(ElectionResultsRef results,
     Boolean		primary_is_null = FALSE;
     RouteListRef	routes = NULL;
 
+    assert(services_info != NULL);
+
     if (results != NULL) {
 	CandidateRef		deferred[results->count];
 	int			deferred_count;
@@ -8128,6 +8133,9 @@ IPMonitorProcessChanges(SCDynamicStoreRef session, CFArrayRef changed_keys,
 
     /* grab a snapshot of everything we need */
     services_info = services_info_copy(session, service_changes);
+    assert(services_info != NULL);
+
+    /* grab the service order */
     service_order = service_order_get(services_info);
     if (service_order != NULL) {
 	if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
diff --git a/Plugins/InterfaceNamer/ifnamer.c b/Plugins/InterfaceNamer/ifnamer.c
index e796110..398f5c3 100644
--- a/Plugins/InterfaceNamer/ifnamer.c
+++ b/Plugins/InterfaceNamer/ifnamer.c
@@ -155,6 +155,14 @@ static io_iterator_t		S_iter			= MACH_PORT_NULL;
  */
 static IONotificationPortRef	S_notify		= NULL;
 
+/*
+ * S_preconfigured
+ *   An array of CFData(WatchedInfo) objects representing those
+ *   pre-configured interfaces that have been connected to the
+ *   system.
+ */
+static CFMutableArrayRef	S_preconfigured		= NULL;
+
 /* S_prev_active_list
  *   An array of CFDictionary's representing the previously
  *   named interfaces.
@@ -453,6 +461,9 @@ previouslyActiveInterfaces()
     return active;
 }
 
+static void
+updateInterfaces(void);
+
 static void
 updateStore(void)
 {
@@ -1473,6 +1484,136 @@ builtinCount(CFArrayRef if_list, CFIndex last, CFNumberRef if_type)
     return n;
 }
 
+
+#pragma mark -
+#pragma mark Interface monitoring (e.g. watch for "detach")
+
+
+typedef struct WatchedInfo	*WatchedInfoRef;
+
+typedef void (*InterfaceUpdateCallBack)	(
+    CFDataRef			watched,
+    natural_t			messageType,
+    void			*messageArgument
+);
+
+typedef struct {
+    SCNetworkInterfaceRef	interface;
+    io_service_t		interface_node;
+    io_object_t			notification;
+    InterfaceUpdateCallBack	callback;
+} WatchedInfo;
+
+static void
+watcherRelease(CFDataRef watched);
+
+static void
+updateWatchedInterface(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
+{
+#pragma unused(service)
+#pragma unused(messageArgument)
+    switch (messageType) {
+	case kIOMessageServiceIsTerminated : {		// if [locked] interface yanked
+	    CFDataRef	watched		= (CFDataRef)refCon;
+	    WatchedInfo	*watchedInfo	= (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
+
+	    CFRetain(watched);
+	    watchedInfo->callback(watched, messageType, messageArgument);
+	    watcherRelease(watched);
+	    CFRelease(watched);
+	    break;
+	}
+
+	default :
+	    return;
+    }
+
+    return;
+}
+
+static CFDataRef
+watcherCreate(SCNetworkInterfaceRef interface, InterfaceUpdateCallBack callback)
+{
+    uint64_t		entryID;
+    io_service_t	interface_node;
+    kern_return_t	kr;
+    CFDictionaryRef	matching;
+    CFMutableDataRef	watched;
+    WatchedInfo		*watchedInfo;
+
+    // get the IORegistry node
+    entryID = _SCNetworkInterfaceGetIORegistryEntryID(interface);
+    matching = IORegistryEntryIDMatching(entryID);
+    interface_node = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
+    if (interface_node == MACH_PORT_NULL) {
+	// interface no longer present
+	return NULL;
+    }
+
+    // create [locked] interface watcher
+    watched = CFDataCreateMutable(NULL, sizeof(WatchedInfo));
+    CFDataSetLength(watched, sizeof(WatchedInfo));
+    watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
+    bzero(watchedInfo, sizeof(*watchedInfo));
+
+    // retain interface
+    watchedInfo->interface = CFRetain(interface);
+
+    // ... and the interface node
+    watchedInfo->interface_node = interface_node;
+
+    // ... and set the callback
+    watchedInfo->callback = callback;
+
+    kr = IOServiceAddInterestNotification(S_notify,			// IONotificationPortRef
+					  watchedInfo->interface_node,	// io_service_t
+					  kIOGeneralInterest,		// interestType
+					  updateWatchedInterface,	// IOServiceInterestCallback
+					  (void *)watched,		// refCon
+					  &watchedInfo->notification);	// notification
+    if (kr != KERN_SUCCESS) {
+	SC_log(LOG_ERR,
+	       "IOServiceAddInterestNotification() failed, kr =  0x%x",
+	       kr);
+	watcherRelease(watched);
+	CFRelease(watched);
+	return NULL;
+    }
+
+    return watched;
+}
+
+static void
+watcherRelease(CFDataRef watched)
+{
+    WatchedInfo	*watchedInfo	= (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
+
+    // release watcher
+    if (watchedInfo->notification != IO_OBJECT_NULL) {
+	IOObjectRelease(watchedInfo->notification);
+	watchedInfo->notification = IO_OBJECT_NULL;
+    }
+
+    // release interface node
+    if (watchedInfo->interface_node != IO_OBJECT_NULL) {
+	IOObjectRelease(watchedInfo->interface_node);
+	watchedInfo->interface_node = IO_OBJECT_NULL;
+    }
+
+    // release interface
+    if (watchedInfo->interface != NULL) {
+	CFRelease(watchedInfo->interface);
+	watchedInfo->interface = NULL;
+    }
+
+    return;
+}
+
+
+#pragma mark -
+#pragma mark Locked device support [macOS]
+
+
 #if	!TARGET_OS_IPHONE
 static boolean_t
 blockNewInterfaces()
@@ -1563,6 +1704,11 @@ isConsoleLocked()
 }
 #endif	// !TARGET_OS_IPHONE
 
+
+#pragma mark -
+#pragma mark Interface naming
+
+
 static __inline__ boolean_t
 isQuiet(void)
 {
@@ -1929,52 +2075,107 @@ updateNetworkConfiguration(CFArrayRef if_list)
 #endif	// !TARGET_OS_IPHONE
 
 static void
-updatePreConfigured(CFArrayRef interfaces)
+sharePreconfigured()
 {
-    CFIndex		i;
-    CFIndex		n;
-    CFMutableArrayRef	new_list    = NULL;
-    Boolean		updated	    = FALSE;
+    CFIndex	n;
 
-    n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
-    for (i = 0; i < n; i++) {
-	SCNetworkInterfaceRef	interface;
+    n = (S_preconfigured != NULL) ? CFArrayGetCount(S_preconfigured) : 0;
+    if (n > 0) {
+	CFMutableArrayRef	preconfigured;
 
-	interface = CFArrayGetValueAtIndex(interfaces, i);
-	if (_SCNetworkInterfaceIsApplePreconfigured(interface)) {
+	preconfigured = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+	for (CFIndex i = 0; i < n; i++) {
 	    CFStringRef	bsdName;
+	    CFDataRef	watched		= CFArrayGetValueAtIndex(S_preconfigured, i);
+	    WatchedInfo	*watchedInfo	= (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
 
-	    bsdName = SCNetworkInterfaceGetBSDName(interface);
-	    if (bsdName == NULL) {
-		continue;
-	    }
+	    bsdName = SCNetworkInterfaceGetBSDName(watchedInfo->interface);
+	    CFArrayAppendValue(preconfigured, bsdName);
+	}
 
-	    // add pre-configured interface
-	    if (new_list == NULL) {
-		CFArrayRef	cur_list;
+	CFDictionarySetValue(S_state, kInterfaceNamerKey_PreConfiguredInterfaces, preconfigured);
+	CFRelease(preconfigured);
+    } else {
+	CFDictionaryRemoveValue(S_state, kInterfaceNamerKey_PreConfiguredInterfaces);
+    }
 
-		cur_list = CFDictionaryGetValue(S_state, kInterfaceNamerKey_PreConfiguredInterfaces);
-		if (cur_list != NULL) {
-		    new_list = CFArrayCreateMutableCopy(NULL, 0, cur_list);
-		} else {
-		    new_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+    updateStore();
+
+    return;
+}
+
+static void
+preconfiguredInterfaceUpdated(CFDataRef watched, natural_t messageType, void *messageArgument)
+{
+    Boolean	updated		= FALSE;
+    WatchedInfo	*watchedInfo	= (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
+
+#pragma unused(messageArgument)
+    switch (messageType) {
+	case kIOMessageServiceIsTerminated : {		// if [locked] interface yanked
+	    SC_log(LOG_INFO, "[pre-configured] interface removed: %@",
+		   SCNetworkInterfaceGetBSDName(watchedInfo->interface));
+
+	    if (S_preconfigured != NULL) {
+		CFIndex	i;
+		CFIndex	n	= CFArrayGetCount(S_preconfigured);
+
+		i = CFArrayGetFirstIndexOfValue(S_preconfigured, CFRangeMake(0, n), watched);
+		if (i != kCFNotFound) {
+		    CFArrayRemoveValueAtIndex(S_preconfigured, i);
+		    if (CFArrayGetCount(S_preconfigured) == 0) {
+			CFRelease(S_preconfigured);
+			S_preconfigured = NULL;
+		    }
+		    updated = TRUE;
 		}
 	    }
 
-	    if (!CFArrayContainsValue(new_list, CFRangeMake(0, CFArrayGetCount(new_list)), bsdName)) {
-		CFArrayAppendValue(new_list, bsdName);
-		updated = TRUE;
-	    }
+	    break;
 	}
+
+	default :
+	    return;
     }
 
-    if (new_list != NULL) {
-	if (updated) {
-	    CFDictionarySetValue(S_state, kInterfaceNamerKey_PreConfiguredInterfaces, new_list);
-	    updateStore();
+    if (updated) {
+	sharePreconfigured();
+    }
+
+    return;
+}
+
+static void
+updatePreConfiguredInterfaces(CFArrayRef interfaces)
+{
+    CFIndex	n;
+    Boolean	updated	= FALSE;
+
+    n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
+    for (CFIndex i = 0; i < n; i++) {
+	SCNetworkInterfaceRef	interface;
+
+	interface = CFArrayGetValueAtIndex(interfaces, i);
+	if (_SCNetworkInterfaceIsApplePreconfigured(interface)) {
+	    CFDataRef	watched;
+
+	    watched = watcherCreate(interface, preconfiguredInterfaceUpdated);
+	    if (watched != NULL) {
+		SC_log(LOG_INFO, "watching [pre-configured] interface: %@",
+		       SCNetworkInterfaceGetBSDName(interface));
+
+		if (S_preconfigured == NULL) {
+		    S_preconfigured = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+		}
+		CFArrayAppendValue(S_preconfigured, watched);
+		updated = TRUE;
+	    }
 	}
+    }
 
-	CFRelease(new_list);
+    if (updated) {
+	sharePreconfigured();
     }
 
     return;
@@ -2001,7 +2202,7 @@ updateInterfaces()
     /*
      * Update the list of [Apple] pre-configured interfaces
      */
-    updatePreConfigured(S_iflist);
+    updatePreConfiguredInterfaces(S_iflist);
 
     if (isQuiet()) {
 	/*
diff --git a/Plugins/KernelEventMonitor/eventmon.c b/Plugins/KernelEventMonitor/eventmon.c
index 73fd9a1..efb8c8c 100644
--- a/Plugins/KernelEventMonitor/eventmon.c
+++ b/Plugins/KernelEventMonitor/eventmon.c
@@ -179,58 +179,6 @@ dgram_socket(int domain)
     return s;
 }
 
-static int
-ifflags_set(int s, char * name, short flags)
-{
-    struct ifreq	ifr;
-    int 		ret;
-
-    bzero(&ifr, sizeof(ifr));
-    strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-    ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
-    if (ret == -1) {
-		return (ret);
-    }
-    ifr.ifr_flags |= flags;
-    return (ioctl(s, SIOCSIFFLAGS, &ifr));
-}
-
-static int
-ifflags_clear(int s, char * name, short flags)
-{
-    struct ifreq	ifr;
-    int 		ret;
-
-    bzero(&ifr, sizeof(ifr));
-    strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-    ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
-    if (ret == -1) {
-		return (ret);
-    }
-    ifr.ifr_flags &= ~flags;
-    return (ioctl(s, SIOCSIFFLAGS, &ifr));
-}
-
-static void
-mark_if_up(char * name)
-{
-	int s = dgram_socket(AF_INET);
-	if (s == -1)
-		return;
-	ifflags_set(s, name, IFF_UP);
-	close(s);
-}
-
-static void
-mark_if_down(char * name)
-{
-	int s = dgram_socket(AF_INET);
-	if (s == -1)
-		return;
-	ifflags_clear(s, name, IFF_UP);
-	close(s);
-}
-
 static void
 post_network_changed(void)
 {
@@ -481,11 +429,6 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg)
 						 (char *)ifr_name,
 						 protoEvent->proto_family,
 						 protoEvent->proto_remaining_count);
-					if (protoEvent->proto_remaining_count == 0) {
-						mark_if_down(ifr_name);
-					} else {
-						mark_if_up(ifr_name);
-					}
 					break;
 				}
 
diff --git a/Plugins/PreferencesMonitor/prefsmon.c b/Plugins/PreferencesMonitor/prefsmon.c
index ac7bbdd..84e9476 100644
--- a/Plugins/PreferencesMonitor/prefsmon.c
+++ b/Plugins/PreferencesMonitor/prefsmon.c
@@ -425,7 +425,6 @@ storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
 	dict = SCDynamicStoreCopyValue(store, namerKey);
 	if (dict != NULL) {
 		if (isA_CFDictionary(dict)) {
-			CFIndex		n;
 			CFArrayRef	preconfigured;
 
 			if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet)) {
@@ -437,74 +436,87 @@ storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
 
 			preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces);
 			preconfigured = isA_CFArray(preconfigured);
+			if (!_SC_CFEqual(preconfigured, preconfigured_names)) {
+				CFIndex		n;
+				CFIndex		nx	= 0;
 
-			n = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0;
-			for (CFIndex i = 0; i < n; i++) {
-				CFStringRef		bsdName	 = CFArrayGetValueAtIndex(preconfigured, i);
-				SCNetworkInterfaceRef	interface;
-				CFRange			range;
-
-				range.location = 0;
-				range.length   = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0;
-				if ((range.length > 0) &&
-				    CFArrayContainsValue(preconfigured_names, range, bsdName)) {
-					// if we already know about this interface
-					continue;
+				// start clean
+				if (preconfigured_names != NULL) {
+					nx = CFArrayGetCount(preconfigured_names);
+					CFRelease(preconfigured_names);
+					preconfigured_names = NULL;
+				}
+				if (preconfigured_interfaces != NULL) {
+					CFRelease(preconfigured_interfaces);
+					preconfigured_interfaces = NULL;
 				}
 
-				for (int retry = 0; retry < 10; retry++) {
-					if (retry != 0) {
-						// add short delay (before retry)
-						usleep(20 * 1000);	// 20ms
+				// add pre-configured interfaces
+				n = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0;
+				for (CFIndex i = 0; i < n; i++) {
+					CFStringRef		bsdName	 = CFArrayGetValueAtIndex(preconfigured, i);
+					SCNetworkInterfaceRef	interface;
+
+					for (int retry = 0; retry < 10; retry++) {
+						if (retry != 0) {
+							// add short delay (before retry)
+							usleep(20 * 1000);	// 20ms
+						}
+
+						interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces);
+						if (interface == NULL) {
+							SC_log(LOG_ERR, "could not create network interface for %@", bsdName);
+						} else if (_SCNetworkInterfaceGetIOPath(interface) == NULL) {
+							SC_log(LOG_ERR, "could not get IOPath for %@", bsdName);
+							CFRelease(interface);
+							interface = NULL;
+						}
+
+						if (interface != NULL) {
+							// if we have an interface
+							break;
+						}
 					}
 
-					interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces);
 					if (interface == NULL) {
-						SC_log(LOG_ERR, "could not create network interface for %@", bsdName);
-					} else if (_SCNetworkInterfaceGetIOPath(interface) == NULL) {
-						SC_log(LOG_ERR, "could not get IOPath for %@", bsdName);
-						CFRelease(interface);
-						interface = NULL;
+						// if SCNetworkInterface not [currently] available
+						continue;
 					}
 
-					if (interface != NULL) {
-						// if we have an interface
-						break;
+					// keep track of the interface name (quicker than having to iterate the list
+					// of SCNetworkInterfaces, extract the name, and compare).
+					if (preconfigured_names == NULL) {
+						preconfigured_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
 					}
-				}
+					CFArrayAppendValue(preconfigured_names, bsdName);
 
-				if (interface == NULL) {
-					// if SCNetworkInterface not [currently] available
-					continue;
-				}
+					if (preconfigured_interfaces == NULL) {
+						preconfigured_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+					}
+					CFArrayAppendValue(preconfigured_interfaces, interface);
+					CFRelease(interface);
 
-				// keep track of the interface name (quicker than having to iterate the list
-				// of SCNetworkInterfaces, extract the name, and compare).
-				if (preconfigured_names == NULL) {
-					preconfigured_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+					updated = TRUE;
 				}
-				CFArrayAppendValue(preconfigured_names, bsdName);
 
-				if (preconfigured_interfaces == NULL) {
-					preconfigured_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+				// check if all pre-configured interfaces were detached
+				n = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0;
+				if ((nx > 0) && (n == 0)) {
+					updated = TRUE;
 				}
-				CFArrayAppendValue(preconfigured_interfaces, interface);
-				CFRelease(interface);
 
-				updated = TRUE;
-			}
-
-			if (updated) {
-				CFStringRef	interfaces	= CFSTR("<empty>");
+				if (updated) {
+					CFStringRef	interfaces	= CFSTR("<empty>");
 
-				// report [new] pre-configured interfaces
-				if (preconfigured_names != NULL) {
-					interfaces = CFStringCreateByCombiningStrings(NULL, preconfigured_names, CFSTR(","));
-				} else {
-					CFRetain(interfaces);
+					// report [updated] pre-configured interfaces
+					if (preconfigured_names != NULL) {
+						interfaces = CFStringCreateByCombiningStrings(NULL, preconfigured_names, CFSTR(","));
+					} else {
+						CFRetain(interfaces);
+					}
+					SC_log(LOG_INFO, "pre-configured interface list changed: %@", interfaces);
+					CFRelease(interfaces);
 				}
-				SC_log(LOG_INFO, "pre-configured interface list changed: %@", interfaces);
-				CFRelease(interfaces);
 			}
 		}
 
@@ -668,42 +680,6 @@ flatten(SCPreferencesRef	prefs,
 }
 
 
-static CF_RETURNS_RETAINED SCNetworkServiceRef
-copyInterfaceService(SCNetworkSetRef set, CFStringRef matchName)
-{
-	CFIndex			i;
-	CFIndex			n;
-	SCNetworkServiceRef	service	= NULL;
-	CFArrayRef		services;
-
-	services = SCNetworkSetCopyServices(set);
-	assert(services != NULL);
-
-	n = CFArrayGetCount(services);
-	for (i = 0; i < n; i++) {
-		SCNetworkInterfaceRef	interface;
-
-		service = CFArrayGetValueAtIndex(services, i);
-		interface = SCNetworkServiceGetInterface(service);
-		if (interface != NULL) {
-			CFStringRef		bsdName;
-
-			bsdName = SCNetworkInterfaceGetBSDName(interface);
-			if (_SC_CFEqual(bsdName, matchName)) {
-				// if match
-				CFRetain(service);
-				break;
-			}
-		}
-
-		service = NULL;
-	}
-
-	CFRelease(services);
-	return service;
-}
-
-
 static CF_RETURNS_RETAINED CFStringRef
 copyInterfaceUUID(CFStringRef bsdName)
 {
@@ -745,126 +721,145 @@ updatePreConfiguredConfiguration(SCPreferencesRef prefs)
 {
 	Boolean		ok;
 	CFRange		range;
+	CFArrayRef	services;
 	SCNetworkSetRef	set;
 	Boolean		updated	= FALSE;
 
-	range.length = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0;
+	range = CFRangeMake(0,
+			    (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0);
 	if (range.length == 0) {
-		// if no [preconfigured] interfaces
+		// if no [pre-configured] interfaces
 		return;
 	}
-	range.location = 0;
 
 	set = SCNetworkSetCopyCurrent(prefs);
-	if (set != NULL) {
-		CFArrayRef	services;
-
-		/*
-		 * Check for (and remove) any network services associated with
-		 * a pre-configured interface from the prefs.
-		 */
-		services = SCNetworkServiceCopyAll(prefs);
-		if (services != NULL) {
-			CFIndex		n;
-
-			n = CFArrayGetCount(services);
-			for (CFIndex i = 0; i < n; i++) {
-				CFStringRef		bsdName;
-				SCNetworkInterfaceRef	interface;
-				SCNetworkServiceRef	service;
-
-				service = CFArrayGetValueAtIndex(services, i);
-
-				interface = SCNetworkServiceGetInterface(service);
-				if (interface == NULL) {
-					// if no interface
-					continue;
-				}
+	if (set == NULL) {
+		// if no current set
+		return;
+	}
 
-				bsdName = SCNetworkInterfaceGetBSDName(interface);
-				if (bsdName == NULL) {
-					// if no interface name
-					continue;
-				}
+	/*
+	 * Check for (and remove) any network services associated with
+	 * a pre-configured interface from the prefs.
+	 */
+	services = SCNetworkServiceCopyAll(prefs);
+	if (services != NULL) {
+		CFIndex		n;
 
-				if (!CFArrayContainsValue(preconfigured_names, range, bsdName)) {
-					// if not preconfigured
-					continue;
-				}
+		n = CFArrayGetCount(services);
+		for (CFIndex i = 0; i < n; i++) {
+			CFStringRef		bsdName;
+			SCNetworkInterfaceRef	interface;
+			SCNetworkServiceRef	service;
 
-				// remove [preconfigured] network service from the prefs
-				SC_log(LOG_NOTICE, "removing network service for %@", bsdName);
-				ok = SCNetworkServiceRemove(service);
-				if (!ok) {
-					SC_log(LOG_ERR, "SCNetworkServiceRemove() failed: %s",
-					       SCErrorString(SCError()));
-				}
-				updated = TRUE;
+			service = CFArrayGetValueAtIndex(services, i);
+
+			interface = SCNetworkServiceGetInterface(service);
+			if (interface == NULL) {
+				// if no interface
+				continue;
 			}
 
-			CFRelease(services);
-		}
+			bsdName = SCNetworkInterfaceGetBSDName(interface);
+			if (bsdName == NULL) {
+				// if no interface name
+				continue;
+			}
 
-		if (updated) {
-			// commit the updated prefs ... but don't apply
-			ok = SCPreferencesCommitChanges(prefs);
+			if (!CFArrayContainsValue(preconfigured_names, range, bsdName)) {
+				// if not preconfigured
+				continue;
+			}
+
+			// remove [preconfigured] network service from the prefs
+			SC_log(LOG_NOTICE, "removing network service for %@", bsdName);
+			ok = SCNetworkServiceRemove(service);
 			if (!ok) {
-				if (SCError() != EROFS) {
-					SC_log(LOG_ERR, "SCPreferencesCommitChanges() failed: %s",
-					       SCErrorString(SCError()));
-				}
+				SC_log(LOG_ERR, "SCNetworkServiceRemove() failed: %s",
+				       SCErrorString(SCError()));
 			}
+			updated = TRUE;
 		}
 
-		/*
-		 * Now, add a new network service for each pre-configured interface
-		 */
-		range.length = (preconfigured_interfaces != NULL) ? CFArrayGetCount(preconfigured_interfaces) : 0;
-		for (CFIndex i = 0; i < range.length; i++) {
-			CFStringRef		bsdName;
-			SCNetworkInterfaceRef	interface	= CFArrayGetValueAtIndex(preconfigured_interfaces, i);
-			SCNetworkServiceRef	service;
+		CFRelease(services);
+	}
 
-			bsdName = SCNetworkInterfaceGetBSDName(interface);
-			ok = SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface);
-			if (!ok) {
-				SC_log(LOG_ERR, "could not establish network service for %@: %s",
-				       bsdName,
+	if (updated) {
+		// commit the updated prefs ... but don't apply
+		ok = SCPreferencesCommitChanges(prefs);
+		if (!ok) {
+			if (SCError() != EROFS) {
+				SC_log(LOG_ERR, "SCPreferencesCommitChanges() failed: %s",
 				       SCErrorString(SCError()));
-				continue;
 			}
+		}
+	}
 
-			service = copyInterfaceService(set, bsdName);
-			if (service != NULL) {
-				CFStringRef	serviceID;
-
-				serviceID = copyInterfaceUUID(bsdName);
-				if (serviceID != NULL) {
-					ok = _SCNetworkServiceSetServiceID(service, serviceID);
-					CFRelease(serviceID);
-					if (!ok) {
-						SC_log(LOG_ERR, "_SCNetworkServiceSetServiceID() failed: %s",
-						       SCErrorString(SCError()));
-						// ... and keep whatever random UUID was created for the service
-					}
-				} else {
-					SC_log(LOG_ERR, "could not create serviceID for %@", bsdName);
-					// ... and we'll use whatever random UUID was created for the service
-				}
-
-				SC_log(LOG_INFO, "network service %@ added for %@",
-				       SCNetworkServiceGetServiceID(service),
-				       bsdName);
+	/*
+	 * Now, add a new network service for each pre-configured interface
+	 */
+	for (CFIndex i = 0; i < range.length; i++) {
+		CFStringRef		bsdName;
+		SCNetworkInterfaceRef	interface	= CFArrayGetValueAtIndex(preconfigured_interfaces, i);
+		SCNetworkServiceRef	service;
+		CFStringRef		serviceID;
+
+		bsdName = SCNetworkInterfaceGetBSDName(interface);
+
+		// create network service
+		service = SCNetworkServiceCreate(prefs, interface);
+		if (service == NULL) {
+			SC_log(LOG_ERR, "could not create network service for \"%@\": %s",
+			       bsdName,
+			       SCErrorString(SCError()));
+			continue;
+		}
 
-				CFRelease(service);
-			} else {
-				SC_log(LOG_ERR, "could not find network service for %@", bsdName);
+		// update network service to use a consistent serviceID
+		serviceID = copyInterfaceUUID(bsdName);
+		if (serviceID != NULL) {
+			ok = _SCNetworkServiceSetServiceID(service, serviceID);
+			CFRelease(serviceID);
+			if (!ok) {
+				SC_log(LOG_ERR, "_SCNetworkServiceSetServiceID() failed: %s",
+				       SCErrorString(SCError()));
+				// ... and keep whatever random UUID was created for the service
 			}
+		} else {
+			SC_log(LOG_ERR, "could not create serviceID for \"%@\"", bsdName);
+			// ... and we'll use whatever random UUID was created for the service
+		}
+
+		// establish [template] configuration
+		ok = SCNetworkServiceEstablishDefaultConfiguration(service);
+		if (!ok) {
+			SC_log(LOG_ERR, "could not establish network service for \"%@\": %s",
+			       bsdName,
+			       SCErrorString(SCError()));
+			SCNetworkServiceRemove(service);
+			CFRelease(service);
+			continue;
 		}
 
-		CFRelease(set);
+		// add network service to the current set
+		ok = SCNetworkSetAddService(set, service);
+		if (!ok) {
+			SC_log(LOG_ERR, "could not add service for \"%@\": %s",
+			       bsdName,
+			       SCErrorString(SCError()));
+			SCNetworkServiceRemove(service);
+			CFRelease(service);
+			continue;
+		}
+
+		SC_log(LOG_INFO, "network service %@ added for \"%@\"",
+		       SCNetworkServiceGetServiceID(service),
+		       bsdName);
+
+		CFRelease(service);
 	}
 
+	CFRelease(set);
 	return;
 }
 
diff --git a/SystemConfiguration.fproj/SCDPrivate.c b/SystemConfiguration.fproj/SCDPrivate.c
index 4e618f7..1cb9577 100644
--- a/SystemConfiguration.fproj/SCDPrivate.c
+++ b/SystemConfiguration.fproj/SCDPrivate.c
@@ -365,6 +365,31 @@ _SC_hw_model(Boolean trim)
 #pragma mark Serialization
 
 
+static kern_return_t
+__CFDataCopyVMData(CFDataRef data, void **dataRef, CFIndex *dataLen)
+{
+	kern_return_t		kr;
+
+	vm_address_t	vm_address;
+	vm_size_t	vm_size;
+
+	vm_address = (vm_address_t)CFDataGetBytePtr(data);
+	vm_size    = (vm_size_t)CFDataGetLength(data);
+	kr = vm_allocate(mach_task_self(), &vm_address, vm_size, VM_FLAGS_ANYWHERE);
+	if (kr != KERN_SUCCESS) {
+		*dataRef = NULL;
+		*dataLen = 0;
+		return kr;
+	}
+
+	bcopy((char *)CFDataGetBytePtr(data), (void *)vm_address, vm_size);
+	*dataRef = (void *)vm_address;
+	*dataLen = vm_size;
+
+	return kr;
+}
+
+
 Boolean
 _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dataLen)
 {
@@ -399,24 +424,14 @@ _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dat
 			*dataLen = CFDataGetLength(myXml);
 		}
 	} else {
-		mach_msg_type_number_t	len;
-		kern_return_t		status;
-
-		status = vm_read(mach_task_self(),
-				 (vm_address_t)CFDataGetBytePtr(myXml),	// address
-				 (vm_size_t)   CFDataGetLength(myXml),	// size
-				 (void *)dataRef,
-				 &len);
-		if (status != KERN_SUCCESS) {
-			SC_log(LOG_NOTICE, "vm_read() failed: %s", mach_error_string(status));
-			CFRelease(myXml);
-			*dataRef = NULL;
-			*dataLen = 0;
-			return FALSE;
-		}
+		kern_return_t	kr;
 
-		*dataLen = len;
+		kr = __CFDataCopyVMData(myXml, dataRef, dataLen);
 		CFRelease(myXml);
+		if (kr != KERN_SUCCESS) {
+			SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr));
+			return FALSE;
+		}
 	}
 
 	return TRUE;
@@ -446,7 +461,7 @@ _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dat
 
 	if (*obj == NULL) {
 		if (error != NULL) {
-			SC_log(LOG_NOTICE, "CFPropertyListCreateWithData() faled: %@", error);
+			SC_log(LOG_NOTICE, "CFPropertyListCreateWithData() failed: %@", error);
 			CFRelease(error);
 		}
 		_SCErrorSet(kSCStatusFailed);
@@ -492,25 +507,14 @@ _SCSerializeString(CFStringRef str, CFDataRef *data, void **dataRef, CFIndex *da
 			*dataLen = CFDataGetLength(myData);
 		}
 	} else {
-		mach_msg_type_number_t	len;
-		kern_return_t		status;
-
-		*dataLen = CFDataGetLength(myData);
-		status = vm_read(mach_task_self(),
-				 (vm_address_t)CFDataGetBytePtr(myData),	// address
-				 *dataLen,					// size
-				 (void *)dataRef,
-				 &len);
-		if (status != KERN_SUCCESS) {
-			SC_log(LOG_NOTICE, "vm_read() failed: %s", mach_error_string(status));
-			CFRelease(myData);
-			*dataRef = NULL;
-			*dataLen = 0;
-			return FALSE;
-		}
+		kern_return_t	kr;
 
-		*dataLen = len;
+		kr = __CFDataCopyVMData(myData, dataRef, dataLen);
 		CFRelease(myData);
+		if (kr != KERN_SUCCESS) {
+			SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr));
+			return FALSE;
+		}
 	}
 
 	return TRUE;
@@ -548,29 +552,19 @@ _SCUnserializeString(CFStringRef *str, CFDataRef utf8, void *dataRef, CFIndex da
 Boolean
 _SCSerializeData(CFDataRef data, void **dataRef, CFIndex *dataLen)
 {
-	mach_msg_type_number_t	len;
-	kern_return_t		status;
+	kern_return_t	kr;
 
 	if (!isA_CFData(data)) {
 		/* if not a CFData */
 		return FALSE;
 	}
 
-	*dataLen = CFDataGetLength(data);
-	status = vm_read(mach_task_self(),
-			 (vm_address_t)CFDataGetBytePtr(data),	// address
-			 *dataLen,				// size
-			 (void *)dataRef,
-			 &len);
-	if (status != KERN_SUCCESS) {
-		SC_log(LOG_NOTICE, "vm_read() failed: %s", mach_error_string(status));
-		*dataRef = NULL;
-		*dataLen = 0;
+	kr = __CFDataCopyVMData(data, dataRef, dataLen);
+	if (kr != KERN_SUCCESS) {
+		SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr));
 		return FALSE;
 	}
 
-	*dataLen = len;
-
 	return TRUE;
 }
 
diff --git a/dnsinfo/dnsinfo_server.c b/dnsinfo/dnsinfo_server.c
index b02f8d9..b6c96a3 100644
--- a/dnsinfo/dnsinfo_server.c
+++ b/dnsinfo/dnsinfo_server.c
@@ -315,7 +315,7 @@ add_state_handler()
 		if (state_data_size > MAX_STATEDUMP_SIZE) {
 			SC_log(LOG_ERR, "DNS configuration: state data too large (%zd > %zd)",
 			       state_data_size,
-			       MAX_STATEDUMP_SIZE);
+			       (size_t)MAX_STATEDUMP_SIZE);
 			return NULL;
 		}
 
diff --git a/get-network-info b/get-network-info
index b2ba85d..f42023c 100755
--- a/get-network-info
+++ b/get-network-info
@@ -335,19 +335,34 @@ run_skywalk () {
 	fi
 
 	echo "#"							 > skywalk.txt
-	echo "# skywalkctl list-providers -D"				>> skywalk.txt
+	echo "# skywalkctl show"					>> skywalk.txt
 	echo "#"							>> skywalk.txt
-	/usr/sbin/skywalkctl list-providers -D				>> skywalk.txt		2>&1
+	/usr/sbin/skywalkctl show					>> skywalk.txt		2>&1
 
 	echo "#"							>> skywalk.txt
-	echo "# skywalkctl channel-stats"				>> skywalk.txt
+	echo "# skywalkctl flow -n"					>> skywalk.txt
 	echo "#"							>> skywalk.txt
-	/usr/sbin/skywalkctl channel-stats				>> skywalk.txt		2>&1
+	/usr/sbin/skywalkctl flow -n					>> skywalk.txt		2>&1
 
 	echo "#"							>> skywalk.txt
-	echo "# skywalkctl netstat -a -n"				>> skywalk.txt
+	echo "# skywalkctl flow-route -n"				>> skywalk.txt
 	echo "#"							>> skywalk.txt
-	/usr/sbin/skywalkctl netstat -a -n				>> skywalk.txt		2>&1
+	/usr/sbin/skywalkctl flow-route -n				>> skywalk.txt		2>&1
+
+	echo "#"							>> skywalk.txt
+	echo "# skywalkctl flow-switch"					>> skywalk.txt
+	echo "#"							>> skywalk.txt
+	/usr/sbin/skywalkctl flow-switch				>> skywalk.txt		2>&1
+
+	echo "#"							>> skywalk.txt
+	echo "# skywalkctl flow-owner"					>> skywalk.txt
+	echo "#"							>> skywalk.txt
+	/usr/sbin/skywalkctl flow-owner					>> skywalk.txt		2>&1
+
+	echo "#"							>> skywalk.txt
+	echo "# skywalkctl flow-adv"					>> skywalk.txt
+	echo "#"							>> skywalk.txt
+	/usr/sbin/skywalkctl flow-adv					>> skywalk.txt		2>&1
 
 	echo "#"							>> skywalk.txt
 	echo "# skywalkctl netstat -s"					>> skywalk.txt
@@ -360,24 +375,19 @@ run_skywalk () {
 	/usr/sbin/skywalkctl netstat -s --global			>> skywalk.txt		2>&1
 
 	echo "#"							>> skywalk.txt
-	echo "# skywalkctl netstat --netif"				>> skywalk.txt
-	echo "#"							>> skywalk.txt
-	/usr/sbin/skywalkctl netstat --netif				>> skywalk.txt		2>&1
-
-	echo "#"							>> skywalk.txt
-	echo "# skywalkctl netstat --flowswitch"			>> skywalk.txt
+	echo "# skywalkctl interface"					>> skywalk.txt
 	echo "#"							>> skywalk.txt
-	/usr/sbin/skywalkctl netstat --flowswitch			>> skywalk.txt		2>&1
+	/usr/sbin/skywalkctl interface					>> skywalk.txt		2>&1
 
 	echo "#"							>> skywalk.txt
-	echo "# skywalkctl netstat --flow-adv"				>> skywalk.txt
+	echo "# skywalkctl channel"					>> skywalk.txt
 	echo "#"							>> skywalk.txt
-	/usr/sbin/skywalkctl netstat --flow-adv				>> skywalk.txt		2>&1
+	/usr/sbin/skywalkctl channel					>> skywalk.txt		2>&1
 
 	echo "#"							>> skywalk.txt
-	echo "# skywalkctl netstat --flow-owner"			>> skywalk.txt
+	echo "# skywalkctl provider -D"					>> skywalk.txt
 	echo "#"							>> skywalk.txt
-	/usr/sbin/skywalkctl netstat --flow-owner			>> skywalk.txt		2>&1
+	/usr/sbin/skywalkctl provider -D				>> skywalk.txt		2>&1
 
 	echo "#"							>> skywalk.txt
 	echo "# skywalkctl netns -a"					>> skywalk.txt
@@ -478,6 +488,10 @@ run_neutil () {
 		echo "# neutil agent dump"						>> network-agents.txt
 		echo "#"								>> network-agents.txt
 		/usr/local/bin/neutil agent dump					>> network-agents.txt	2>&1
+
+		# Generates a default-level log message containing the current file handles that UserEventAgent has
+		/usr/local/bin/neutil session log-file-handles
+		sleep 1 &
 	) &
 }
 
diff --git a/nwi/network_information_server.c b/nwi/network_information_server.c
index a47861a..ffdc047 100644
--- a/nwi/network_information_server.c
+++ b/nwi/network_information_server.c
@@ -395,7 +395,7 @@ add_state_handler()
 		if (state_data_size > MAX_STATEDUMP_SIZE) {
 			SC_log(LOG_ERR, "Network information : state data too large (%zd > %zd)",
 			       state_data_size,
-			       MAX_STATEDUMP_SIZE);
+			       (size_t)MAX_STATEDUMP_SIZE);
 			return NULL;
 		}