/*
- * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2010, 2012-2020 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
#include <TargetConditionals.h>
-#include <fcntl.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <unistd.h>
-
+#define SC_LOG_HANDLE __log_PreferencesMonitor
+#define SC_LOG_HANDLE_TYPE static
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include <SystemConfiguration/SCValidation.h>
-
-
+#include "SCNetworkConfigurationInternal.h"
+#include "plugin_shared.h"
/* globals */
-static SCPreferencesRef prefs = NULL;
-static SCDynamicStoreRef store = NULL;
+static SCPreferencesRef prefs = NULL;
+static SCDynamicStoreRef store = NULL;
+
+/* InterfaceNamer[.plugin] monitoring globals */
+static CFMutableArrayRef excluded_interfaces = NULL; // of SCNetworkInterfaceRef
+static CFMutableArrayRef excluded_names = NULL; // of CFStringRef (BSD name)
+static Boolean haveConfiguration = FALSE;
+static CFStringRef namerKey = NULL;
+static CFMutableArrayRef preconfigured_interfaces= NULL; // of SCNetworkInterfaceRef
+static CFMutableArrayRef preconfigured_names = NULL; // of CFStringRef (BSD name)
-/* preferences "initialization" globals */
-static CFStringRef initKey = NULL;
-static CFRunLoopSourceRef initRls = NULL;
+/* KernelEventMonitor[.plugin] monitoring globals */
+static CFStringRef interfacesKey = NULL;
/* SCDynamicStore (Setup:) */
static CFMutableDictionaryRef currentPrefs; /* current prefs */
static CFMutableArrayRef unchangedPrefsKeys; /* new prefs keys which match current */
static CFMutableArrayRef removedPrefsKeys; /* old prefs keys to be removed */
-static Boolean rofs = FALSE;
-static Boolean _verbose = FALSE;
+static Boolean rofs = FALSE;
+
+#define MY_PLUGIN_NAME "PreferencesMonitor"
+#define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
+
+
+static void
+updateConfiguration(SCPreferencesRef prefs,
+ SCPreferencesNotification notificationType,
+ void *info);
+
+
+static os_log_t
+__log_PreferencesMonitor(void)
+{
+ static os_log_t log = NULL;
+
+ if (log == NULL) {
+ log = os_log_create("com.apple.SystemConfiguration", "PreferencesMonitor");
+ }
+
+ return log;
+}
+
+
+static void
+savePastConfiguration(CFStringRef old_model)
+{
+ CFDictionaryRef system;
+
+ // save "/System" (e.g. host names)
+ system = SCPreferencesGetValue(prefs, kSCPrefSystem);
+ if (system != NULL) {
+ CFRetain(system);
+ }
+
+ // save the [previous devices] configuration
+ __SCNetworkConfigurationSaveModel(prefs, old_model);
+
+ if (system != NULL) {
+ // and retain "/System" (e.g. host names)
+ SCPreferencesSetValue(prefs, kSCPrefSystem, system);
+ CFRelease(system);
+ }
+
+ return;
+}
static Boolean
establishNewPreferences()
{
- CFBundleRef bundle;
SCNetworkSetRef current = NULL;
+ CFStringRef new_model;
Boolean ok = FALSE;
+ CFStringRef old_model;
int sc_status = kSCStatusFailed;
SCNetworkSetRef set = NULL;
- CFStringRef setName = NULL;
Boolean updated = FALSE;
while (TRUE) {
if (sc_status == kSCStatusStale) {
SCPreferencesSynchronize(prefs);
} else {
- SCLog(TRUE, LOG_ERR,
- CFSTR("Could not acquire network configuration lock: %s"),
- SCErrorString(sc_status));
+ SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s",
+ SCErrorString(sc_status));
return FALSE;
}
}
+ // check if we need to regenerate the configuration for a new model
+ old_model = SCPreferencesGetValue(prefs, MODEL);
+ new_model = _SC_hw_model(FALSE);
+ if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
+ SC_log(LOG_NOTICE, "Hardware model changed\n"
+ " created on \"%@\"\n"
+ " now on \"%@\"",
+ old_model,
+ new_model);
+
+ // save (and clean) the configuration that was created for "other" hardware
+ savePastConfiguration(old_model);
+ }
+
current = SCNetworkSetCopyCurrent(prefs);
if (current != NULL) {
set = current;
}
if (set == NULL) {
- set = SCNetworkSetCreate(prefs);
+ set = _SCNetworkSetCreateDefault(prefs);
if (set == NULL) {
ok = FALSE;
sc_status = SCError();
goto done;
}
-
- bundle = _SC_CFBundleGet();
- if (bundle != NULL) {
- setName = CFBundleCopyLocalizedString(bundle,
- CFSTR("DEFAULT_SET_NAME"),
- CFSTR("Automatic"),
- NULL);
- }
-
- ok = SCNetworkSetSetName(set, (setName != NULL) ? setName : CFSTR("Automatic"));
- if (!ok) {
- sc_status = SCError();
- goto done;
- }
-
- ok = SCNetworkSetSetCurrent(set);
- if (!ok) {
- sc_status = SCError();
- goto done;
- }
}
ok = SCNetworkSetEstablishDefaultConfiguration(set);
if (ok) {
ok = SCPreferencesCommitChanges(prefs);
if (ok) {
- SCLog(TRUE, LOG_NOTICE, CFSTR("New network configuration saved"));
+ SC_log(LOG_NOTICE, "New network configuration saved");
updated = TRUE;
} else {
sc_status = SCError();
}
if (!ok) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("Could not establish network configuration: %s"),
- SCErrorString(sc_status));
+ if (sc_status == kSCStatusOK) {
+ SC_log(LOG_NOTICE, "Network configuration not updated");
+ } else {
+ SC_log(LOG_NOTICE, "Could not establish network configuration: %s",
+ SCErrorString(sc_status));
+ }
}
(void)SCPreferencesUnlock(prefs);
- if (setName != NULL) CFRelease(setName);
if (set != NULL) CFRelease(set);
return updated;
}
-static Boolean
-quiet(Boolean *timeout)
+static void
+watchSCDynamicStore()
{
- CFDictionaryRef dict;
- Boolean _quiet = FALSE;
- Boolean _timeout = FALSE;
+ CFMutableArrayRef keys;
+ Boolean ok;
+ CFRunLoopSourceRef rls;
- // check if quiet
- dict = SCDynamicStoreCopyValue(store, initKey);
- if (dict != NULL) {
- if (isA_CFDictionary(dict)) {
- if (CFDictionaryContainsKey(dict, CFSTR("*QUIET*"))) {
- _quiet = TRUE;
- }
- if (CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*"))) {
- _timeout = TRUE;
- }
- }
- CFRelease(dict);
+ /*
+ * watch for KernelEventMonitor[.bundle] changes (the list of
+ * active network interfaces)
+ */
+ interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
+ kSCDynamicStoreDomainState);
+
+ /*
+ * watch for InterfaceNamer[.bundle] changes (quiet, timeout,
+ * and the list of pre-configured interfaces)
+ */
+ namerKey = SCDynamicStoreKeyCreate(NULL,
+ CFSTR("%@" "InterfaceNamer"),
+ kSCDynamicStoreDomainPlugin);
+
+ rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
+ if (rls == NULL) {
+ SC_log(LOG_NOTICE, "SCDynamicStoreCreateRunLoopSource() failed: %s", SCErrorString(SCError()));
+ haveConfiguration = TRUE;
+ return;
}
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+ CFRelease(rls);
- if (timeout != NULL) {
- *timeout = _timeout;
+ keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(keys, interfacesKey);
+ CFArrayAppendValue(keys, namerKey);
+ ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
+ CFRelease(keys);
+ if (!ok) {
+ SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
+ haveConfiguration = TRUE;
}
- return _quiet;
+
+ return;
}
-static void
-watchQuietDisable()
+static Boolean
+findInterfaces(CFArrayRef interfaces, CFMutableArrayRef *matched_interfaces, CFMutableArrayRef *matched_names)
{
- if ((initKey == NULL) || (initRls == NULL)) {
- return;
+ CFIndex n;
+ CFIndex nx = 0;
+ Boolean updated = FALSE;
+
+ // start clean
+ if (*matched_interfaces != NULL) {
+ CFRelease(*matched_interfaces);
+ *matched_interfaces = NULL;
+ }
+ if (*matched_names != NULL) {
+ nx = CFArrayGetCount(*matched_names);
+ CFRelease(*matched_names);
+ *matched_names = NULL;
}
- (void) SCDynamicStoreSetNotificationKeys(store, NULL, NULL);
-
- CFRunLoopSourceInvalidate(initRls);
- CFRelease(initRls);
- initRls = NULL;
+ n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
+ for (CFIndex i = 0; i < n; i++) {
+ CFStringRef bsdName = CFArrayGetValueAtIndex(interfaces, i);
+ SCNetworkInterfaceRef interface;
- CFRelease(initKey);
- initKey = NULL;
+ for (int retry = 0; retry < 10; retry++) {
+ if (retry != 0) {
+ // add short delay (before retry)
+ usleep(20 * 1000); // 20ms
+ }
- return;
-}
+ 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 SCNetworkInterface not [currently] available
+ continue;
+ }
-static void
-watchQuietEnable()
-{
- CFArrayRef keys;
- Boolean ok;
+ // keep track of the interface name (quicker than having to iterate the list
+ // of SCNetworkInterfaces, extract the name, and compare).
+ if (*matched_names == NULL) {
+ *matched_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(*matched_names, bsdName);
- initKey = SCDynamicStoreKeyCreate(NULL,
- CFSTR("%@" "InterfaceNamer"),
- kSCDynamicStoreDomainPlugin);
+ if (*matched_interfaces == NULL) {
+ *matched_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(*matched_interfaces, interface);
+ CFRelease(interface);
- initRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), initRls, kCFRunLoopDefaultMode);
+ updated = TRUE;
+ break;
+ }
+ }
- keys = CFArrayCreate(NULL, (const void **)&initKey, 1, &kCFTypeArrayCallBacks);
- ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
- CFRelease(keys);
- if (!ok) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
- watchQuietDisable();
+ // check if all interfaces were detached
+ n = (*matched_names != NULL) ? CFArrayGetCount(*matched_names) : 0;
+ if ((nx > 0) && (n == 0)) {
+ updated = TRUE;
}
- return;
+ return updated;
}
+
static void
-watchQuietCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
+storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
{
- Boolean _quiet;
- Boolean _timeout = FALSE;
+#pragma unused(info)
+ CFDictionaryRef dict;
+ Boolean quiet = FALSE;
+ Boolean timeout = FALSE;
+ Boolean updated = FALSE;
- _quiet = quiet(&_timeout);
- if (_quiet
-#if !TARGET_OS_IPHONE
- || _timeout
-#endif /* !TARGET_OS_IPHONE */
- ) {
- watchQuietDisable();
+ /*
+ * Capture/process InterfaceNamer[.bundle] info
+ * 1. check if IORegistry "quiet", "timeout"
+ * 2. update list of excluded interfaces (e.g. those requiring that
+ * the attached host be trusted)
+ * 3. update list of named pre-configured interfaces
+ */
+ dict = SCDynamicStoreCopyValue(store, namerKey);
+ if (dict != NULL) {
+ if (isA_CFDictionary(dict)) {
+ CFArrayRef excluded;
+ CFArrayRef preconfigured;
+
+ if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet)) {
+ quiet = TRUE;
+ }
+ if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Timeout)) {
+ timeout = TRUE;
+ }
+
+ excluded = CFDictionaryGetValue(dict, kInterfaceNamerKey_ExcludedInterfaces);
+ excluded = isA_CFArray(excluded);
+ if (!_SC_CFEqual(excluded, excluded_names)) {
+ Boolean excluded_updated;
+
+ excluded_updated = findInterfaces(excluded, &excluded_interfaces, &excluded_names);
+ if (excluded_updated) {
+ CFStringRef interfaces = CFSTR("<empty>");
+
+ // report [updated] pre-configured interfaces
+ if (excluded_names != NULL) {
+ interfaces = CFStringCreateByCombiningStrings(NULL, excluded_names, CFSTR(","));
+ } else {
+ CFRetain(interfaces);
+ }
+ SC_log(LOG_INFO, "excluded interface list changed: %@", interfaces);
+ CFRelease(interfaces);
+
+ updated = TRUE;
+ }
+ }
+
+ preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces);
+ preconfigured = isA_CFArray(preconfigured);
+ if (!_SC_CFEqual(preconfigured, preconfigured_names)) {
+ Boolean preconfigured_updated;
+
+ preconfigured_updated = findInterfaces(preconfigured, &preconfigured_interfaces, &preconfigured_names);
+ if (preconfigured_updated) {
+ CFStringRef interfaces = CFSTR("<empty>");
+
+ // 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);
+
+ updated = TRUE;
+ }
+ }
+ }
+
+ CFRelease(dict);
}
- if (_quiet || _timeout) {
+ if (!haveConfiguration && (quiet || timeout)) {
static int logged = 0;
+ if (quiet
+#if !TARGET_OS_IPHONE
+ || timeout
+#endif /* !TARGET_OS_IPHONE */
+ ) {
+ haveConfiguration = TRUE;
+ }
+
(void) establishNewPreferences();
- if (_timeout && (logged++ == 0)) {
- SCLog(TRUE, LOG_NOTICE,
- CFSTR("Network configuration creation timed out waiting for IORegistry"));
+
+ if (timeout && (logged++ == 0)) {
+ SC_log(LOG_ERR, "Network configuration creation timed out waiting for IORegistry");
}
}
+ if (updated && (changedKeys != NULL)) {
+ // if pre-configured interface list changed
+ updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
+ }
+
return;
}
static void
updateCache(const void *key, const void *value, void *context)
{
+#pragma unused(context)
CFStringRef configKey = (CFStringRef)key;
CFPropertyListRef configData = (CFPropertyListRef)value;
CFPropertyListRef cacheData;
subset = SCPreferencesPathGetValue(prefs, link);
if (!subset) {
/* if error with link */
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCPreferencesPathGetValue(,%@,) failed: %s"),
- link,
- SCErrorString(SCError()));
+ SC_log(LOG_NOTICE, "SCPreferencesPathGetValue(,%@,) failed: %s",
+ link,
+ SCErrorString(SCError()));
return;
}
}
}
+static void
+excludeConfigurations(SCPreferencesRef prefs)
+{
+ Boolean ok;
+ CFRange range;
+ CFArrayRef services;
+ SCNetworkSetRef set;
+
+ range = CFRangeMake(0,
+ (excluded_names != NULL) ? CFArrayGetCount(excluded_names) : 0);
+ if (range.length == 0) {
+ // if no [excluded] interfaces
+ return;
+ }
+
+ set = SCNetworkSetCopyCurrent(prefs);
+ if (set == NULL) {
+ // if no current set
+ return;
+ }
+
+ /*
+ * Check for (and remove) any network services associated with
+ * an excluded interface from the prefs.
+ */
+ services = SCNetworkSetCopyServices(set);
+ 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;
+ }
+
+ bsdName = SCNetworkInterfaceGetBSDName(interface);
+ if (bsdName == NULL) {
+ // if no interface name
+ continue;
+ }
+
+ if (!CFArrayContainsValue(excluded_names, range, bsdName)) {
+ // if not excluded
+ continue;
+ }
+
+ // remove [excluded] network service from the prefs
+ SC_log(LOG_NOTICE, "excluding network service for %@", bsdName);
+ ok = SCNetworkSetRemoveService(set, service);
+ if (!ok) {
+ SC_log(LOG_ERR, "SCNetworkSetRemoveService() failed: %s",
+ SCErrorString(SCError()));
+ }
+ }
+
+ CFRelease(services);
+ }
+
+ CFRelease(set);
+ return;
+}
+
+
+static void
+updatePreConfiguredConfiguration(SCPreferencesRef prefs)
+{
+ Boolean ok;
+ CFRange range;
+ CFArrayRef services;
+ SCNetworkSetRef set;
+ Boolean updated = FALSE;
+
+ range = CFRangeMake(0,
+ (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0);
+ if (range.length == 0) {
+ // if no [pre-configured] interfaces
+ return;
+ }
+
+ set = SCNetworkSetCopyCurrent(prefs);
+ if (set == NULL) {
+ // if no current set
+ return;
+ }
+
+ /*
+ * 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;
+ }
+
+ bsdName = SCNetworkInterfaceGetBSDName(interface);
+ if (bsdName == NULL) {
+ // if no interface name
+ continue;
+ }
+
+ 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) {
+ SC_log(LOG_ERR, "SCNetworkServiceRemove() failed: %s",
+ SCErrorString(SCError()));
+ }
+ updated = TRUE;
+ }
+
+ CFRelease(services);
+ }
+
+ 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()));
+ }
+ }
+ }
+
+ /*
+ * 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;
+
+ bsdName = SCNetworkInterfaceGetBSDName(interface);
+
+ // create network service
+ service = _SCNetworkServiceCreatePreconfigured(prefs, interface);
+ if (service == NULL) {
+ continue;
+ }
+
+ // 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;
+}
+
+
static void
updateSCDynamicStore(SCPreferencesRef prefs)
{
*/
keys = SCPreferencesCopyKeyList(prefs);
if ((keys == NULL) || (CFArrayGetCount(keys) == 0)) {
- SCLog(TRUE, LOG_NOTICE, CFSTR("updateConfiguration(): no preferences."));
+ SC_log(LOG_NOTICE, "updateConfiguration(): no preferences");
goto done;
}
}
if (!isA_CFDictionary(global)) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("updateConfiguration(): %@ is not a dictionary."),
- kSCPrefSystem);
+ SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
+ kSCPrefSystem);
goto done;
}
}
if (!isA_CFString(current)) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("updateConfiguration(): %@ is not a string."),
- kSCPrefCurrentSet);
+ SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a string",
+ kSCPrefCurrentSet);
goto done;
}
set = SCPreferencesPathGetValue(prefs, current);
if (!set) {
/* if error with path */
- SCLog(TRUE, LOG_ERR,
- CFSTR("%@ value (%@) not valid"),
- kSCPrefCurrentSet,
- current);
+ SC_log(LOG_NOTICE, "%@ value (%@) not valid",
+ kSCPrefCurrentSet,
+ current);
goto done;
}
if (!isA_CFDictionary(set)) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("updateConfiguration(): %@ is not a dictionary."),
- current);
+ SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
+ current);
goto done;
}
}
/* Update the dynamic store */
+#ifndef MAIN
if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
- SCErrorString(SCError()));
+ SC_log(LOG_NOTICE, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
}
+#else // !MAIN
+ SC_log(LOG_DEBUG, "SCDynamicStore\nset: %@\nremove: %@",
+ newPrefs,
+ removedPrefsKeys);
+#endif // !MAIN
CFRelease(currentPrefs);
CFRelease(newPrefs);
SCPreferencesNotification notificationType,
void *info)
{
-
-
+#pragma unused(info)
#if !TARGET_OS_IPHONE
if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
SCNetworkSetRef current;
current = SCNetworkSetCopyCurrent(prefs);
if (current != NULL) {
/* network configuration available, disable template creation */
- watchQuietDisable();
+ haveConfiguration = TRUE;
CFRelease(current);
}
}
#endif /* !TARGET_OS_IPHONE */
if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
- return;
+ goto done;
}
- SCLog(_verbose, LOG_DEBUG, CFSTR("updating configuration"));
+ SC_log(LOG_INFO, "updating configuration");
+
+ /* add any [Apple] pre-configured network services */
+ updatePreConfiguredConfiguration(prefs);
+
+ /* remove any excluded network services */
+ excludeConfigurations(prefs);
/* update SCDynamicStore (Setup:) */
updateSCDynamicStore(prefs);
SCPreferencesSynchronize(prefs);
}
+ done :
+
return;
}
void
prime_PreferencesMonitor()
{
- SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
+ SC_log(LOG_DEBUG, "prime() called");
/* load the initial configuration from the database */
updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
}
+#ifndef MAIN
+#define PREFERENCES_MONITOR_PLIST NULL
+#else // !MAIN
+#define PREFERENCES_MONITOR_PLIST CFSTR("/tmp/preferences.plist")
+#endif // !MAIN
+
+
__private_extern__
void
load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
{
- Boolean initPrefs = TRUE;
-
- if (bundleVerbose) {
- _verbose = TRUE;
- }
-
- SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
- SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
+#pragma unused(bundle)
+#pragma unused(bundleVerbose)
+ SC_log(LOG_DEBUG, "load() called");
+ SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle));
/* open a SCDynamicStore session to allow cache updates */
store = SCDynamicStoreCreate(NULL,
CFSTR("PreferencesMonitor.bundle"),
- watchQuietCallback,
+ storeCallback,
NULL);
if (store == NULL) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCDynamicStoreCreate() failed: %s"),
- SCErrorString(SCError()));
+ SC_log(LOG_NOTICE, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
goto error;
}
/* open a SCPreferences session */
- prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
+ prefs = SCPreferencesCreateWithOptions(NULL,
+ MY_PLUGIN_ID,
+ PREFERENCES_MONITOR_PLIST,
+ NULL, // authorization
+ NULL);
if (prefs != NULL) {
- SCNetworkSetRef current;
+ Boolean need_update = FALSE;
+ CFStringRef new_model;
+ CFStringRef old_model;
+
+ // check if we need to update the configuration
+ __SCNetworkConfigurationUpgrade(&prefs, NULL, TRUE);
+
+ // check if we need to regenerate the configuration for a new model
+ old_model = SCPreferencesGetValue(prefs, MODEL);
+ new_model = _SC_hw_model(FALSE);
+ if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
+ SC_log(LOG_NOTICE, "Hardware model changed\n"
+ " created on \"%@\"\n"
+ " now on \"%@\"",
+ old_model,
+ new_model);
+
+ // save (and clean) the configuration that was created for "other" hardware
+ savePastConfiguration(old_model);
+
+ // ... and we'll update the configuration later (when the IORegistry quiesces)
+ need_update = TRUE;
+ }
- current = SCNetworkSetCopyCurrent(prefs);
- if (current != NULL) {
- /* network configuration available, disable template creation */
- initPrefs = FALSE;
- CFRelease(current);
+ if (!need_update) {
+ SCNetworkSetRef current;
+
+ current = SCNetworkSetCopyCurrent(prefs);
+ if (current != NULL) {
+ /* network configuration available, disable template creation */
+ haveConfiguration = TRUE;
+ CFRelease(current);
+ }
}
} else {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCPreferencesCreate() failed: %s"),
- SCErrorString(SCError()));
+ SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
goto error;
}
* register for change notifications.
*/
if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCPreferencesSetCallBack() failed: %s"),
- SCErrorString(SCError()));
+ SC_log(LOG_NOTICE, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
goto error;
}
if (!SCPreferencesScheduleWithRunLoop(prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCPreferencesScheduleWithRunLoop() failed: %s"),
- SCErrorString(SCError()));
+ SC_log(LOG_NOTICE, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
goto error;
}
/*
- * if no preferences, initialize with a template (now or
- * when IOKit has quiesced).
+ * watch InterfaceNamer and KernelEventMonitor changes to know when
+ * the IORegistry has quiesced (to create the initial configuration
+ * template), to track any pre-configured interfaces, and to ensure
+ * that we create a network service for any active interfaces.
*/
- if (initPrefs) {
- watchQuietEnable();
- watchQuietCallback(store, NULL, NULL);
- }
+ watchSCDynamicStore();
+ storeCallback(store, NULL, NULL);
return;
error :
- watchQuietDisable();
if (store != NULL) CFRelease(store);
if (prefs != NULL) CFRelease(prefs);
+ haveConfiguration = TRUE;
return;
}
int
main(int argc, char **argv)
{
- _sc_log = FALSE;
+ _sc_log = kSCLogDestinationFile;
_sc_verbose = (argc > 1) ? TRUE : FALSE;
load_PreferencesMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);