TestNetworkService: Add support for toggling carrier on tun/tap
Adds support for setting carrier to on/off for a tun/tap interface. It turns out that TUNSETCARRIER is also usable by tap interfaces, and TUNSETLINK does not work as expected. Test: atest EthernetManagerTest Change-Id: I39d70e0a65a34e7a4c4df70c53e4cc781a24a213
This commit is contained in:
@@ -32,6 +32,8 @@ interface ITestNetworkManager
|
|||||||
TestNetworkInterface createInterface(boolean isTun, boolean bringUp, in LinkAddress[] addrs,
|
TestNetworkInterface createInterface(boolean isTun, boolean bringUp, in LinkAddress[] addrs,
|
||||||
in @nullable String iface);
|
in @nullable String iface);
|
||||||
|
|
||||||
|
void setCarrierEnabled(in TestNetworkInterface iface, boolean enabled);
|
||||||
|
|
||||||
void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
|
void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
|
||||||
in int[] administratorUids, in IBinder binder);
|
in int[] administratorUids, in IBinder binder);
|
||||||
|
|
||||||
|
|||||||
@@ -231,4 +231,23 @@ public class TestNetworkManager {
|
|||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable / disable carrier on TestNetworkInterface
|
||||||
|
*
|
||||||
|
* Note: TUNSETCARRIER is not supported until kernel version 5.0.
|
||||||
|
* TODO: add RequiresApi annotation.
|
||||||
|
*
|
||||||
|
* @param iface the interface to configure.
|
||||||
|
* @param enabled true to turn carrier on, false to turn carrier off.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
|
||||||
|
public void setCarrierEnabled(@NonNull TestNetworkInterface iface, boolean enabled) {
|
||||||
|
try {
|
||||||
|
mService.setCarrierEnabled(iface, enabled);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,15 @@ static void throwException(JNIEnv* env, int error, const char* action, const cha
|
|||||||
jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
|
jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) {
|
// enable or disable carrier on tun / tap interface.
|
||||||
|
static void setTunTapCarrierEnabledImpl(JNIEnv* env, const char* iface, int tunFd, bool enabled) {
|
||||||
|
uint32_t carrierOn = enabled;
|
||||||
|
if (ioctl(tunFd, TUNSETCARRIER, &carrierOn)) {
|
||||||
|
throwException(env, errno, "set carrier", iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createTunTapImpl(JNIEnv* env, bool isTun, const char* iface) {
|
||||||
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
|
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
|
||||||
ifreq ifr{};
|
ifreq ifr{};
|
||||||
|
|
||||||
@@ -79,23 +87,30 @@ static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static jint create(JNIEnv* env, jobject /* thiz */, jboolean isTun, jstring jIface) {
|
static void setTunTapCarrierEnabled(JNIEnv* env, jclass /* clazz */, jstring
|
||||||
|
jIface, jint tunFd, jboolean enabled) {
|
||||||
|
ScopedUtfChars iface(env, jIface);
|
||||||
|
if (!iface.c_str()) {
|
||||||
|
jniThrowNullPointerException(env, "iface");
|
||||||
|
}
|
||||||
|
setTunTapCarrierEnabledImpl(env, iface.c_str(), tunFd, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint createTunTap(JNIEnv* env, jclass /* clazz */, jboolean isTun, jstring jIface) {
|
||||||
ScopedUtfChars iface(env, jIface);
|
ScopedUtfChars iface(env, jIface);
|
||||||
if (!iface.c_str()) {
|
if (!iface.c_str()) {
|
||||||
jniThrowNullPointerException(env, "iface");
|
jniThrowNullPointerException(env, "iface");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tun = createTunTapInterface(env, isTun, iface.c_str());
|
return createTunTapImpl(env, isTun, iface.c_str());
|
||||||
|
|
||||||
// Any exceptions will be thrown from the createTunTapInterface call
|
|
||||||
return tun;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static const JNINativeMethod gMethods[] = {
|
static const JNINativeMethod gMethods[] = {
|
||||||
{"jniCreateTunTap", "(ZLjava/lang/String;)I", (void*)create},
|
{"nativeSetTunTapCarrierEnabled", "(Ljava/lang/String;IZ)V", (void*)setTunTapCarrierEnabled},
|
||||||
|
{"nativeCreateTunTap", "(ZLjava/lang/String;)I", (void*)createTunTap},
|
||||||
};
|
};
|
||||||
|
|
||||||
int register_com_android_server_TestNetworkService(JNIEnv* env) {
|
int register_com_android_server_TestNetworkService(JNIEnv* env) {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
import com.android.net.module.util.NetdUtils;
|
import com.android.net.module.util.NetdUtils;
|
||||||
import com.android.net.module.util.NetworkStackConstants;
|
import com.android.net.module.util.NetworkStackConstants;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
@@ -76,7 +77,10 @@ class TestNetworkService extends ITestNetworkManager.Stub {
|
|||||||
@NonNull private final NetworkProvider mNetworkProvider;
|
@NonNull private final NetworkProvider mNetworkProvider;
|
||||||
|
|
||||||
// Native method stubs
|
// Native method stubs
|
||||||
private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
|
private static native int nativeCreateTunTap(boolean isTun, @NonNull String iface);
|
||||||
|
|
||||||
|
private static native void nativeSetTunTapCarrierEnabled(@NonNull String iface, int tunFd,
|
||||||
|
boolean enabled);
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected TestNetworkService(@NonNull Context context) {
|
protected TestNetworkService(@NonNull Context context) {
|
||||||
@@ -131,7 +135,7 @@ class TestNetworkService extends ITestNetworkManager.Stub {
|
|||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
ParcelFileDescriptor tunIntf =
|
ParcelFileDescriptor tunIntf =
|
||||||
ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, interfaceName));
|
ParcelFileDescriptor.adoptFd(nativeCreateTunTap(isTun, interfaceName));
|
||||||
for (LinkAddress addr : linkAddrs) {
|
for (LinkAddress addr : linkAddrs) {
|
||||||
mNetd.interfaceAddAddress(
|
mNetd.interfaceAddAddress(
|
||||||
interfaceName,
|
interfaceName,
|
||||||
@@ -375,4 +379,20 @@ class TestNetworkService extends ITestNetworkManager.Stub {
|
|||||||
public static void enforceTestNetworkPermissions(@NonNull Context context) {
|
public static void enforceTestNetworkPermissions(@NonNull Context context) {
|
||||||
context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
|
context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Enable / disable TestNetworkInterface carrier */
|
||||||
|
@Override
|
||||||
|
public void setCarrierEnabled(@NonNull TestNetworkInterface iface, boolean enabled) {
|
||||||
|
enforceTestNetworkPermissions(mContext);
|
||||||
|
nativeSetTunTapCarrierEnabled(iface.getInterfaceName(), iface.getFileDescriptor().getFd(),
|
||||||
|
enabled);
|
||||||
|
// Explicitly close fd after use to prevent StrictMode from complaining.
|
||||||
|
// Also, explicitly referencing iface guarantees that the object is not garbage collected
|
||||||
|
// before nativeSetTunTapCarrierEnabled() executes.
|
||||||
|
try {
|
||||||
|
iface.getFileDescriptor().close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// if the close fails, there is not much that can be done -- move on.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user