+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)
+{
+ union {
+ unsigned char sha1_bytes[CC_SHA1_DIGEST_LENGTH];
+ CFUUIDBytes uuid_bytes;
+ } bytes;
+ CC_SHA1_CTX ctx;
+ char if_name[IF_NAMESIZE];
+ CFUUIDRef uuid;
+ CFStringRef uuid_str;
+
+ // start with interface name
+ bzero(&if_name, sizeof(if_name));
+ (void) _SC_cfstring_to_cstring(bsdName,
+ if_name,
+ sizeof(if_name),
+ kCFStringEncodingASCII);
+
+ // create SHA1 hash
+ bzero(&bytes, sizeof(bytes));
+ CC_SHA1_Init(&ctx);
+ CC_SHA1_Update(&ctx,
+ if_name,
+ sizeof(if_name));
+ CC_SHA1_Final(bytes.sha1_bytes, &ctx);
+
+ // create UUID string
+ uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes.uuid_bytes);
+ uuid_str = CFUUIDCreateString(NULL, uuid);
+ CFRelease(uuid);
+
+ return uuid_str;
+}
+
+
+static void
+updatePreConfiguredConfiguration(SCPreferencesRef prefs)
+{
+ Boolean ok;
+ CFRange range;
+ SCNetworkSetRef set;
+ Boolean updated = FALSE;
+
+ range.length = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0;
+ if (range.length == 0) {
+ // if no [preconfigured] interfaces
+ return;
+ }
+ range.location = 0;
+
+ set = SCNetworkSetCopyCurrent(prefs);
+ if (set != NULL) {
+ CFArrayRef services;
+
+ /*
+ * Check for (and remove) and network services associated with
+ * a pre-configured 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(preconfigured, range, bsdName)) {
+ // if not preconfigured
+ continue;
+ }
+
+ // remove [preconfigured] network service from the prefs
+ SC_log(LOG_NOTICE, "removing network service for %@", bsdName);
+ SCNetworkServiceRemove(service);
+ 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_NOTICE, "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;
+ SCNetworkServiceRef service;
+
+ bsdName = CFArrayGetValueAtIndex(preconfigured, i);
+ interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces);
+ if (interface == NULL) {
+ SC_log(LOG_ERR, "could not create network interface for %@", bsdName);
+ continue;
+ }
+
+ if (_SCNetworkInterfaceGetIOPath(interface) == NULL) {
+ // if no [real] interface exists
+ CFRelease(interface);
+ continue;
+ }
+
+ ok = SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface);
+ CFRelease(interface);
+ if (!ok) {
+ SC_log(LOG_ERR, "could not create network service for %@", bsdName);
+ 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);
+
+ CFRelease(service);
+ } else {
+ SC_log(LOG_ERR, "could not find network service for %@", bsdName);
+ }
+ }
+
+ CFRelease(set);
+ }
+
+ return;
+}
+
+