/* * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Modification History * * October 21, 2000 Allan Nathanson * - initial revision */ #include #include //#include #include #include #include #include #include #include #include #include CFMutableDictionaryRef baseSettings = NULL; SCDynamicStoreRef store = NULL; CFRunLoopSourceRef rls = NULL; Boolean _verbose = FALSE; int __createMediaOptions(CFDictionaryRef media_options); static char * cfstring_to_cstring(CFStringRef cfstr, char *buf, int bufLen) { CFIndex len = CFStringGetLength(cfstr); if (!buf) { bufLen = len + 1; buf = CFAllocatorAllocate(NULL, bufLen, 0); } if (len >= bufLen) { len = bufLen - 1; } (void)CFStringGetBytes(cfstr, CFRangeMake(0, len), kCFStringEncodingASCII, 0, FALSE, buf, bufLen, NULL); buf[len] = '\0'; return buf; } Boolean _NetworkInterfaceSetMediaOptions(CFStringRef interface, CFDictionaryRef options) { CFArrayRef available = NULL; CFDictionaryRef current = NULL; struct ifmediareq ifm; struct ifreq ifr; Boolean ok = FALSE; int newOptions; CFMutableDictionaryRef requested = NULL; int sock = -1; CFTypeRef val; /* get current & available options */ if (!NetworkInterfaceCopyMediaOptions(interface, ¤t, NULL, &available, FALSE)) { return FALSE; } /* extract just the dictionary key/value pairs of interest */ requested = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType); if (!val) { val = CFDictionaryGetValue(current, kSCPropNetEthernetMediaSubType); } if (isA_CFString(val)) { CFDictionaryAddValue(requested, kSCPropNetEthernetMediaSubType, val); } else { /* if garbage */; goto done; } val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions); if (!val) { val = CFDictionaryGetValue(current, kSCPropNetEthernetMediaOptions); } if (isA_CFArray(val)) { CFDictionaryAddValue(requested, kSCPropNetEthernetMediaOptions, val); } else { /* if garbage */; goto done; } if (current && CFEqual(current, requested)) { /* if current settings are as requested */ ok = TRUE; goto done; } if (!CFArrayContainsValue(available, CFRangeMake(0, CFArrayGetCount(available)), requested)) { /* if requested settings not currently available */ SCLog(TRUE, LOG_DEBUG, CFSTR("requested media settings unavailable")); goto done; } newOptions = __createMediaOptions(requested); if (newOptions == -1) { /* since we have just validated, this should never happen */ goto done; } sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno)); goto done; } bzero((char *)&ifm, sizeof(ifm)); (void)cfstring_to_cstring(interface, ifm.ifm_name, sizeof(ifm.ifm_name)); if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) < 0) { SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno)); goto done; } bzero((char *)&ifr, sizeof(ifr)); bcopy(ifm.ifm_name, ifr.ifr_name, sizeof(ifr.ifr_name)); ifr.ifr_media = ifm.ifm_current & ~(IFM_NMASK|IFM_TMASK|IFM_OMASK|IFM_GMASK); ifr.ifr_media |= newOptions; //SCLog(TRUE, LOG_INFO, CFSTR("old media settings: 0x%8.8x (0x%8.8x)"), ifm.ifm_current, ifm.ifm_active); //SCLog(TRUE, LOG_INFO, CFSTR("new media settings: 0x%8.8x"), ifr.ifr_media); if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) { SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCSIFMEDIA) failed: %s"), strerror(errno)); goto done; } ok = TRUE; done : if (available) CFRelease(available); if (current) CFRelease(current); if (requested) CFRelease(requested); if (sock >= 0) (void)close(sock); return ok; } Boolean _NetworkInterfaceSetMTU(CFStringRef interface, CFDictionaryRef options) { struct ifreq ifr; int mtu_cur = -1; int mtu_max = -1; int mtu_min = -1; Boolean ok = FALSE; int requested; int sock = -1; CFNumberRef val; if (!NetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) { /* could not get current MTU */ return FALSE; } val = CFDictionaryGetValue(options, kSCPropNetEthernetMTU); if (val) { if (isA_CFNumber(val)) { CFNumberGetValue(val, kCFNumberIntType, &requested); } else { goto done; } } else { requested = mtu_cur; } if (requested == mtu_cur) { /* if current setting is as requested */ ok = TRUE; goto done; } if (((mtu_min >= 0) && (requested < mtu_min)) || ((mtu_max >= 0) && (requested > mtu_max))) { /* if requested MTU outside of the valid range */ goto done; } bzero((char *)&ifr, sizeof(ifr)); (void)cfstring_to_cstring(interface, ifr.ifr_name, sizeof(ifr.ifr_name)); ifr.ifr_mtu = requested; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno)); goto done; } if (ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr) < 0) { SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCSIFMTU) failed: %s"), strerror(errno)); goto done; } ok = TRUE; done : if (sock >= 0) (void)close(sock); return ok; } /* * Function: parse_component * Purpose: * Given a string 'key' and a string prefix 'prefix', * return the next component in the slash '/' separated * key. * * Examples: * 1. key = "a/b/c" prefix = "a/" * returns "b" * 2. key = "a/b/c" prefix = "a/b/" * returns "c" */ static CFStringRef parse_component(CFStringRef key, CFStringRef prefix) { CFMutableStringRef comp; CFRange range; if (CFStringHasPrefix(key, prefix) == FALSE) { return NULL; } comp = CFStringCreateMutableCopy(NULL, 0, key); CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix))); range = CFStringFind(comp, CFSTR("/"), 0); if (range.location == kCFNotFound) { return comp; } range.length = CFStringGetLength(comp) - range.location; CFStringDelete(comp, range); return comp; } static void updateLink(CFStringRef ifKey, CFDictionaryRef options) { CFStringRef interface = NULL; static CFStringRef prefix = NULL; if (!prefix) { prefix = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@/"), kSCDynamicStoreDomainSetup, kSCCompNetwork, kSCCompInterface); } interface = parse_component(ifKey, prefix); if (!interface) { goto done; } if (options) { if (!CFDictionaryContainsKey(baseSettings, interface)) { CFDictionaryRef cur_media = NULL; CFMutableDictionaryRef new_media = NULL; int cur_mtu = -1; CFNumberRef num; if (!NetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) { /* could not determine current settings */ goto done; } if (!cur_media) { /* could not determine current settings */ goto done; } if (!NetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) { /* could not determine current MTU */ CFRelease(cur_media); goto done; } if (cur_mtu < 0) { /* could not determine current MTU */ CFRelease(cur_media); goto done; } new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media); CFRelease(cur_media); num = CFNumberCreate(NULL, kCFNumberIntType, &cur_mtu); CFDictionaryAddValue(new_media, kSCPropNetEthernetMTU, num); CFRelease(num); CFDictionarySetValue(baseSettings, interface, new_media); CFRelease(new_media); } /* establish new settings */ (void)_NetworkInterfaceSetMediaOptions(interface, options); (void)_NetworkInterfaceSetMTU (interface, options); } else { /* no requested settings */ options = CFDictionaryGetValue(baseSettings, interface); if (options) { /* restore original settings */ (void)_NetworkInterfaceSetMediaOptions(interface, options); (void)_NetworkInterfaceSetMTU (interface, options); CFDictionaryRemoveValue(baseSettings, interface); } } done : if (interface) CFRelease(interface); return; } static void linkConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg) { CFIndex i; CFDictionaryRef linkInfo; linkInfo = SCDynamicStoreCopyMultiple(store, changedKeys, NULL); for (i=0; i 1) ? TRUE : FALSE; load(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE); CFRunLoopRun(); /* not reached */ exit(0); return 0; } #endif