Loading common/networkstackclient/src/android/net/shared/ProvisioningConfiguration.java +18 −1 Original line number Diff line number Diff line Loading @@ -92,7 +92,7 @@ public class ProvisioningConfiguration { // ipv4ProvisioningMode and ipv6ProvisioningMode members are introduced since // networkstack-aidl-interfaces-v12. private static final int VERSION_ADDED_PROVISIONING_ENUM = 12; public static final int VERSION_ADDED_PROVISIONING_ENUM = 12; /** * Builder to create a {@link ProvisioningConfiguration}. Loading Loading @@ -257,10 +257,27 @@ public class ProvisioningConfiguration { return this; } /** * Specify that the configuration should enable IPv6 link-local only mode used for * WiFi Neighbor Aware Networking and other link-local-only technologies. It's not * used by default, and IPv4 must be disabled when this mode is enabled. * * @note This API is only supported since Android T. */ public Builder withIpv6LinkLocalOnly() { mConfig.mIPv6ProvisioningMode = PROV_IPV6_LINKLOCAL; return this; } /** * Build the configuration using previously specified parameters. */ public ProvisioningConfiguration build() { if (mConfig.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL && mConfig.mIPv4ProvisioningMode != PROV_IPV4_DISABLED) { throw new IllegalArgumentException("IPv4 must be disabled in IPv6 link-local" + "only mode."); } return new ProvisioningConfiguration(mConfig); } } Loading src/android/net/ip/IpClient.java +53 −13 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.net.RouteInfo.RTN_UNICAST; import static android.net.dhcp.DhcpResultsParcelableUtil.toStableParcelable; import static android.net.ip.IIpClient.PROV_IPV4_DISABLED; import static android.net.ip.IIpClient.PROV_IPV6_DISABLED; import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL; import static android.net.util.NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION; import static android.net.util.NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION; import static android.net.util.NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION; Loading Loading @@ -399,6 +400,24 @@ public class IpClient extends StateMachine { log("Failed to call onPreconnectionStart", e); } } /** * Get the version of the IIpClientCallbacks AIDL interface. */ public int getInterfaceVersion() { log("getInterfaceVersion"); try { return mCallback.getInterfaceVersion(); } catch (RemoteException e) { // This can never happen for callers in the system server, because if the // system server crashes, then the networkstack will crash as well. But it can // happen for other callers such as bluetooth or telephony (if it starts to use // IpClient). 0 will generally work but will assume an old client and disable // all new features. log("Failed to call getInterfaceVersion", e); return 0; } } } public static final String DUMP_ARG_CONFIRM = "confirm"; Loading Loading @@ -498,7 +517,6 @@ public class IpClient extends StateMachine { private final String mClatInterfaceName; @VisibleForTesting protected final IpClientCallbacksWrapper mCallback; private final IIpClientCallbacks mIpClientCallback; private final Dependencies mDependencies; private final CountDownLatch mShutdownLatch; private final ConnectivityManager mCm; Loading Loading @@ -678,7 +696,6 @@ public class IpClient extends StateMachine { sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS)); mConnectivityPacketLog = sPktLogs.get(mInterfaceName); mMsgStateLogger = new MessageHandlingLogger(); mIpClientCallback = callback; mCallback = new IpClientCallbacksWrapper(callback, mLog, mShim); // TODO: Consider creating, constructing, and passing in some kind of Loading Loading @@ -799,14 +816,8 @@ public class IpClient extends StateMachine { @Override public void startProvisioning(ProvisioningConfigurationParcelable req) { enforceNetworkStackCallingPermission(); int interfaceVersion = 0; try { interfaceVersion = mIpClientCallback.getInterfaceVersion(); } catch (RemoteException e) { mLog.e("Fail to get the remote IIpClientCallbacks interface version", e); } IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req, interfaceVersion)); mCallback.getInterfaceVersion())); } @Override public void stop() { Loading Loading @@ -1238,12 +1249,41 @@ public class IpClient extends StateMachine { transitionTo(mStoppingState); } private static boolean hasIpv6LinkLocalInterfaceRoute(final LinkProperties lp) { for (RouteInfo r : lp.getRoutes()) { if (r.getDestination().equals(new IpPrefix("fe80::/64")) && r.getGateway().isAnyLocalAddress()) { return true; } } return false; } private static boolean hasIpv6LinkLocalAddress(final LinkProperties lp) { for (LinkAddress address : lp.getLinkAddresses()) { if (address.isIpv6() && address.getAddress().isLinkLocalAddress()) { return true; } } return false; } // LinkProperties has a link-local (fe80::xxx) IPv6 address and route to fe80::/64 destination. private boolean isIpv6LinkLocalProvisioned(final LinkProperties lp) { if (mConfiguration == null || mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_LINKLOCAL) return false; if (hasIpv6LinkLocalAddress(lp) && hasIpv6LinkLocalInterfaceRoute(lp)) return true; return false; } // For now: use WifiStateMachine's historical notion of provisioned. @VisibleForTesting static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) { // For historical reasons, we should connect even if all we have is // an IPv4 address and nothing else. if (lp.hasIpv4Address() || lp.isProvisioned()) { boolean isProvisioned(final LinkProperties lp, final InitialConfiguration config) { // For historical reasons, we should connect even if all we have is an IPv4 // address and nothing else. If IPv6 link-local only mode is enabled and // it's provisioned without IPv4, then still connecting once IPv6 link-local // address is ready to use and route to fe80::/64 destination is up. if (lp.hasIpv4Address() || lp.isProvisioned() || isIpv6LinkLocalProvisioned(lp)) { return true; } if (config == null) { Loading tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java +39 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable; import static android.net.ip.IpReachabilityMonitor.MIN_NUD_SOLICIT_NUM; import static android.net.ip.IpReachabilityMonitor.NUD_MCAST_RESOLICIT_NUM; import static android.net.ipmemorystore.Status.SUCCESS; import static android.net.shared.ProvisioningConfiguration.VERSION_ADDED_PROVISIONING_ENUM; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IFA_F_TEMPORARY; import static android.system.OsConstants.IPPROTO_ICMPV6; Loading @@ -56,6 +57,7 @@ import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTI import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; import static com.android.testutils.MiscAsserts.assertThrows; import static junit.framework.Assert.fail; Loading Loading @@ -106,6 +108,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.NetworkStackIpMemoryStore; import android.net.RouteInfo; import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.Uri; Loading Loading @@ -570,6 +573,7 @@ public abstract class IpClientIntegrationTestCommon { when(mContext.getContentResolver()).thenReturn(mContentResolver); when(mNetworkStackServiceManager.getIpMemoryStoreService()) .thenReturn(mIpMemoryStoreService); when(mCb.getInterfaceVersion()).thenReturn(VERSION_ADDED_PROVISIONING_ENUM); mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67); mDependencies.setDeviceConfigProperty(DhcpClient.DHCP_RESTART_CONFIG_DELAY, 10); Loading Loading @@ -3458,4 +3462,39 @@ public abstract class IpClientIntegrationTestCommon { mPacketReader.sendResponse(na); assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */); } @Test public void testIPv6LinkLocalOnly() throws Exception { ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() .withoutIPv4() .withIpv6LinkLocalOnly() .withRandomMacAddress() .build(); startIpClientProvisioning(config); final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); final LinkProperties lp = captor.getValue(); assertNotNull(lp); assertEquals(0, lp.getDnsServers().size()); final List<LinkAddress> addresses = lp.getLinkAddresses(); assertEquals(1, addresses.size()); assertTrue(addresses.get(0).getAddress().isLinkLocalAddress()); assertEquals(1, lp.getRoutes().size()); final RouteInfo route = lp.getRoutes().get(0); assertNotNull(route); assertTrue(route.getDestination().equals(new IpPrefix("fe80::/64"))); assertTrue(route.getGateway().isAnyLocalAddress()); } @Test public void testIPv6LinkLocalOnly_enableBothIPv4andIPv6LinkLocalOnly() throws Exception { assertThrows(IllegalArgumentException.class, () -> new ProvisioningConfiguration.Builder() .withoutIpReachabilityMonitor() .withIpv6LinkLocalOnly() .withRandomMacAddress() .build() ); } } tests/integration/src/android/net/ip/IpClientRootTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,7 @@ class IpClientRootTest : IpClientIntegrationTestCommon() { IIpClientCallbacks.Stub(), IIpClientCallbacks by base { // asBinder is implemented by both base class and delegate: specify explicitly override fun asBinder() = super.asBinder() override fun getInterfaceVersion() = IIpClientCallbacks.VERSION } @After Loading tests/unit/src/android/net/ip/IpClientTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -431,6 +431,7 @@ public class IpClientTest { @Test public void testIsProvisioned() throws Exception { final IpClient ipc = makeIpClient(TEST_IFNAME); InitialConfiguration empty = conf(links(), prefixes()); IsProvisionedTestCase[] testcases = { // nothing Loading Loading @@ -462,7 +463,7 @@ public class IpClientTest { }; for (IsProvisionedTestCase testcase : testcases) { if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) { if (ipc.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) { fail(testcase.errorMessage()); } } Loading Loading
common/networkstackclient/src/android/net/shared/ProvisioningConfiguration.java +18 −1 Original line number Diff line number Diff line Loading @@ -92,7 +92,7 @@ public class ProvisioningConfiguration { // ipv4ProvisioningMode and ipv6ProvisioningMode members are introduced since // networkstack-aidl-interfaces-v12. private static final int VERSION_ADDED_PROVISIONING_ENUM = 12; public static final int VERSION_ADDED_PROVISIONING_ENUM = 12; /** * Builder to create a {@link ProvisioningConfiguration}. Loading Loading @@ -257,10 +257,27 @@ public class ProvisioningConfiguration { return this; } /** * Specify that the configuration should enable IPv6 link-local only mode used for * WiFi Neighbor Aware Networking and other link-local-only technologies. It's not * used by default, and IPv4 must be disabled when this mode is enabled. * * @note This API is only supported since Android T. */ public Builder withIpv6LinkLocalOnly() { mConfig.mIPv6ProvisioningMode = PROV_IPV6_LINKLOCAL; return this; } /** * Build the configuration using previously specified parameters. */ public ProvisioningConfiguration build() { if (mConfig.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL && mConfig.mIPv4ProvisioningMode != PROV_IPV4_DISABLED) { throw new IllegalArgumentException("IPv4 must be disabled in IPv6 link-local" + "only mode."); } return new ProvisioningConfiguration(mConfig); } } Loading
src/android/net/ip/IpClient.java +53 −13 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.net.RouteInfo.RTN_UNICAST; import static android.net.dhcp.DhcpResultsParcelableUtil.toStableParcelable; import static android.net.ip.IIpClient.PROV_IPV4_DISABLED; import static android.net.ip.IIpClient.PROV_IPV6_DISABLED; import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL; import static android.net.util.NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION; import static android.net.util.NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION; import static android.net.util.NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION; Loading Loading @@ -399,6 +400,24 @@ public class IpClient extends StateMachine { log("Failed to call onPreconnectionStart", e); } } /** * Get the version of the IIpClientCallbacks AIDL interface. */ public int getInterfaceVersion() { log("getInterfaceVersion"); try { return mCallback.getInterfaceVersion(); } catch (RemoteException e) { // This can never happen for callers in the system server, because if the // system server crashes, then the networkstack will crash as well. But it can // happen for other callers such as bluetooth or telephony (if it starts to use // IpClient). 0 will generally work but will assume an old client and disable // all new features. log("Failed to call getInterfaceVersion", e); return 0; } } } public static final String DUMP_ARG_CONFIRM = "confirm"; Loading Loading @@ -498,7 +517,6 @@ public class IpClient extends StateMachine { private final String mClatInterfaceName; @VisibleForTesting protected final IpClientCallbacksWrapper mCallback; private final IIpClientCallbacks mIpClientCallback; private final Dependencies mDependencies; private final CountDownLatch mShutdownLatch; private final ConnectivityManager mCm; Loading Loading @@ -678,7 +696,6 @@ public class IpClient extends StateMachine { sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS)); mConnectivityPacketLog = sPktLogs.get(mInterfaceName); mMsgStateLogger = new MessageHandlingLogger(); mIpClientCallback = callback; mCallback = new IpClientCallbacksWrapper(callback, mLog, mShim); // TODO: Consider creating, constructing, and passing in some kind of Loading Loading @@ -799,14 +816,8 @@ public class IpClient extends StateMachine { @Override public void startProvisioning(ProvisioningConfigurationParcelable req) { enforceNetworkStackCallingPermission(); int interfaceVersion = 0; try { interfaceVersion = mIpClientCallback.getInterfaceVersion(); } catch (RemoteException e) { mLog.e("Fail to get the remote IIpClientCallbacks interface version", e); } IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req, interfaceVersion)); mCallback.getInterfaceVersion())); } @Override public void stop() { Loading Loading @@ -1238,12 +1249,41 @@ public class IpClient extends StateMachine { transitionTo(mStoppingState); } private static boolean hasIpv6LinkLocalInterfaceRoute(final LinkProperties lp) { for (RouteInfo r : lp.getRoutes()) { if (r.getDestination().equals(new IpPrefix("fe80::/64")) && r.getGateway().isAnyLocalAddress()) { return true; } } return false; } private static boolean hasIpv6LinkLocalAddress(final LinkProperties lp) { for (LinkAddress address : lp.getLinkAddresses()) { if (address.isIpv6() && address.getAddress().isLinkLocalAddress()) { return true; } } return false; } // LinkProperties has a link-local (fe80::xxx) IPv6 address and route to fe80::/64 destination. private boolean isIpv6LinkLocalProvisioned(final LinkProperties lp) { if (mConfiguration == null || mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_LINKLOCAL) return false; if (hasIpv6LinkLocalAddress(lp) && hasIpv6LinkLocalInterfaceRoute(lp)) return true; return false; } // For now: use WifiStateMachine's historical notion of provisioned. @VisibleForTesting static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) { // For historical reasons, we should connect even if all we have is // an IPv4 address and nothing else. if (lp.hasIpv4Address() || lp.isProvisioned()) { boolean isProvisioned(final LinkProperties lp, final InitialConfiguration config) { // For historical reasons, we should connect even if all we have is an IPv4 // address and nothing else. If IPv6 link-local only mode is enabled and // it's provisioned without IPv4, then still connecting once IPv6 link-local // address is ready to use and route to fe80::/64 destination is up. if (lp.hasIpv4Address() || lp.isProvisioned() || isIpv6LinkLocalProvisioned(lp)) { return true; } if (config == null) { Loading
tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java +39 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable; import static android.net.ip.IpReachabilityMonitor.MIN_NUD_SOLICIT_NUM; import static android.net.ip.IpReachabilityMonitor.NUD_MCAST_RESOLICIT_NUM; import static android.net.ipmemorystore.Status.SUCCESS; import static android.net.shared.ProvisioningConfiguration.VERSION_ADDED_PROVISIONING_ENUM; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IFA_F_TEMPORARY; import static android.system.OsConstants.IPPROTO_ICMPV6; Loading @@ -56,6 +57,7 @@ import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTI import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; import static com.android.testutils.MiscAsserts.assertThrows; import static junit.framework.Assert.fail; Loading Loading @@ -106,6 +108,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.NetworkStackIpMemoryStore; import android.net.RouteInfo; import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.Uri; Loading Loading @@ -570,6 +573,7 @@ public abstract class IpClientIntegrationTestCommon { when(mContext.getContentResolver()).thenReturn(mContentResolver); when(mNetworkStackServiceManager.getIpMemoryStoreService()) .thenReturn(mIpMemoryStoreService); when(mCb.getInterfaceVersion()).thenReturn(VERSION_ADDED_PROVISIONING_ENUM); mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67); mDependencies.setDeviceConfigProperty(DhcpClient.DHCP_RESTART_CONFIG_DELAY, 10); Loading Loading @@ -3458,4 +3462,39 @@ public abstract class IpClientIntegrationTestCommon { mPacketReader.sendResponse(na); assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */); } @Test public void testIPv6LinkLocalOnly() throws Exception { ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() .withoutIPv4() .withIpv6LinkLocalOnly() .withRandomMacAddress() .build(); startIpClientProvisioning(config); final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); final LinkProperties lp = captor.getValue(); assertNotNull(lp); assertEquals(0, lp.getDnsServers().size()); final List<LinkAddress> addresses = lp.getLinkAddresses(); assertEquals(1, addresses.size()); assertTrue(addresses.get(0).getAddress().isLinkLocalAddress()); assertEquals(1, lp.getRoutes().size()); final RouteInfo route = lp.getRoutes().get(0); assertNotNull(route); assertTrue(route.getDestination().equals(new IpPrefix("fe80::/64"))); assertTrue(route.getGateway().isAnyLocalAddress()); } @Test public void testIPv6LinkLocalOnly_enableBothIPv4andIPv6LinkLocalOnly() throws Exception { assertThrows(IllegalArgumentException.class, () -> new ProvisioningConfiguration.Builder() .withoutIpReachabilityMonitor() .withIpv6LinkLocalOnly() .withRandomMacAddress() .build() ); } }
tests/integration/src/android/net/ip/IpClientRootTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,7 @@ class IpClientRootTest : IpClientIntegrationTestCommon() { IIpClientCallbacks.Stub(), IIpClientCallbacks by base { // asBinder is implemented by both base class and delegate: specify explicitly override fun asBinder() = super.asBinder() override fun getInterfaceVersion() = IIpClientCallbacks.VERSION } @After Loading
tests/unit/src/android/net/ip/IpClientTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -431,6 +431,7 @@ public class IpClientTest { @Test public void testIsProvisioned() throws Exception { final IpClient ipc = makeIpClient(TEST_IFNAME); InitialConfiguration empty = conf(links(), prefixes()); IsProvisionedTestCase[] testcases = { // nothing Loading Loading @@ -462,7 +463,7 @@ public class IpClientTest { }; for (IsProvisionedTestCase testcase : testcases) { if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) { if (ipc.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) { fail(testcase.errorMessage()); } } Loading