#include <dirent.h>
#include <errno.h>
#include <malloc.h>
+#include <sys/socket.h>
#define LOG_TAG "InterfaceController"
#include <android-base/file.h>
#include "RouteController.h"
using android::base::StringPrintf;
+using android::base::ReadFileToString;
using android::base::WriteStringToFile;
namespace {
const char ipv6_neigh_conf_dir[] = "/proc/sys/net/ipv6/neigh";
+const char proc_net_path[] = "/proc/sys/net";
const char sys_net_path[] = "/sys/class/net";
const char wl_util_path[] = "/vendor/xbin/wlutil";
-bool isInterfaceName(const char *name) {
- return strcmp(name, ".") &&
- strcmp(name, "..") &&
- strcmp(name, "default") &&
- strcmp(name, "all");
+inline bool isNormalPathComponent(const char *component) {
+ return (strcmp(component, ".") != 0) &&
+ (strcmp(component, "..") != 0) &&
+ (strchr(component, '/') == nullptr);
+}
+
+inline bool isAddressFamilyPathComponent(const char *component) {
+ return strcmp(component, "ipv4") == 0 || strcmp(component, "ipv6") == 0;
+}
+
+inline bool isInterfaceName(const char *name) {
+ return isNormalPathComponent(name) &&
+ (strcmp(name, "default") != 0) &&
+ (strcmp(name, "all") != 0);
}
int writeValueToPath(
setOnAllInterfaces(ipv6_proc_path, "use_oif_addrs_only", value);
}
+std::string getParameterPathname(
+ const char *family, const char *which, const char *interface, const char *parameter) {
+ if (!isAddressFamilyPathComponent(family)) {
+ errno = EAFNOSUPPORT;
+ return "";
+ } else if (!isNormalPathComponent(which) ||
+ !isInterfaceName(interface) ||
+ !isNormalPathComponent(parameter)) {
+ errno = EINVAL;
+ return "";
+ }
+
+ return StringPrintf("%s/%s/%s/%s/%s", proc_net_path, family, which, interface, parameter);
+}
+
} // namespace
void InterfaceController::initializeAll() {
return writeValueToPath(sys_net_path, interface, "mtu", mtu);
}
-
int InterfaceController::addAddress(const char *interface,
const char *addrString, int prefixLength) {
return ifc_add_address(interface, addrString, prefixLength);
return ifc_del_address(interface, addrString, prefixLength);
}
+int InterfaceController::getParameter(
+ const char *family, const char *which, const char *interface, const char *parameter,
+ std::string *value) {
+ const std::string path(getParameterPathname(family, which, interface, parameter));
+ if (path.empty()) {
+ return -errno;
+ }
+ return ReadFileToString(path, value) ? 0 : -errno;
+}
+
+int InterfaceController::setParameter(
+ const char *family, const char *which, const char *interface, const char *parameter,
+ const char *value) {
+ const std::string path(getParameterPathname(family, which, interface, parameter));
+ if (path.empty()) {
+ return -errno;
+ }
+ return WriteStringToFile(value, path) ? 0 : -errno;
+}
+
void InterfaceController::setBaseReachableTimeMs(unsigned int millis) {
std::string value(StringPrintf("%u", millis));
setOnAllInterfaces(ipv4_neigh_conf_dir, "base_reachable_time_ms", value.c_str());
#ifndef _INTERFACE_CONTROLLER_H
#define _INTERFACE_CONTROLLER_H
+#include <string>
+
class InterfaceController {
public:
static void initializeAll();
static int addAddress(const char *interface, const char *addrString, int prefixLength);
static int delAddress(const char *interface, const char *addrString, int prefixLength);
+ // Read and write values in files of the form:
+ // /proc/sys/net/<family>/<which>/<interface>/<parameter>
+ static int getParameter(
+ const char *family, const char *which, const char *interface, const char *parameter,
+ std::string *value);
+ static int setParameter(
+ const char *family, const char *which, const char *interface, const char *parameter,
+ const char *value);
+
private:
static void setAcceptRA(const char* value);
static void setAcceptRARouteTable(int tableOrOffset);
#include "Controllers.h"
#include "DumpWriter.h"
+#include "InterfaceController.h"
#include "NetdConstants.h"
#include "NetdNativeService.h"
#include "RouteController.h"
return binder::Status::ok();
}
+binder::Status NetdNativeService::setProcSysNet(
+ int32_t family, int32_t which, const std::string &ifname, const std::string ¶meter,
+ const std::string &value) {
+ ENFORCE_PERMISSION(CONNECTIVITY_INTERNAL);
+
+ const char *familyStr;
+ switch (family) {
+ case INetd::IPV4:
+ familyStr = "ipv4";
+ break;
+ case INetd::IPV6:
+ familyStr = "ipv6";
+ break;
+ default:
+ return binder::Status::fromServiceSpecificError(EAFNOSUPPORT, String8("Bad family"));
+ }
+
+ const char *whichStr;
+ switch (which) {
+ case INetd::CONF:
+ whichStr = "conf";
+ break;
+ case INetd::NEIGH:
+ whichStr = "neigh";
+ break;
+ default:
+ return binder::Status::fromServiceSpecificError(EINVAL, String8("Bad category"));
+ }
+
+ const int err = InterfaceController::setParameter(
+ familyStr, whichStr, ifname.c_str(), parameter.c_str(),
+ value.c_str());
+ if (err != 0) {
+ return binder::Status::fromServiceSpecificError(-err,
+ String8::format("ResolverController error: %s", strerror(-err)));
+ }
+ return binder::Status::ok();
+}
+
} // namespace net
} // namespace android
const std::string &addrString, int prefixLength) override;
binder::Status interfaceDelAddress(const std::string &ifName,
const std::string &addrString, int prefixLength) override;
+
+ binder::Status setProcSysNet(
+ int32_t family, int32_t which, const std::string &ifname, const std::string ¶meter,
+ const std::string &value) override;
};
} // namespace net
int prefixLength);
void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString,
int prefixLength);
+
+ /*
+ * Set and get /proc/sys/net interface configuration parameters.
+ *
+ * @param family One of IPV4/IPV6 integers, indicating the desired address family directory.
+ * @param which One of CONF/NEIGH integers, indicating the desired parameter category directory.
+ * @param ifname The interface name portion of the path; may also be "all" or "default".
+ * @param parameter The parameter name portion of the path.
+ * @param value The value string to be written into the assembled path.
+ */
+
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ void setProcSysNet(int family, int which, in @utf8InCpp String ifname,
+ in @utf8InCpp String parameter, in @utf8InCpp String value);
+ // TODO: add corresponding getProcSysNet().
}
EXPECT_FALSE(interfaceHasAddress(sTunIfName, td.addrString, -1));
}
}
+
+TEST_F(BinderTest, TestSetProcSysNet) {
+ static const struct TestData {
+ const int family;
+ const int which;
+ const char *ifname;
+ const char *parameter;
+ const char *value;
+ const int expectedReturnCode;
+ } kTestData[] = {
+ { INetd::IPV4, INetd::CONF, sTunIfName.c_str(), "arp_ignore", "1", 0 },
+ { -1, INetd::CONF, sTunIfName.c_str(), "arp_ignore", "1", EAFNOSUPPORT },
+ { INetd::IPV4, -1, sTunIfName.c_str(), "arp_ignore", "1", EINVAL },
+ { INetd::IPV4, INetd::CONF, "..", "conf/lo/arp_ignore", "1", EINVAL },
+ { INetd::IPV4, INetd::CONF, ".", "lo/arp_ignore", "1", EINVAL },
+ { INetd::IPV4, INetd::CONF, sTunIfName.c_str(), "../all/arp_ignore", "1", EINVAL },
+ { INetd::IPV6, INetd::NEIGH, sTunIfName.c_str(), "ucast_solicit", "7", 0 },
+ };
+
+ for (unsigned int i = 0; i < arraysize(kTestData); i++) {
+ const auto &td = kTestData[i];
+
+ const binder::Status status = mNetd->setProcSysNet(
+ td.family, td.which, td.ifname, td.parameter,
+ td.value);
+
+ if (td.expectedReturnCode == 0) {
+ SCOPED_TRACE(String8::format("test case %d should have passed", i));
+ EXPECT_EQ(0, status.exceptionCode());
+ EXPECT_EQ(0, status.serviceSpecificErrorCode());
+ } else {
+ SCOPED_TRACE(String8::format("test case %d should have failed", i));
+ EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode());
+ EXPECT_EQ(td.expectedReturnCode, status.serviceSpecificErrorCode());
+ }
+ }
+}