resolve merge conflicts of 4f2a0fe213 to stage-aosp-master am: a428392c1d
am: 164ff8a2ed
Change-Id: I08195e119f866acc9fe1795b892fe45cea3c7f47
This commit is contained in:
@@ -16,6 +16,15 @@
|
|||||||
|
|
||||||
package android.net;
|
package android.net;
|
||||||
|
|
||||||
|
import static android.system.OsConstants.IFA_F_DADFAILED;
|
||||||
|
import static android.system.OsConstants.IFA_F_DEPRECATED;
|
||||||
|
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
|
||||||
|
import static android.system.OsConstants.IFA_F_TENTATIVE;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_HOST;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_LINK;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_SITE;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -26,15 +35,6 @@ import java.net.InetAddress;
|
|||||||
import java.net.InterfaceAddress;
|
import java.net.InterfaceAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import static android.system.OsConstants.IFA_F_DADFAILED;
|
|
||||||
import static android.system.OsConstants.IFA_F_DEPRECATED;
|
|
||||||
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
|
|
||||||
import static android.system.OsConstants.IFA_F_TENTATIVE;
|
|
||||||
import static android.system.OsConstants.RT_SCOPE_HOST;
|
|
||||||
import static android.system.OsConstants.RT_SCOPE_LINK;
|
|
||||||
import static android.system.OsConstants.RT_SCOPE_SITE;
|
|
||||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies an IP address on a network link.
|
* Identifies an IP address on a network link.
|
||||||
*
|
*
|
||||||
@@ -101,7 +101,7 @@ public class LinkAddress implements Parcelable {
|
|||||||
* Per RFC 4193 section 8, fc00::/7 identifies these addresses.
|
* Per RFC 4193 section 8, fc00::/7 identifies these addresses.
|
||||||
*/
|
*/
|
||||||
private boolean isIPv6ULA() {
|
private boolean isIPv6ULA() {
|
||||||
if (address != null && address instanceof Inet6Address) {
|
if (address instanceof Inet6Address) {
|
||||||
byte[] bytes = address.getAddress();
|
byte[] bytes = address.getAddress();
|
||||||
return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
|
return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,12 @@ public final class IpManagerEvent implements Parcelable {
|
|||||||
public static final int ERROR_STARTING_IPV4 = 4;
|
public static final int ERROR_STARTING_IPV4 = 4;
|
||||||
public static final int ERROR_STARTING_IPV6 = 5;
|
public static final int ERROR_STARTING_IPV6 = 5;
|
||||||
public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
|
public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
|
||||||
|
public static final int ERROR_INVALID_PROVISIONING = 7;
|
||||||
|
|
||||||
@IntDef(value = {
|
@IntDef(value = {
|
||||||
PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
|
PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
|
||||||
ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
|
ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
|
||||||
|
ERROR_INVALID_PROVISIONING,
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface EventType {}
|
public @interface EventType {}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import android.content.Context;
|
|||||||
import android.net.DhcpResults;
|
import android.net.DhcpResults;
|
||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
import android.net.InterfaceConfiguration;
|
import android.net.InterfaceConfiguration;
|
||||||
|
import android.net.IpPrefix;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties.ProvisioningChange;
|
import android.net.LinkProperties.ProvisioningChange;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
@@ -35,6 +36,7 @@ import android.net.dhcp.DhcpClient;
|
|||||||
import android.net.metrics.IpConnectivityLog;
|
import android.net.metrics.IpConnectivityLog;
|
||||||
import android.net.metrics.IpManagerEvent;
|
import android.net.metrics.IpManagerEvent;
|
||||||
import android.net.util.MultinetworkPolicyTracker;
|
import android.net.util.MultinetworkPolicyTracker;
|
||||||
|
import android.net.util.NetworkConstants;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
@@ -51,17 +53,25 @@ import android.util.SparseArray;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
import com.android.internal.util.IState;
|
import com.android.internal.util.IState;
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
import com.android.internal.util.State;
|
import com.android.internal.util.State;
|
||||||
import com.android.internal.util.StateMachine;
|
import com.android.internal.util.StateMachine;
|
||||||
import com.android.server.net.NetlinkTracker;
|
import com.android.server.net.NetlinkTracker;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -308,6 +318,11 @@ public class IpManager extends StateMachine {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
|
||||||
|
mConfig.mInitialConfig = initialConfig;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
|
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
|
||||||
mConfig.mStaticIpConfig = staticConfig;
|
mConfig.mStaticIpConfig = staticConfig;
|
||||||
return this;
|
return this;
|
||||||
@@ -342,18 +357,20 @@ public class IpManager extends StateMachine {
|
|||||||
/* package */ boolean mEnableIPv6 = true;
|
/* package */ boolean mEnableIPv6 = true;
|
||||||
/* package */ boolean mUsingIpReachabilityMonitor = true;
|
/* package */ boolean mUsingIpReachabilityMonitor = true;
|
||||||
/* package */ int mRequestedPreDhcpActionMs;
|
/* package */ int mRequestedPreDhcpActionMs;
|
||||||
|
/* package */ InitialConfiguration mInitialConfig;
|
||||||
/* package */ StaticIpConfiguration mStaticIpConfig;
|
/* package */ StaticIpConfiguration mStaticIpConfig;
|
||||||
/* package */ ApfCapabilities mApfCapabilities;
|
/* package */ ApfCapabilities mApfCapabilities;
|
||||||
/* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
|
/* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
|
||||||
/* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
/* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||||
|
|
||||||
public ProvisioningConfiguration() {}
|
public ProvisioningConfiguration() {} // used by Builder
|
||||||
|
|
||||||
public ProvisioningConfiguration(ProvisioningConfiguration other) {
|
public ProvisioningConfiguration(ProvisioningConfiguration other) {
|
||||||
mEnableIPv4 = other.mEnableIPv4;
|
mEnableIPv4 = other.mEnableIPv4;
|
||||||
mEnableIPv6 = other.mEnableIPv6;
|
mEnableIPv6 = other.mEnableIPv6;
|
||||||
mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
|
mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
|
||||||
mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
|
mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
|
||||||
|
mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
|
||||||
mStaticIpConfig = other.mStaticIpConfig;
|
mStaticIpConfig = other.mStaticIpConfig;
|
||||||
mApfCapabilities = other.mApfCapabilities;
|
mApfCapabilities = other.mApfCapabilities;
|
||||||
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
|
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
|
||||||
@@ -366,12 +383,124 @@ public class IpManager extends StateMachine {
|
|||||||
.add("mEnableIPv6: " + mEnableIPv6)
|
.add("mEnableIPv6: " + mEnableIPv6)
|
||||||
.add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
|
.add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
|
||||||
.add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
|
.add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
|
||||||
|
.add("mInitialConfig: " + mInitialConfig)
|
||||||
.add("mStaticIpConfig: " + mStaticIpConfig)
|
.add("mStaticIpConfig: " + mStaticIpConfig)
|
||||||
.add("mApfCapabilities: " + mApfCapabilities)
|
.add("mApfCapabilities: " + mApfCapabilities)
|
||||||
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
|
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
|
||||||
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
|
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return (mInitialConfig == null) || mInitialConfig.isValid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InitialConfiguration {
|
||||||
|
public final Set<LinkAddress> ipAddresses = new HashSet<>();
|
||||||
|
public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
|
||||||
|
public final Set<InetAddress> dnsServers = new HashSet<>();
|
||||||
|
public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config
|
||||||
|
|
||||||
|
public static InitialConfiguration copy(InitialConfiguration config) {
|
||||||
|
if (config == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
InitialConfiguration configCopy = new InitialConfiguration();
|
||||||
|
configCopy.ipAddresses.addAll(config.ipAddresses);
|
||||||
|
configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
|
||||||
|
configCopy.dnsServers.addAll(config.dnsServers);
|
||||||
|
return configCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)",
|
||||||
|
join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
|
||||||
|
join(", ", dnsServers), gateway);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
// For every IP address, there must be at least one prefix containing that address.
|
||||||
|
for (LinkAddress addr : ipAddresses) {
|
||||||
|
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For every dns server, there must be at least one prefix containing that address.
|
||||||
|
for (InetAddress addr : dnsServers) {
|
||||||
|
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All IPv6 LinkAddresses have an RFC7421-suitable prefix length
|
||||||
|
// (read: compliant with RFC4291#section2.5.4).
|
||||||
|
if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If directlyConnectedRoutes contains an IPv6 default route
|
||||||
|
// then ipAddresses MUST contain at least one non-ULA GUA.
|
||||||
|
if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
|
||||||
|
&& all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// The prefix length of routes in directlyConnectedRoutes be within reasonable
|
||||||
|
// bounds for IPv6: /48-/64 just as we’d accept in RIOs.
|
||||||
|
if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// There no more than one IPv4 address
|
||||||
|
if (ipAddresses.stream().filter(Inet4Address.class::isInstance).count() > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPrefixLengthCompliant(LinkAddress addr) {
|
||||||
|
return (addr.getAddress() instanceof Inet4Address)
|
||||||
|
|| isCompliantIPv6PrefixLength(addr.getPrefixLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
|
||||||
|
return (prefix.getAddress() instanceof Inet4Address)
|
||||||
|
|| isCompliantIPv6PrefixLength(prefix.getPrefixLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
|
||||||
|
return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
|
||||||
|
&& (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
|
||||||
|
return prefix.getAddress().equals(Inet6Address.ANY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isIPv6GUA(LinkAddress addr) {
|
||||||
|
return (addr.getAddress() instanceof Inet6Address) && addr.isGlobalPreferred();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
|
||||||
|
for (T t : coll) {
|
||||||
|
if (fn.test(t)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
|
||||||
|
return !any(coll, not(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Predicate<T> not(Predicate<T> fn) {
|
||||||
|
return (t) -> !fn.test(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> String join(String delimiter, Collection<T> coll) {
|
||||||
|
return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String DUMP_ARG = "ipmanager";
|
public static final String DUMP_ARG = "ipmanager";
|
||||||
@@ -436,8 +565,7 @@ public class IpManager extends StateMachine {
|
|||||||
private boolean mMulticastFiltering;
|
private boolean mMulticastFiltering;
|
||||||
private long mStartTimeMillis;
|
private long mStartTimeMillis;
|
||||||
|
|
||||||
public IpManager(Context context, String ifName, Callback callback)
|
public IpManager(Context context, String ifName, Callback callback) {
|
||||||
throws IllegalArgumentException {
|
|
||||||
this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
|
this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)));
|
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)));
|
||||||
}
|
}
|
||||||
@@ -446,7 +574,7 @@ public class IpManager extends StateMachine {
|
|||||||
* An expanded constructor, useful for dependency injection.
|
* An expanded constructor, useful for dependency injection.
|
||||||
*/
|
*/
|
||||||
public IpManager(Context context, String ifName, Callback callback,
|
public IpManager(Context context, String ifName, Callback callback,
|
||||||
INetworkManagementService nwService) throws IllegalArgumentException {
|
INetworkManagementService nwService) {
|
||||||
super(IpManager.class.getSimpleName() + "." + ifName);
|
super(IpManager.class.getSimpleName() + "." + ifName);
|
||||||
mTag = getName();
|
mTag = getName();
|
||||||
|
|
||||||
@@ -563,6 +691,11 @@ public class IpManager extends StateMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startProvisioning(ProvisioningConfiguration req) {
|
public void startProvisioning(ProvisioningConfiguration req) {
|
||||||
|
if (!req.isValid()) {
|
||||||
|
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getNetworkInterface();
|
getNetworkInterface();
|
||||||
|
|
||||||
mCallback.setNeighborDiscoveryOffload(true);
|
mCallback.setNeighborDiscoveryOffload(true);
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ public final class NetworkConstants {
|
|||||||
public static final int IPV6_ADDR_LEN = 16;
|
public static final int IPV6_ADDR_LEN = 16;
|
||||||
public static final int IPV6_MIN_MTU = 1280;
|
public static final int IPV6_MIN_MTU = 1280;
|
||||||
public static final int RFC7421_PREFIX_LENGTH = 64;
|
public static final int RFC7421_PREFIX_LENGTH = 64;
|
||||||
|
public static final int RFC6177_MIN_PREFIX_LENGTH = 48;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ICMPv6 constants.
|
* ICMPv6 constants.
|
||||||
|
|||||||
@@ -16,11 +16,26 @@
|
|||||||
|
|
||||||
package android.net.ip;
|
package android.net.ip;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.timeout;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.AlarmManager;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.net.IpPrefix;
|
||||||
|
import android.net.LinkAddress;
|
||||||
|
import android.net.ip.IpManager.Callback;
|
||||||
|
import android.net.ip.IpManager.InitialConfiguration;
|
||||||
|
import android.net.ip.IpManager.ProvisioningConfiguration;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
@@ -31,11 +46,17 @@ import com.android.internal.util.test.FakeSettingsProvider;
|
|||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for IpManager.
|
* Tests for IpManager.
|
||||||
*/
|
*/
|
||||||
@@ -44,14 +65,20 @@ import org.mockito.MockitoAnnotations;
|
|||||||
public class IpManagerTest {
|
public class IpManagerTest {
|
||||||
private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
|
private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
|
||||||
|
|
||||||
|
private static final String VALID = "VALID";
|
||||||
|
private static final String INVALID = "INVALID";
|
||||||
|
|
||||||
@Mock private Context mContext;
|
@Mock private Context mContext;
|
||||||
@Mock private INetworkManagementService mNMService;
|
@Mock private INetworkManagementService mNMService;
|
||||||
@Mock private Resources mResources;
|
@Mock private Resources mResources;
|
||||||
|
@Mock private Callback mCb;
|
||||||
|
@Mock private AlarmManager mAlarm;
|
||||||
private MockContentResolver mContentResolver;
|
private MockContentResolver mContentResolver;
|
||||||
|
|
||||||
@Before public void setUp() throws Exception {
|
@Before public void setUp() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
|
||||||
when(mContext.getResources()).thenReturn(mResources);
|
when(mContext.getResources()).thenReturn(mResources);
|
||||||
when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
|
when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
|
||||||
.thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
|
.thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
|
||||||
@@ -68,7 +95,152 @@ public class IpManagerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidInterfaceDoesNotThrow() throws Exception {
|
public void testInvalidInterfaceDoesNotThrow() throws Exception {
|
||||||
final IpManager.Callback cb = new IpManager.Callback();
|
final IpManager ipm = new IpManager(mContext, "test_wlan0", mCb, mNMService);
|
||||||
final IpManager ipm = new IpManager(mContext, "test_wlan0", cb, mNMService);
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultProvisioningConfiguration() throws Exception {
|
||||||
|
final String iface = "test_wlan0";
|
||||||
|
final IpManager ipm = new IpManager(mContext, iface, mCb, mNMService);
|
||||||
|
ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
|
||||||
|
.withoutIPv4()
|
||||||
|
// TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
|
||||||
|
// and enable it in this test
|
||||||
|
.withoutIpReachabilityMonitor()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ipm.startProvisioning(config);
|
||||||
|
verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
|
||||||
|
verify(mCb, timeout(100).times(1)).setFallbackMulticastFilter(false);
|
||||||
|
verify(mCb, never()).onProvisioningFailure(any());
|
||||||
|
|
||||||
|
ipm.stop();
|
||||||
|
verify(mNMService, timeout(100).times(1)).disableIpv6(iface);
|
||||||
|
verify(mNMService, timeout(100).times(1)).clearInterfaceAddresses(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitialConfigurations() throws Exception {
|
||||||
|
InitialConfigurationTestCase[] testcases = {
|
||||||
|
validConf("valid IPv4 configuration",
|
||||||
|
links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
|
||||||
|
validConf("another valid IPv4 configuration",
|
||||||
|
links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
|
||||||
|
validConf("valid IPv6 configurations",
|
||||||
|
links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
|
||||||
|
prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
|
||||||
|
dns("2001:db8:dead:beef:f00::02")),
|
||||||
|
validConf("valid IPv6 configurations",
|
||||||
|
links("fe80::1/64"), prefixes("fe80::/64"), dns()),
|
||||||
|
validConf("valid IPv6/v4 configuration",
|
||||||
|
links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
|
||||||
|
prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
|
||||||
|
dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
|
||||||
|
validConf("valid IPv6 configuration without any GUA.",
|
||||||
|
links("fd00:1234:5678::1/48"),
|
||||||
|
prefixes("fd00:1234:5678::/48"),
|
||||||
|
dns("fd00:1234:5678::1000")),
|
||||||
|
|
||||||
|
invalidConf("v4 addr and dns not in any prefix",
|
||||||
|
links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
|
||||||
|
invalidConf("v4 addr not in any prefix",
|
||||||
|
links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
|
||||||
|
invalidConf("v4 dns addr not in any prefix",
|
||||||
|
links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
|
||||||
|
invalidConf("v6 addr not in any prefix",
|
||||||
|
links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
|
||||||
|
prefixes("2001:db8:dead:beef::/64"),
|
||||||
|
dns("2001:db8:dead:beef:f00::02")),
|
||||||
|
invalidConf("v6 dns addr not in any prefix",
|
||||||
|
links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
|
||||||
|
invalidConf("default ipv6 route and no GUA",
|
||||||
|
links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
|
||||||
|
invalidConf("invalid v6 prefix length",
|
||||||
|
links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
|
||||||
|
dns()),
|
||||||
|
invalidConf("another invalid v6 prefix length",
|
||||||
|
links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
|
||||||
|
dns())
|
||||||
|
};
|
||||||
|
|
||||||
|
for (InitialConfigurationTestCase testcase : testcases) {
|
||||||
|
if (testcase.config.isValid() != testcase.isValid) {
|
||||||
|
fail(testcase.errorMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class InitialConfigurationTestCase {
|
||||||
|
String descr;
|
||||||
|
boolean isValid;
|
||||||
|
InitialConfiguration config;
|
||||||
|
public String errorMessage() {
|
||||||
|
return String.format("%s: expected configuration %s to be %s, but was %s",
|
||||||
|
descr, config, validString(isValid), validString(!isValid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String validString(boolean isValid) {
|
||||||
|
return isValid ? VALID : INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
|
||||||
|
Set<IpPrefix> prefixes, Set<InetAddress> dns) {
|
||||||
|
return confTestCase(descr, true, conf(links, prefixes, dns));
|
||||||
|
}
|
||||||
|
|
||||||
|
static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
|
||||||
|
Set<IpPrefix> prefixes, Set<InetAddress> dns) {
|
||||||
|
return confTestCase(descr, false, conf(links, prefixes, dns));
|
||||||
|
}
|
||||||
|
|
||||||
|
static InitialConfigurationTestCase confTestCase(
|
||||||
|
String descr, boolean isValid, InitialConfiguration config) {
|
||||||
|
InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
|
||||||
|
testcase.descr = descr;
|
||||||
|
testcase.isValid = isValid;
|
||||||
|
testcase.config = config;
|
||||||
|
return testcase;
|
||||||
|
}
|
||||||
|
|
||||||
|
static InitialConfiguration conf(
|
||||||
|
Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
|
||||||
|
InitialConfiguration conf = new InitialConfiguration();
|
||||||
|
conf.ipAddresses.addAll(links);
|
||||||
|
conf.directlyConnectedRoutes.addAll(prefixes);
|
||||||
|
conf.dnsServers.addAll(dns);
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<IpPrefix> prefixes(String... prefixes) {
|
||||||
|
return mapIntoSet(prefixes, IpPrefix::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<LinkAddress> links(String... addresses) {
|
||||||
|
return mapIntoSet(addresses, LinkAddress::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<InetAddress> ips(String... addresses) {
|
||||||
|
return mapIntoSet(addresses, InetAddress::getByName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<InetAddress> dns(String... addresses) {
|
||||||
|
return ips(addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
|
||||||
|
Set<B> out = new HashSet<>(in.length);
|
||||||
|
for (A item : in) {
|
||||||
|
try {
|
||||||
|
out.add(fn.call(item));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Fn<A,B> {
|
||||||
|
B call(A a) throws Exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user