InterfaceController.cpp revision 0ea8ff87012f6bda41b6d2b4629d4fd0fd6f4794
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 26const char ipv6_proc_path[] = "/proc/sys/net/ipv6/conf"; 27 28const char sys_net_path[] = "/sys/class/net"; 29 30const char wl_util_path[] = "/system/xbin/wlutil"; 31 32InterfaceController::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 43InterfaceController::~InterfaceController() { 44} 45 46int InterfaceController::writeIPv6ProcPath(const char *interface, const char *setting, const char *value) { 47 char *path; 48 if (!isIfaceName(interface)) { 49 errno = ENOENT; 50 return -1; 51 } 52 asprintf(&path, "%s/%s/%s", ipv6_proc_path, interface, setting); 53 int success = writeFile(path, value, strlen(value)); 54 free(path); 55 return success; 56} 57 58int InterfaceController::setEnableIPv6(const char *interface, const int on) { 59 // When disable_ipv6 changes from 1 to 0, the kernel starts autoconf. 60 // When disable_ipv6 changes from 0 to 1, the kernel clears all autoconf 61 // addresses and routes and disables IPv6 on the interface. 62 const char *disable_ipv6 = on ? "0" : "1"; 63 return writeIPv6ProcPath(interface, "disable_ipv6", disable_ipv6); 64} 65 66int InterfaceController::setIPv6PrivacyExtensions(const char *interface, const int on) { 67 // 0: disable IPv6 privacy addresses 68 // 0: enable IPv6 privacy addresses and prefer them over non-privacy ones. 69 return writeIPv6ProcPath(interface, "use_tempaddr", on ? "2" : "0"); 70} 71 72// Enables or disables IPv6 ND offload. This is useful for 464xlat on wifi, IPv6 tethering, and 73// generally implementing IPv6 neighbour discovery and duplicate address detection properly. 74// TODO: This should be implemented in wpa_supplicant via driver commands instead. 75int InterfaceController::setIPv6NdOffload(char* interface, const int on) { 76 // Only supported on Broadcom chipsets via wlutil for now. 77 if (access(wl_util_path, X_OK) == 0) { 78 const char *argv[] = { 79 wl_util_path, 80 "-a", 81 interface, 82 "ndoe", 83 on ? "1" : "0" 84 }; 85 int ret = android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL, 86 false, false); 87 ALOGD("%s ND offload on %s: %d (%s)", 88 (on ? "enabling" : "disabling"), interface, ret, strerror(errno)); 89 return ret; 90 } else { 91 return 0; 92 } 93} 94 95int InterfaceController::isInterfaceName(const char *name) { 96 return strcmp(name, ".") && 97 strcmp(name, "..") && 98 strcmp(name, "default") && 99 strcmp(name, "all"); 100} 101 102void InterfaceController::setOnAllInterfaces(const char* filename, const char* value) { 103 // Set the default value, which is used by any interfaces that are created in the future. 104 writeIPv6ProcPath("default", filename, value); 105 106 // Set the value on all the interfaces that currently exist. 107 DIR* dir = opendir(ipv6_proc_path); 108 if (!dir) { 109 ALOGE("Can't list %s: %s", ipv6_proc_path, strerror(errno)); 110 return; 111 } 112 dirent* d; 113 while ((d = readdir(dir))) { 114 if (d->d_type == DT_DIR && isInterfaceName(d->d_name)) { 115 writeIPv6ProcPath(d->d_name, filename, value); 116 } 117 } 118 closedir(dir); 119} 120 121void InterfaceController::setAcceptRA(const char *value) { 122 setOnAllInterfaces("accept_ra", value); 123} 124 125// |tableOrOffset| is interpreted as: 126// If == 0: default. Routes go into RT6_TABLE_MAIN. 127// If > 0: user set. Routes go into the specified table. 128// If < 0: automatic. The absolute value is intepreted as an offset and added to the interface 129// ID to get the table. If it's set to -1000, routes from interface ID 5 will go into 130// table 1005, etc. 131void InterfaceController::setAcceptRARouteTable(int tableOrOffset) { 132 char* value; 133 asprintf(&value, "%d", tableOrOffset); 134 setOnAllInterfaces("accept_ra_rt_table", value); 135 free(value); 136} 137 138int InterfaceController::setMtu(const char *interface, const char *mtu) 139{ 140 char *path; 141 if (!isIfaceName(interface)) { 142 errno = ENOENT; 143 return -1; 144 } 145 asprintf(&path, "%s/%s/mtu", sys_net_path, interface); 146 int success = writeFile(path, mtu, strlen(mtu)); 147 free(path); 148 return success; 149} 150