Loading src/android/net/ip/IpClient.java +73 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.net.RouteInfo.RTN_UNICAST; import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static com.android.server.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID; import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingPermission; import android.content.Context; Loading @@ -40,10 +41,13 @@ import android.net.Uri; import android.net.apf.ApfCapabilities; import android.net.apf.ApfFilter; import android.net.dhcp.DhcpClient; import android.net.dhcp.DhcpPacket; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; import android.net.shared.InitialConfiguration; import android.net.shared.ProvisioningConfiguration; import android.net.shared.ProvisioningConfiguration.ScanResultInfo; import android.net.shared.ProvisioningConfiguration.ScanResultInfo.InformationElement; import android.net.util.InterfaceParams; import android.net.util.NetworkStackUtils; import android.net.util.SharedLog; Loading @@ -64,6 +68,7 @@ import android.util.SparseArray; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.IState; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; Loading @@ -80,6 +85,10 @@ import com.android.server.NetworkStackService.NetworkStackServiceManager; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; Loading Loading @@ -406,6 +415,13 @@ public class IpClient extends StateMachine { private static final int PROV_CHANGE_GAINED_PROVISIONING = 3; private static final int PROV_CHANGE_STILL_PROVISIONED = 4; // Specific vendor OUI(3 bytes)/vendor specific type(1 byte) pattern for upstream hotspot // device detection. Add new byte array pattern below in turn. private static final List<byte[]> METERED_IE_PATTERN_LIST = Collections.unmodifiableList( Arrays.asList( new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xf2, (byte) 0x06 } )); private final State mStoppedState = new StoppedState(); private final State mStoppingState = new StoppingState(); private final State mClearingIpAddressesState = new ClearingIpAddressesState(); Loading Loading @@ -1265,15 +1281,70 @@ public class IpClient extends StateMachine { return (delta != PROV_CHANGE_LOST_PROVISIONING); } @VisibleForTesting static String removeDoubleQuotes(@NonNull String ssid) { final int length = ssid.length(); if ((length > 1) && (ssid.charAt(0) == '"') && (ssid.charAt(length - 1) == '"')) { return ssid.substring(1, length - 1); } return ssid; } private List<ByteBuffer> getVendorSpecificIEs(@NonNull ScanResultInfo scanResultInfo) { ArrayList<ByteBuffer> vendorSpecificPayloadList = new ArrayList<>(); for (InformationElement ie : scanResultInfo.getInformationElements()) { if (ie.getId() == VENDOR_SPECIFIC_IE_ID) { vendorSpecificPayloadList.add(ie.getPayload()); } } return vendorSpecificPayloadList; } private boolean detectUpstreamHotspotFromVendorIe() { if (mConfiguration.mScanResultInfo == null) return false; final ScanResultInfo scanResultInfo = mConfiguration.mScanResultInfo; final String ssid = scanResultInfo.getSsid(); final List<ByteBuffer> vendorSpecificPayloadList = getVendorSpecificIEs(scanResultInfo); if (mConfiguration.mDisplayName == null || !removeDoubleQuotes(mConfiguration.mDisplayName).equals(ssid)) { return false; } for (ByteBuffer payload : vendorSpecificPayloadList) { byte[] ouiAndType = new byte[4]; try { payload.get(ouiAndType); } catch (BufferUnderflowException e) { Log.e(mTag, "Couldn't parse vendor specific IE, buffer underflow"); return false; } for (byte[] pattern : METERED_IE_PATTERN_LIST) { if (Arrays.equals(pattern, ouiAndType)) { if (DBG) { Log.d(mTag, "detected upstream hotspot that matches OUI:" + HexDump.toHexString(ouiAndType)); } return true; } } } return false; } private void handleIPv4Success(DhcpResults dhcpResults) { mDhcpResults = new DhcpResults(dhcpResults); final LinkProperties newLp = assembleLinkProperties(); final int delta = setLinkProperties(newLp); if (mDhcpResults.vendorInfo == null && detectUpstreamHotspotFromVendorIe()) { mDhcpResults.vendorInfo = DhcpPacket.VENDOR_INFO_ANDROID_METERED; } if (DBG) { Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")"); Log.d(mTag, "onNewDhcpResults(" + Objects.toString(mDhcpResults) + ")"); } mCallback.onNewDhcpResults(dhcpResults); mCallback.onNewDhcpResults(mDhcpResults); maybeSaveNetworkToIpMemoryStore(); dispatchCallback(delta, newLp); Loading src/android/net/util/ConnectivityPacketSummary.java +4 −4 Original line number Diff line number Diff line Loading @@ -84,8 +84,8 @@ public class ConnectivityPacketSummary { /** * Create a string summary of a received packet. * @param hwaddr MacAddress of the receiving device. * @param buffer Buffer of the packet. Length is assumed to be the buffer length. * @param hwaddr MacAddress of the interface sending/receiving the packet. * @param buffer The packet bytes. Length is assumed to be the buffer length. * @return A summary of the packet. */ public static String summarize(MacAddress hwaddr, byte[] buffer) { Loading @@ -97,8 +97,8 @@ public class ConnectivityPacketSummary { /** * Create a string summary of a received packet. * @param macAddr MacAddress of the receiving device. * @param buffer Buffer of the packet. * @param macAddr MacAddress of the interface sending/receiving the packet. * @param buffer The packet bytes. * @param length Length of the packet. * @return A summary of the packet. */ Loading src/com/android/server/util/NetworkStackConstants.java +8 −0 Original line number Diff line number Diff line Loading @@ -148,6 +148,14 @@ public final class NetworkStackConstants { public static final int INFINITE_LEASE = 0xffffffff; public static final int DHCP4_CLIENT_PORT = 68; /** * IEEE802.11 standard constants. * * See also: * - https://ieeexplore.ieee.org/document/7786995 */ public static final int VENDOR_SPECIFIC_IE_ID = 0xdd; private NetworkStackConstants() { throw new UnsupportedOperationException("This class is not to be instantiated"); } Loading tests/integration/src/android/net/ip/IpClientIntegrationTest.java +119 −8 Original line number Diff line number Diff line Loading @@ -24,9 +24,11 @@ import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_L2; import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; import static android.net.ip.IpClient.removeDoubleQuotes; import static android.net.ipmemorystore.Status.SUCCESS; import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.IPPROTO_TCP; Loading @@ -47,6 +49,7 @@ import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICI import static com.android.server.util.NetworkStackConstants.IPV6_HEADER_LEN; import static com.android.server.util.NetworkStackConstants.IPV6_LEN_OFFSET; import static com.android.server.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET; import static com.android.server.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID; import static junit.framework.Assert.fail; Loading Loading @@ -78,6 +81,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.DhcpResults; import android.net.DhcpResultsParcelable; import android.net.INetd; import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; Loading @@ -100,6 +105,7 @@ import android.net.ipmemorystore.NetworkAttributes; import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener; import android.net.ipmemorystore.Status; import android.net.shared.ProvisioningConfiguration; import android.net.shared.ProvisioningConfiguration.ScanResultInfo; import android.net.util.InterfaceParams; import android.net.util.IpUtils; import android.net.util.NetworkStackUtils; Loading Loading @@ -152,6 +158,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.Random; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; Loading Loading @@ -226,6 +233,10 @@ public class IpClientIntegrationTest { private static final String TEST_HOST_NAME = "AOSP on Crosshatch"; private static final String TEST_HOST_NAME_TRANSLITERATION = "AOSP-on-Crosshatch"; private static final String TEST_CAPTIVE_PORTAL_URL = "https://example.com/capportapi"; private static final byte[] TEST_HOTSPOT_OUI = new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }; private static final byte TEST_VENDOR_SPECIFIC_TYPE = 0x06; private static class TapPacketReader extends PacketReader { private final ParcelFileDescriptor mTapFd; Loading Loading @@ -549,12 +560,15 @@ public class IpClientIntegrationTest { private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled, final boolean shouldReplyRapidCommitAck, final boolean isPreconnectionEnabled, final boolean isDhcpIpConflictDetectEnabled, final boolean isHostnameConfigurationEnabled, final String hostname) final boolean isHostnameConfigurationEnabled, final String hostname, final String displayName, final ScanResultInfo scanResultInfo) throws RemoteException { ProvisioningConfiguration.Builder builder = new ProvisioningConfiguration.Builder() .withoutIpReachabilityMonitor() .withoutIPv6(); if (isPreconnectionEnabled) builder.withPreconnection(); if (displayName != null) builder.withDisplayName(displayName); if (scanResultInfo != null) builder.withScanResultInfo(scanResultInfo); mDependencies.setDhcpLeaseCacheEnabled(isDhcpLeaseCacheEnabled); mDependencies.setDhcpRapidCommitEnabled(shouldReplyRapidCommitAck); Loading @@ -575,7 +589,8 @@ public class IpClientIntegrationTest { throws RemoteException { startIpClientProvisioning(isDhcpLeaseCacheEnabled, isDhcpRapidCommitEnabled, isPreconnectionEnabled, isDhcpIpConflictDetectEnabled, false /* isHostnameConfigurationEnabled */, null /* hostname */); false /* isHostnameConfigurationEnabled */, null /* hostname */, null /* displayName */, null /* ScanResultInfo */); } private void assertIpMemoryStoreNetworkAttributes(final Integer leaseTimeSec, Loading Loading @@ -633,10 +648,11 @@ public class IpClientIntegrationTest { final boolean shouldReplyRapidCommitAck, final int mtu, final boolean isDhcpIpConflictDetectEnabled, final boolean isHostnameConfigurationEnabled, final String hostname, final String captivePortalApiUrl) throws Exception { final String captivePortalApiUrl, final String displayName, final ScanResultInfo scanResultInfo) throws Exception { startIpClientProvisioning(isDhcpLeaseCacheEnabled, shouldReplyRapidCommitAck, false /* isPreconnectionEnabled */, isDhcpIpConflictDetectEnabled, isHostnameConfigurationEnabled, hostname); isHostnameConfigurationEnabled, hostname, displayName, scanResultInfo); return handleDhcpPackets(isSuccessLease, leaseTimeSec, shouldReplyRapidCommitAck, mtu, isDhcpIpConflictDetectEnabled, captivePortalApiUrl); } Loading Loading @@ -693,7 +709,7 @@ public class IpClientIntegrationTest { return performDhcpHandshake(isSuccessLease, leaseTimeSec, isDhcpLeaseCacheEnabled, isDhcpRapidCommitEnabled, mtu, isDhcpIpConflictDetectEnabled, false /* isHostnameConfigurationEnabled */, null /* hostname */, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); } private DhcpPacket getNextDhcpPacket() throws ParseException { Loading Loading @@ -1484,7 +1500,7 @@ public class IpClientIntegrationTest { false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, true /* isHostnameConfigurationEnabled */, TEST_HOST_NAME /* hostname */, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); assertEquals(2, sentPackets.size()); assertHostname(true, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets); assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); Loading @@ -1498,7 +1514,7 @@ public class IpClientIntegrationTest { false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, false /* isHostnameConfigurationEnabled */, TEST_HOST_NAME, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); assertEquals(2, sentPackets.size()); assertHostname(false, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets); assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); Loading @@ -1512,7 +1528,7 @@ public class IpClientIntegrationTest { false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, true /* isHostnameConfigurationEnabled */, null /* hostname */, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); assertEquals(2, sentPackets.size()); assertHostname(true, null /* hostname */, null /* hostnameAfterTransliteration */, sentPackets); Loading Loading @@ -1566,4 +1582,99 @@ public class IpClientIntegrationTest { assumeFalse(CaptivePortalDataShimImpl.isSupported()); runDhcpClientCaptivePortalApiTest(false /* featureEnabled */, true /* serverSendsOption */); } private ScanResultInfo makeScanResultInfo(final int id, final String ssid, final byte[] oui, final byte type, final byte[] data) { final ByteBuffer payload = ByteBuffer.allocate(4 + data.length); payload.put(oui); payload.put(type); payload.put(data); payload.flip(); final ScanResultInfo.InformationElement ie = new ScanResultInfo.InformationElement(id /* IE id */, payload); return new ScanResultInfo(ssid, Collections.singletonList(ie)); } private void doUpstreamHotspotDetectionTest(final int id, final String displayName, final String ssid, final byte[] oui, final byte type, final byte[] data) throws Exception { final ScanResultInfo info = makeScanResultInfo(id, ssid, oui, type, data); final long currentTime = System.currentTimeMillis(); final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, false /* isHostnameConfigurationEnabled */, null /* hostname */, null /* captivePortalApiUrl */, displayName, info /* scanResultInfo */); assertEquals(2, sentPackets.size()); ArgumentCaptor<DhcpResultsParcelable> captor = ArgumentCaptor.forClass(DhcpResultsParcelable.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(captor.capture()); DhcpResults lease = fromStableParcelable(captor.getValue()); assertNotNull(lease); assertEquals(lease.getIpAddress().getAddress(), CLIENT_ADDR); assertEquals(lease.getGateway(), SERVER_ADDR); assertEquals(1, lease.getDnsServers().size()); assertTrue(lease.getDnsServers().contains(SERVER_ADDR)); assertEquals(lease.getServerAddress(), SERVER_ADDR); assertEquals(lease.getMtu(), TEST_DEFAULT_MTU); if (id == VENDOR_SPECIFIC_IE_ID && ssid.equals(removeDoubleQuotes(displayName)) && Arrays.equals(oui, TEST_HOTSPOT_OUI) && type == TEST_VENDOR_SPECIFIC_TYPE) { assertEquals(lease.vendorInfo, DhcpPacket.VENDOR_INFO_ANDROID_METERED); } else { assertNull(lease.vendorInfo); } assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); } @Test public void testUpstreamHotspotDetection() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectIeId() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdc, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectOUI() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x1A, (byte) 0x11 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectSsid() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"another ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectType() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x0a, data); } @Test public void testUpstreamHotspotDetection_zeroLengthData() throws Exception { byte[] data = new byte[0]; doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } } Loading
src/android/net/ip/IpClient.java +73 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.net.RouteInfo.RTN_UNICAST; import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static com.android.server.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID; import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingPermission; import android.content.Context; Loading @@ -40,10 +41,13 @@ import android.net.Uri; import android.net.apf.ApfCapabilities; import android.net.apf.ApfFilter; import android.net.dhcp.DhcpClient; import android.net.dhcp.DhcpPacket; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; import android.net.shared.InitialConfiguration; import android.net.shared.ProvisioningConfiguration; import android.net.shared.ProvisioningConfiguration.ScanResultInfo; import android.net.shared.ProvisioningConfiguration.ScanResultInfo.InformationElement; import android.net.util.InterfaceParams; import android.net.util.NetworkStackUtils; import android.net.util.SharedLog; Loading @@ -64,6 +68,7 @@ import android.util.SparseArray; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.IState; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; Loading @@ -80,6 +85,10 @@ import com.android.server.NetworkStackService.NetworkStackServiceManager; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; Loading Loading @@ -406,6 +415,13 @@ public class IpClient extends StateMachine { private static final int PROV_CHANGE_GAINED_PROVISIONING = 3; private static final int PROV_CHANGE_STILL_PROVISIONED = 4; // Specific vendor OUI(3 bytes)/vendor specific type(1 byte) pattern for upstream hotspot // device detection. Add new byte array pattern below in turn. private static final List<byte[]> METERED_IE_PATTERN_LIST = Collections.unmodifiableList( Arrays.asList( new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xf2, (byte) 0x06 } )); private final State mStoppedState = new StoppedState(); private final State mStoppingState = new StoppingState(); private final State mClearingIpAddressesState = new ClearingIpAddressesState(); Loading Loading @@ -1265,15 +1281,70 @@ public class IpClient extends StateMachine { return (delta != PROV_CHANGE_LOST_PROVISIONING); } @VisibleForTesting static String removeDoubleQuotes(@NonNull String ssid) { final int length = ssid.length(); if ((length > 1) && (ssid.charAt(0) == '"') && (ssid.charAt(length - 1) == '"')) { return ssid.substring(1, length - 1); } return ssid; } private List<ByteBuffer> getVendorSpecificIEs(@NonNull ScanResultInfo scanResultInfo) { ArrayList<ByteBuffer> vendorSpecificPayloadList = new ArrayList<>(); for (InformationElement ie : scanResultInfo.getInformationElements()) { if (ie.getId() == VENDOR_SPECIFIC_IE_ID) { vendorSpecificPayloadList.add(ie.getPayload()); } } return vendorSpecificPayloadList; } private boolean detectUpstreamHotspotFromVendorIe() { if (mConfiguration.mScanResultInfo == null) return false; final ScanResultInfo scanResultInfo = mConfiguration.mScanResultInfo; final String ssid = scanResultInfo.getSsid(); final List<ByteBuffer> vendorSpecificPayloadList = getVendorSpecificIEs(scanResultInfo); if (mConfiguration.mDisplayName == null || !removeDoubleQuotes(mConfiguration.mDisplayName).equals(ssid)) { return false; } for (ByteBuffer payload : vendorSpecificPayloadList) { byte[] ouiAndType = new byte[4]; try { payload.get(ouiAndType); } catch (BufferUnderflowException e) { Log.e(mTag, "Couldn't parse vendor specific IE, buffer underflow"); return false; } for (byte[] pattern : METERED_IE_PATTERN_LIST) { if (Arrays.equals(pattern, ouiAndType)) { if (DBG) { Log.d(mTag, "detected upstream hotspot that matches OUI:" + HexDump.toHexString(ouiAndType)); } return true; } } } return false; } private void handleIPv4Success(DhcpResults dhcpResults) { mDhcpResults = new DhcpResults(dhcpResults); final LinkProperties newLp = assembleLinkProperties(); final int delta = setLinkProperties(newLp); if (mDhcpResults.vendorInfo == null && detectUpstreamHotspotFromVendorIe()) { mDhcpResults.vendorInfo = DhcpPacket.VENDOR_INFO_ANDROID_METERED; } if (DBG) { Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")"); Log.d(mTag, "onNewDhcpResults(" + Objects.toString(mDhcpResults) + ")"); } mCallback.onNewDhcpResults(dhcpResults); mCallback.onNewDhcpResults(mDhcpResults); maybeSaveNetworkToIpMemoryStore(); dispatchCallback(delta, newLp); Loading
src/android/net/util/ConnectivityPacketSummary.java +4 −4 Original line number Diff line number Diff line Loading @@ -84,8 +84,8 @@ public class ConnectivityPacketSummary { /** * Create a string summary of a received packet. * @param hwaddr MacAddress of the receiving device. * @param buffer Buffer of the packet. Length is assumed to be the buffer length. * @param hwaddr MacAddress of the interface sending/receiving the packet. * @param buffer The packet bytes. Length is assumed to be the buffer length. * @return A summary of the packet. */ public static String summarize(MacAddress hwaddr, byte[] buffer) { Loading @@ -97,8 +97,8 @@ public class ConnectivityPacketSummary { /** * Create a string summary of a received packet. * @param macAddr MacAddress of the receiving device. * @param buffer Buffer of the packet. * @param macAddr MacAddress of the interface sending/receiving the packet. * @param buffer The packet bytes. * @param length Length of the packet. * @return A summary of the packet. */ Loading
src/com/android/server/util/NetworkStackConstants.java +8 −0 Original line number Diff line number Diff line Loading @@ -148,6 +148,14 @@ public final class NetworkStackConstants { public static final int INFINITE_LEASE = 0xffffffff; public static final int DHCP4_CLIENT_PORT = 68; /** * IEEE802.11 standard constants. * * See also: * - https://ieeexplore.ieee.org/document/7786995 */ public static final int VENDOR_SPECIFIC_IE_ID = 0xdd; private NetworkStackConstants() { throw new UnsupportedOperationException("This class is not to be instantiated"); } Loading
tests/integration/src/android/net/ip/IpClientIntegrationTest.java +119 −8 Original line number Diff line number Diff line Loading @@ -24,9 +24,11 @@ import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_L2; import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; import static android.net.ip.IpClient.removeDoubleQuotes; import static android.net.ipmemorystore.Status.SUCCESS; import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.IPPROTO_TCP; Loading @@ -47,6 +49,7 @@ import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICI import static com.android.server.util.NetworkStackConstants.IPV6_HEADER_LEN; import static com.android.server.util.NetworkStackConstants.IPV6_LEN_OFFSET; import static com.android.server.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET; import static com.android.server.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID; import static junit.framework.Assert.fail; Loading Loading @@ -78,6 +81,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.DhcpResults; import android.net.DhcpResultsParcelable; import android.net.INetd; import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; Loading @@ -100,6 +105,7 @@ import android.net.ipmemorystore.NetworkAttributes; import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener; import android.net.ipmemorystore.Status; import android.net.shared.ProvisioningConfiguration; import android.net.shared.ProvisioningConfiguration.ScanResultInfo; import android.net.util.InterfaceParams; import android.net.util.IpUtils; import android.net.util.NetworkStackUtils; Loading Loading @@ -152,6 +158,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.Random; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; Loading Loading @@ -226,6 +233,10 @@ public class IpClientIntegrationTest { private static final String TEST_HOST_NAME = "AOSP on Crosshatch"; private static final String TEST_HOST_NAME_TRANSLITERATION = "AOSP-on-Crosshatch"; private static final String TEST_CAPTIVE_PORTAL_URL = "https://example.com/capportapi"; private static final byte[] TEST_HOTSPOT_OUI = new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }; private static final byte TEST_VENDOR_SPECIFIC_TYPE = 0x06; private static class TapPacketReader extends PacketReader { private final ParcelFileDescriptor mTapFd; Loading Loading @@ -549,12 +560,15 @@ public class IpClientIntegrationTest { private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled, final boolean shouldReplyRapidCommitAck, final boolean isPreconnectionEnabled, final boolean isDhcpIpConflictDetectEnabled, final boolean isHostnameConfigurationEnabled, final String hostname) final boolean isHostnameConfigurationEnabled, final String hostname, final String displayName, final ScanResultInfo scanResultInfo) throws RemoteException { ProvisioningConfiguration.Builder builder = new ProvisioningConfiguration.Builder() .withoutIpReachabilityMonitor() .withoutIPv6(); if (isPreconnectionEnabled) builder.withPreconnection(); if (displayName != null) builder.withDisplayName(displayName); if (scanResultInfo != null) builder.withScanResultInfo(scanResultInfo); mDependencies.setDhcpLeaseCacheEnabled(isDhcpLeaseCacheEnabled); mDependencies.setDhcpRapidCommitEnabled(shouldReplyRapidCommitAck); Loading @@ -575,7 +589,8 @@ public class IpClientIntegrationTest { throws RemoteException { startIpClientProvisioning(isDhcpLeaseCacheEnabled, isDhcpRapidCommitEnabled, isPreconnectionEnabled, isDhcpIpConflictDetectEnabled, false /* isHostnameConfigurationEnabled */, null /* hostname */); false /* isHostnameConfigurationEnabled */, null /* hostname */, null /* displayName */, null /* ScanResultInfo */); } private void assertIpMemoryStoreNetworkAttributes(final Integer leaseTimeSec, Loading Loading @@ -633,10 +648,11 @@ public class IpClientIntegrationTest { final boolean shouldReplyRapidCommitAck, final int mtu, final boolean isDhcpIpConflictDetectEnabled, final boolean isHostnameConfigurationEnabled, final String hostname, final String captivePortalApiUrl) throws Exception { final String captivePortalApiUrl, final String displayName, final ScanResultInfo scanResultInfo) throws Exception { startIpClientProvisioning(isDhcpLeaseCacheEnabled, shouldReplyRapidCommitAck, false /* isPreconnectionEnabled */, isDhcpIpConflictDetectEnabled, isHostnameConfigurationEnabled, hostname); isHostnameConfigurationEnabled, hostname, displayName, scanResultInfo); return handleDhcpPackets(isSuccessLease, leaseTimeSec, shouldReplyRapidCommitAck, mtu, isDhcpIpConflictDetectEnabled, captivePortalApiUrl); } Loading Loading @@ -693,7 +709,7 @@ public class IpClientIntegrationTest { return performDhcpHandshake(isSuccessLease, leaseTimeSec, isDhcpLeaseCacheEnabled, isDhcpRapidCommitEnabled, mtu, isDhcpIpConflictDetectEnabled, false /* isHostnameConfigurationEnabled */, null /* hostname */, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); } private DhcpPacket getNextDhcpPacket() throws ParseException { Loading Loading @@ -1484,7 +1500,7 @@ public class IpClientIntegrationTest { false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, true /* isHostnameConfigurationEnabled */, TEST_HOST_NAME /* hostname */, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); assertEquals(2, sentPackets.size()); assertHostname(true, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets); assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); Loading @@ -1498,7 +1514,7 @@ public class IpClientIntegrationTest { false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, false /* isHostnameConfigurationEnabled */, TEST_HOST_NAME, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); assertEquals(2, sentPackets.size()); assertHostname(false, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets); assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); Loading @@ -1512,7 +1528,7 @@ public class IpClientIntegrationTest { false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, true /* isHostnameConfigurationEnabled */, null /* hostname */, null /* captivePortalApiUrl */); null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */); assertEquals(2, sentPackets.size()); assertHostname(true, null /* hostname */, null /* hostnameAfterTransliteration */, sentPackets); Loading Loading @@ -1566,4 +1582,99 @@ public class IpClientIntegrationTest { assumeFalse(CaptivePortalDataShimImpl.isSupported()); runDhcpClientCaptivePortalApiTest(false /* featureEnabled */, true /* serverSendsOption */); } private ScanResultInfo makeScanResultInfo(final int id, final String ssid, final byte[] oui, final byte type, final byte[] data) { final ByteBuffer payload = ByteBuffer.allocate(4 + data.length); payload.put(oui); payload.put(type); payload.put(data); payload.flip(); final ScanResultInfo.InformationElement ie = new ScanResultInfo.InformationElement(id /* IE id */, payload); return new ScanResultInfo(ssid, Collections.singletonList(ie)); } private void doUpstreamHotspotDetectionTest(final int id, final String displayName, final String ssid, final byte[] oui, final byte type, final byte[] data) throws Exception { final ScanResultInfo info = makeScanResultInfo(id, ssid, oui, type, data); final long currentTime = System.currentTimeMillis(); final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, false /* isHostnameConfigurationEnabled */, null /* hostname */, null /* captivePortalApiUrl */, displayName, info /* scanResultInfo */); assertEquals(2, sentPackets.size()); ArgumentCaptor<DhcpResultsParcelable> captor = ArgumentCaptor.forClass(DhcpResultsParcelable.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(captor.capture()); DhcpResults lease = fromStableParcelable(captor.getValue()); assertNotNull(lease); assertEquals(lease.getIpAddress().getAddress(), CLIENT_ADDR); assertEquals(lease.getGateway(), SERVER_ADDR); assertEquals(1, lease.getDnsServers().size()); assertTrue(lease.getDnsServers().contains(SERVER_ADDR)); assertEquals(lease.getServerAddress(), SERVER_ADDR); assertEquals(lease.getMtu(), TEST_DEFAULT_MTU); if (id == VENDOR_SPECIFIC_IE_ID && ssid.equals(removeDoubleQuotes(displayName)) && Arrays.equals(oui, TEST_HOTSPOT_OUI) && type == TEST_VENDOR_SPECIFIC_TYPE) { assertEquals(lease.vendorInfo, DhcpPacket.VENDOR_INFO_ANDROID_METERED); } else { assertNull(lease.vendorInfo); } assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); } @Test public void testUpstreamHotspotDetection() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectIeId() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdc, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectOUI() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x1A, (byte) 0x11 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectSsid() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"another ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } @Test public void testUpstreamHotspotDetection_incorrectType() throws Exception { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x0a, data); } @Test public void testUpstreamHotspotDetection_zeroLengthData() throws Exception { byte[] data = new byte[0]; doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); } }