1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <dirent.h> 18 19 #define LOG_TAG "InterfaceController" 20 #include <cutils/log.h> 21 #include <logwrap/logwrap.h> 22 23 #include "InterfaceController.h" 24 #include "RouteController.h" 25 26 const char ipv6_proc_path[] = "/proc/sys/net/ipv6/conf"; 27 28 const char sys_net_path[] = "/sys/class/net"; 29 30 const char wl_util_path[] = "/system/xbin/wlutil"; 31 32 InterfaceController::InterfaceController() { 33 // Initial IPv6 settings. 34 // By default, accept_ra is set to 1 (accept RAs unless forwarding is on) on all interfaces. 35 // This causes RAs to work or not work based on whether forwarding is on, and causes routes 36 // learned from RAs to go away when forwarding is turned on. Make this behaviour predictable 37 // by always setting accept_ra to 2. 38 setAcceptRA("2"); 39 40 setAcceptRARouteTable(-RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX); 41 42 // Enable optimistic DAD for IPv6 addresses on all interfaces. 43 setIPv6OptimisticMode("1"); 44 } 45 46 InterfaceController::~InterfaceController() { 47 } 48 49 int InterfaceController::writeIPv6ProcPath(const char *interface, const char *setting, const char *value) { 50 char *path; 51 if (!isIfaceName(interface)) { 52 errno = ENOENT; 53 return -1; 54 } 55 asprintf(&path, "%s/%s/%s", ipv6_proc_path, interface, setting); 56 int success = writeFile(path, value, strlen(value)); 57 free(path); 58 return success; 59 } 60 61 int InterfaceController::setEnableIPv6(const char *interface, const int on) { 62 // When disable_ipv6 changes from 1 to 0, the kernel starts autoconf. 63 // When disable_ipv6 changes from 0 to 1, the kernel clears all autoconf 64 // addresses and routes and disables IPv6 on the interface. 65 const char *disable_ipv6 = on ? "0" : "1"; 66 return writeIPv6ProcPath(interface, "disable_ipv6", disable_ipv6); 67 } 68 69 int InterfaceController::setIPv6PrivacyExtensions(const char *interface, const int on) { 70 // 0: disable IPv6 privacy addresses 71 // 0: enable IPv6 privacy addresses and prefer them over non-privacy ones. 72 return writeIPv6ProcPath(interface, "use_tempaddr", on ? "2" : "0"); 73 } 74 75 // Enables or disables IPv6 ND offload. This is useful for 464xlat on wifi, IPv6 tethering, and 76 // generally implementing IPv6 neighbour discovery and duplicate address detection properly. 77 // TODO: This should be implemented in wpa_supplicant via driver commands instead. 78 int InterfaceController::setIPv6NdOffload(char* interface, const int on) { 79 // Only supported on Broadcom chipsets via wlutil for now. 80 if (access(wl_util_path, X_OK) == 0) { 81 const char *argv[] = { 82 wl_util_path, 83 "-a", 84 interface, 85 "ndoe", 86 on ? "1" : "0" 87 }; 88 int ret = android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL, 89 false, false); 90 ALOGD("%s ND offload on %s: %d (%s)", 91 (on ? "enabling" : "disabling"), interface, ret, strerror(errno)); 92 return ret; 93 } else { 94 return 0; 95 } 96 } 97 98 int InterfaceController::isInterfaceName(const char *name) { 99 return strcmp(name, ".") && 100 strcmp(name, "..") && 101 strcmp(name, "default") && 102 strcmp(name, "all"); 103 } 104 105 void InterfaceController::setOnAllInterfaces(const char* filename, const char* value) { 106 // Set the default value, which is used by any interfaces that are created in the future. 107 writeIPv6ProcPath("default", filename, value); 108 109 // Set the value on all the interfaces that currently exist. 110 DIR* dir = opendir(ipv6_proc_path); 111 if (!dir) { 112 ALOGE("Can't list %s: %s", ipv6_proc_path, strerror(errno)); 113 return; 114 } 115 dirent* d; 116 while ((d = readdir(dir))) { 117 if (d->d_type == DT_DIR && isInterfaceName(d->d_name)) { 118 writeIPv6ProcPath(d->d_name, filename, value); 119 } 120 } 121 closedir(dir); 122 } 123 124 void InterfaceController::setAcceptRA(const char *value) { 125 setOnAllInterfaces("accept_ra", value); 126 } 127 128 // |tableOrOffset| is interpreted as: 129 // If == 0: default. Routes go into RT6_TABLE_MAIN. 130 // If > 0: user set. Routes go into the specified table. 131 // If < 0: automatic. The absolute value is intepreted as an offset and added to the interface 132 // ID to get the table. If it's set to -1000, routes from interface ID 5 will go into 133 // table 1005, etc. 134 void InterfaceController::setAcceptRARouteTable(int tableOrOffset) { 135 char* value; 136 asprintf(&value, "%d", tableOrOffset); 137 setOnAllInterfaces("accept_ra_rt_table", value); 138 free(value); 139 } 140 141 int InterfaceController::setMtu(const char *interface, const char *mtu) 142 { 143 char *path; 144 if (!isIfaceName(interface)) { 145 errno = ENOENT; 146 return -1; 147 } 148 asprintf(&path, "%s/%s/mtu", sys_net_path, interface); 149 int success = writeFile(path, mtu, strlen(mtu)); 150 free(path); 151 return success; 152 } 153 154 void InterfaceController::setIPv6OptimisticMode(const char *value) { 155 setOnAllInterfaces("optimistic_dad", value); 156 setOnAllInterfaces("use_optimistic", value); 157 } 158