Skip to content

Commit

Permalink
Add general /proc/sys/net/ipv[46]/{conf,neigh}/ interface
Browse files Browse the repository at this point in the history
Bug: 21859053
Bug: 28135208
Change-Id: Ia3232706a697fd149ed87f74586efe3d434261f8
  • Loading branch information
Erik Kline committed Sep 2, 2016
1 parent 59d8c48 commit b218a87
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 6 deletions.
58 changes: 52 additions & 6 deletions server/InterfaceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <dirent.h>
#include <errno.h>
#include <malloc.h>
#include <sys/socket.h>

#define LOG_TAG "InterfaceController"
#include <android-base/file.h>
Expand All @@ -29,6 +30,7 @@
#include "RouteController.h"

using android::base::StringPrintf;
using android::base::ReadFileToString;
using android::base::WriteStringToFile;

namespace {
Expand All @@ -39,15 +41,25 @@ const char ipv4_neigh_conf_dir[] = "/proc/sys/net/ipv4/neigh";

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(
Expand Down Expand Up @@ -81,6 +93,21 @@ void setIPv6UseOutgoingInterfaceAddrsOnly(const char *value) {
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() {
Expand Down Expand Up @@ -201,7 +228,6 @@ int InterfaceController::setMtu(const char *interface, const char *mtu)
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);
Expand All @@ -212,6 +238,26 @@ int InterfaceController::delAddress(const char *interface,
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());
Expand Down
11 changes: 11 additions & 0 deletions server/InterfaceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#ifndef _INTERFACE_CONTROLLER_H
#define _INTERFACE_CONTROLLER_H

#include <string>

class InterfaceController {
public:
static void initializeAll();
Expand All @@ -31,6 +33,15 @@ class InterfaceController {
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);
Expand Down
40 changes: 40 additions & 0 deletions server/NetdNativeService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include "Controllers.h"
#include "DumpWriter.h"
#include "InterfaceController.h"
#include "NetdConstants.h"
#include "NetdNativeService.h"
#include "RouteController.h"
Expand Down Expand Up @@ -235,5 +236,44 @@ binder::Status NetdNativeService::interfaceDelAddress(const std::string &ifName,
return binder::Status::ok();
}

binder::Status NetdNativeService::setProcSysNet(
int32_t family, int32_t which, const std::string &ifname, const std::string &parameter,
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
4 changes: 4 additions & 0 deletions server/NetdNativeService.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
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 &parameter,
const std::string &value) override;
};

} // namespace net
Expand Down
18 changes: 18 additions & 0 deletions server/binder/android/net/INetd.aidl
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,22 @@ interface INetd {
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().
}
37 changes: 37 additions & 0 deletions tests/binder_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,3 +617,40 @@ TEST_F(BinderTest, TestInterfaceAddRemoveAddress) {
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());
}
}
}

0 comments on commit b218a87

Please sign in to comment.