1/* 2 * Copyright (c) 2013, 2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * October 7, 2013 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31 32#include <CoreFoundation/CoreFoundation.h> 33#include <SystemConfiguration/SystemConfiguration.h> 34#include <SystemConfiguration/SCPrivate.h> 35 36#include "eventmon.h" 37#include "ev_extra.h" 38 39 40static CFBooleanRef 41is_expensive(SCNetworkInterfaceRef interface) 42{ 43 CFBooleanRef expensive = NULL; 44 CFStringRef interfaceType; 45 46 while (interface != NULL) { 47 SCNetworkInterfaceRef child; 48 49 child = SCNetworkInterfaceGetInterface(interface); 50 if (child == NULL) { 51 break; 52 } 53 54 interface = child; 55 } 56 57 // assume NOT expensive 58 expensive = kCFBooleanFalse; 59 60 interfaceType = SCNetworkInterfaceGetInterfaceType(interface); 61 if (_SCNetworkInterfaceIsTethered(interface)) { 62 // if tethered (to iOS) interface 63 expensive = kCFBooleanTrue; 64 } else if (_SCNetworkInterfaceIsBluetoothPAN(interface)) { 65 // if BT-PAN interface 66 expensive = kCFBooleanTrue; 67 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN)) { 68 // if WWAN [Ethernet] interface 69 expensive = kCFBooleanTrue; 70 } 71 72 return expensive; 73} 74 75 76static int 77ifexpensive_set(int s, const char * name, uint32_t expensive) 78{ 79#if defined(SIOCSIFEXPENSIVE) && !defined(MAIN) 80 struct ifreq ifr; 81 82 bzero(&ifr, sizeof(ifr)); 83 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 84 ifr.ifr_expensive = expensive; 85 return (ioctl(s, SIOCSIFEXPENSIVE, &ifr)); 86#else // defined(SIOCSIFEXPENSIVE) && !defined(MAIN) 87 return 0; 88#endif // defined(SIOCSIFEXPENSIVE) && !defined(MAIN) 89} 90 91 92__private_extern__ 93CFBooleanRef 94interface_update_expensive(const char *if_name) 95{ 96 CFBooleanRef expensive = NULL; 97 SCNetworkInterfaceRef interface; 98 CFStringRef interface_name; 99 int s; 100 101 interface_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman); 102 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interface_name, kIncludeNoVirtualInterfaces); 103 CFRelease(interface_name); 104 105 if (interface != NULL) { 106 expensive = is_expensive(interface); 107 CFRelease(interface); 108 } 109 110 // mark ... or clear ... the [if_name] interface as "expensive" 111 s = dgram_socket(AF_INET); 112 if (s != -1) { 113 ifexpensive_set(s, 114 if_name, 115 ((expensive != NULL) && CFBooleanGetValue(expensive)) ? 1 : 0); 116 close(s); 117 } 118 119 return expensive; 120} 121 122 123#ifdef MAIN 124 125int 126dgram_socket(int domain) 127{ 128 return (socket(domain, SOCK_DGRAM, 0)); 129} 130 131int 132main(int argc, char **argv) 133{ 134 CFBooleanRef expensive; 135 136 if (argc < 1 + 1) { 137 SCPrint(TRUE, stderr, CFSTR("usage: %s <interface>\n"), argv[0]); 138 exit(1); 139 } 140 141 expensive = interface_update_expensive(argv[1]); 142 if (expensive != NULL) { 143 SCPrint(TRUE, stdout, CFSTR("interface \"%s\": %@\n"), argv[1], expensive); 144 } else { 145 SCPrint(TRUE, stdout, CFSTR("interface \"%s\": could not determine \"expensive\" status\n"), argv[1]); 146 } 147 148 exit(0); 149} 150#endif // MAIN 151