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,
|
||||
in @nullable String iface);
|
||||
|
||||
void setCarrierEnabled(in TestNetworkInterface iface, boolean enabled);
|
||||
|
||||
void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
|
||||
in int[] administratorUids, in IBinder binder);
|
||||
|
||||
|
||||
@@ -231,4 +231,23 @@ public class TestNetworkManager {
|
||||
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());
|
||||
}
|
||||
|
||||
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));
|
||||
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);
|
||||
if (!iface.c_str()) {
|
||||
jniThrowNullPointerException(env, "iface");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tun = createTunTapInterface(env, isTun, iface.c_str());
|
||||
|
||||
// Any exceptions will be thrown from the createTunTapInterface call
|
||||
return tun;
|
||||
return createTunTapImpl(env, isTun, iface.c_str());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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) {
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.net.module.util.NetdUtils;
|
||||
import com.android.net.module.util.NetworkStackConstants;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
@@ -76,7 +77,10 @@ class TestNetworkService extends ITestNetworkManager.Stub {
|
||||
@NonNull private final NetworkProvider mNetworkProvider;
|
||||
|
||||
// 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
|
||||
protected TestNetworkService(@NonNull Context context) {
|
||||
@@ -131,7 +135,7 @@ class TestNetworkService extends ITestNetworkManager.Stub {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
ParcelFileDescriptor tunIntf =
|
||||
ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, interfaceName));
|
||||
ParcelFileDescriptor.adoptFd(nativeCreateTunTap(isTun, interfaceName));
|
||||
for (LinkAddress addr : linkAddrs) {
|
||||
mNetd.interfaceAddAddress(
|
||||
interfaceName,
|
||||
@@ -375,4 +379,20 @@ class TestNetworkService extends ITestNetworkManager.Stub {
|
||||
public static void enforceTestNetworkPermissions(@NonNull Context context) {
|
||||
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