diff options
author | Xiao Ma <xiaom@google.com> | 2020-04-16 05:56:41 +0000 |
---|---|---|
committer | Xiao Ma <xiaom@google.com> | 2020-04-16 06:43:56 +0000 |
commit | 39cd852a2060a579a79db2740e52b2c7129a3845 (patch) | |
tree | a0715af2b78d2fb02b307513295ef03236c8b5c6 | |
parent | 9aef7f0ee06f4715e5e447303752f33656689d91 (diff) |
Renew previous IP address when roaming happens in certain specific Wi-Fi networks.
Bug: 131797393
Test: atest NetworkStackTests NetworkStackIntegrationTests
Test: atest FrameworksNetTests
Merged-In: I65ebdd142a2bb402035c63cd282bc2574ddf3d8d
Change-Id: I65ebdd142a2bb402035c63cd282bc2574ddf3d8d
-rw-r--r-- | src/android/net/dhcp/DhcpClient.java | 6 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpPacket.java | 3 | ||||
-rw-r--r-- | src/android/net/ip/IpClient.java | 72 | ||||
-rw-r--r-- | tests/integration/src/android/net/ip/IpClientIntegrationTest.java | 163 |
4 files changed, 216 insertions, 28 deletions
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java index 41e54a4..23e68fa 100644 --- a/src/android/net/dhcp/DhcpClient.java +++ b/src/android/net/dhcp/DhcpClient.java @@ -233,6 +233,9 @@ public class DhcpClient extends StateMachine { public static final int CMD_START_PRECONNECTION = PUBLIC_BASE + 10; public static final int CMD_ABORT_PRECONNECTION = PUBLIC_BASE + 11; + // Command to rebind the leased IPv4 address on L2 roaming happened. + public static final int CMD_REFRESH_LINKADDRESS = PUBLIC_BASE + 12; + /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */ public static final int DHCP_SUCCESS = 1; public static final int DHCP_FAILURE = 2; @@ -1674,6 +1677,9 @@ public class DhcpClient extends StateMachine { case CMD_RENEW_DHCP: preDhcpTransitionTo(mWaitBeforeRenewalState, mDhcpRenewingState); return HANDLED; + case CMD_REFRESH_LINKADDRESS: + transitionTo(mDhcpRebindingState); + return HANDLED; default: return NOT_HANDLED; } diff --git a/src/android/net/dhcp/DhcpPacket.java b/src/android/net/dhcp/DhcpPacket.java index a695060..852719e 100644 --- a/src/android/net/dhcp/DhcpPacket.java +++ b/src/android/net/dhcp/DhcpPacket.java @@ -335,7 +335,8 @@ public abstract class DhcpPacket { * proposed by the client (from an earlier DHCP negotiation) or * supplied by the server. */ - protected final Inet4Address mClientIp; + @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) + public final Inet4Address mClientIp; protected final Inet4Address mYourIp; private final Inet4Address mNextIp; protected final Inet4Address mRelayIp; diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index 9ad2c78..4ddcc13 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java @@ -32,6 +32,7 @@ import android.net.Layer2InformationParcelable; import android.net.Layer2PacketParcelable; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.MacAddress; import android.net.NattKeepalivePacketDataParcelable; import android.net.NetworkStackIpMemoryStore; import android.net.ProvisioningConfigurationParcelable; @@ -92,6 +93,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -381,7 +383,8 @@ public class IpClient extends StateMachine { private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13; private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14; private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15; - protected static final int CMD_COMPLETE_PRECONNECTION = 16; + private static final int CMD_COMPLETE_PRECONNECTION = 16; + private static final int CMD_UPDATE_L2INFORMATION = 17; // Internal commands to use instead of trying to call transitionTo() inside // a given State's enter() method. Calling transitionTo() from enter/exit @@ -423,6 +426,14 @@ public class IpClient extends StateMachine { new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xf2, (byte) 0x06 } )); + // Initialize configurable particular SSID set supporting DHCP Roaming feature. See + // b/131797393 for more details. + private static final Set<String> DHCP_ROAMING_SSID_SET = new HashSet<>( + Arrays.asList( + "0001docomo", "ollehWiFi", "olleh GiGa WiFi", "KT WiFi", + "KT GiGA WiFi", "marente" + )); + private final State mStoppedState = new StoppedState(); private final State mStoppingState = new StoppingState(); private final State mClearingIpAddressesState = new ClearingIpAddressesState(); @@ -470,6 +481,7 @@ public class IpClient extends StateMachine { private String mGroupHint; // The group hint for this network, for writing into the memory store private boolean mMulticastFiltering; private long mStartTimeMillis; + private MacAddress mCurrentBssid; /** * Reading the snapshot is an asynchronous operation initiated by invoking @@ -704,7 +716,6 @@ public class IpClient extends StateMachine { enforceNetworkStackCallingPermission(); IpClient.this.notifyPreconnectionComplete(success); } - @Override public void updateLayer2Information(Layer2InformationParcelable info) { enforceNetworkStackCallingPermission(); @@ -772,6 +783,16 @@ public class IpClient extends StateMachine { return; } + final ScanResultInfo scanResultInfo = req.mScanResultInfo; + mCurrentBssid = null; + if (scanResultInfo != null) { + try { + mCurrentBssid = MacAddress.fromString(scanResultInfo.getBssid()); + } catch (IllegalArgumentException e) { + Log.wtf(mTag, "Invalid BSSID: " + scanResultInfo.getBssid() + + " in provisioning configuration", e); + } + } sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req)); } @@ -819,9 +840,14 @@ public class IpClient extends StateMachine { /** * Set the L2 key and group hint for storing info into the memory store. + * + * This method is only supported on Q devices. For R or above releases, + * caller should call #updateLayer2Information() instead. */ public void setL2KeyAndGroupHint(String l2Key, String groupHint) { - sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint)); + if (!ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) { + sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint)); + } } /** @@ -880,7 +906,7 @@ public class IpClient extends StateMachine { * Update the network bssid, L2Key and GroupHint layer2 information. */ public void updateLayer2Information(@NonNull Layer2InformationParcelable info) { - // TODO: add specific implementation. + sendMessage(CMD_UPDATE_L2INFORMATION, info); } /** @@ -1502,6 +1528,36 @@ public class IpClient extends StateMachine { } } + private void handleUpdateL2Information(@NonNull Layer2InformationParcelable info) { + mL2Key = info.l2Key; + mGroupHint = info.groupHint; + + // This means IpClient is still in the StoppedState, WiFi is trying to associate + // to the AP, just update L2Key and GroupHint at this stage, because these members + // will be used when starting DhcpClient. + if (info.bssid == null || mCurrentBssid == null) return; + + // If the BSSID has not changed, there is nothing to do. + if (info.bssid.equals(mCurrentBssid)) return; + + if (mIpReachabilityMonitor != null) { + mIpReachabilityMonitor.probeAll(); + } + + // Check whether to refresh previous IP lease on L2 roaming happened. + final String ssid = removeDoubleQuotes(mConfiguration.mDisplayName); + if (DHCP_ROAMING_SSID_SET.contains(ssid) && mDhcpClient != null) { + if (DBG) { + Log.d(mTag, "L2 roaming happened from " + mCurrentBssid + + " to " + info.bssid + + " , SSID: " + ssid + + " , starting refresh leased IP address"); + } + mDhcpClient.sendMessage(DhcpClient.CMD_REFRESH_LINKADDRESS); + } + mCurrentBssid = info.bssid; + } + class StoppedState extends State { @Override public void enter() { @@ -1554,6 +1610,10 @@ public class IpClient extends StateMachine { break; } + case CMD_UPDATE_L2INFORMATION: + handleUpdateL2Information((Layer2InformationParcelable) msg.obj); + break; + case CMD_SET_MULTICAST_FILTER: mMulticastFiltering = (boolean) msg.obj; break; @@ -1763,6 +1823,10 @@ public class IpClient extends StateMachine { break; } + case CMD_UPDATE_L2INFORMATION: + handleUpdateL2Information((Layer2InformationParcelable) msg.obj); + break; + case EVENT_PROVISIONING_TIMEOUT: handleProvisioningFailure(); break; diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java index ce2efbb..56ad6c1 100644 --- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java +++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java @@ -24,7 +24,6 @@ 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; @@ -49,7 +48,6 @@ 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; @@ -87,6 +85,7 @@ import android.net.INetd; import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; +import android.net.Layer2InformationParcelable; import android.net.Layer2PacketParcelable; import android.net.LinkAddress; import android.net.LinkProperties; @@ -217,6 +216,8 @@ public class IpClientIntegrationTest { (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.100"); private static final Inet4Address CLIENT_ADDR = (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.2"); + private static final Inet4Address CLIENT_ADDR_NEW = + (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.3"); private static final Inet4Address INADDR_ANY = (Inet4Address) InetAddresses.parseNumericAddress("0.0.0.0"); private static final int PREFIX_LENGTH = 24; @@ -234,7 +235,14 @@ public class IpClientIntegrationTest { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }; private static final byte TEST_VENDOR_SPECIFIC_TYPE = 0x06; + + private static final String TEST_DEFAULT_SSID = "test_ssid"; private static final String TEST_DEFAULT_BSSID = "00:11:22:33:44:55"; + private static final String TEST_DHCP_ROAM_SSID = "0001docomo"; + private static final String TEST_DHCP_ROAM_BSSID = "00:4e:35:17:98:55"; + private static final String TEST_DHCP_ROAM_L2KEY = "roaming_l2key"; + private static final String TEST_DHCP_ROAM_GROUPHINT = "roaming_group_hint"; + private static final byte[] TEST_AP_OUI = new byte[] { 0x00, 0x1A, 0x11 }; private class Dependencies extends IpClient.Dependencies { private boolean mIsDhcpLeaseCacheEnabled; @@ -473,11 +481,11 @@ public class IpClientIntegrationTest { } private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet, - final Integer leaseTimeSec, final short mtu, final boolean rapidCommit, - final String captivePortalApiUrl) { + final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu, + final boolean rapidCommit, final String captivePortalApiUrl) { return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */, - CLIENT_ADDR /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(), + clientAddress /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(), leaseTimeSec, NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */, Collections.singletonList(SERVER_ADDR) /* dnsServers */, @@ -524,7 +532,15 @@ public class IpClientIntegrationTest { mDependencies.setDhcpRapidCommitEnabled(shouldReplyRapidCommitAck); mDependencies.setDhcpIpConflictDetectEnabled(isDhcpIpConflictDetectEnabled); mDependencies.setHostnameConfiguration(isHostnameConfigurationEnabled, hostname); - mIpc.setL2KeyAndGroupHint(TEST_L2KEY, TEST_GROUPHINT); + + if (ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) { + final Layer2InformationParcelable info = new Layer2InformationParcelable(); + info.l2Key = TEST_L2KEY; + info.groupHint = TEST_GROUPHINT; + mIpc.updateLayer2Information(info); + } else { + mIpc.setL2KeyAndGroupHint(TEST_L2KEY, TEST_GROUPHINT); + } mIpc.startProvisioning(builder.build()); if (!isPreconnectionEnabled) { verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false); @@ -616,15 +632,15 @@ public class IpClientIntegrationTest { packetList.add(packet); if (packet instanceof DhcpDiscoverPacket) { if (shouldReplyRapidCommitAck) { - mPacketReader.sendResponse(buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu, - true /* rapidCommit */, captivePortalApiUrl)); + mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec, + (short) mtu, true /* rapidCommit */, captivePortalApiUrl)); } else { mPacketReader.sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec, (short) mtu, captivePortalApiUrl)); } } else if (packet instanceof DhcpRequestPacket) { final ByteBuffer byteBuffer = isSuccessLease - ? buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu, + ? buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec, (short) mtu, false /* rapidCommit */, captivePortalApiUrl) : buildDhcpNakPacket(packet); mPacketReader.sendResponse(byteBuffer); @@ -810,8 +826,8 @@ public class IpClientIntegrationTest { packet = getNextDhcpPacket(); assertTrue(packet instanceof DhcpRequestPacket); } - mPacketReader.sendResponse(buildDhcpAckPacket(packet, TEST_LEASE_DURATION_S, mtu, - shouldReplyRapidCommitAck, null /* captivePortalUrl */)); + mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, TEST_LEASE_DURATION_S, + mtu, shouldReplyRapidCommitAck, null /* captivePortalUrl */)); if (!shouldAbortPreconnection) { mIpc.notifyPreconnectionComplete(true /* success */); @@ -1590,9 +1606,15 @@ public class IpClientIntegrationTest { return new ScanResultInfo(ssid, bssid, Collections.singletonList(ie)); } + private ScanResultInfo makeScanResultInfo(final String ssid, final String bssid) { + byte[] data = new byte[10]; + new Random().nextBytes(data); + return makeScanResultInfo(0xdd, ssid, bssid, TEST_AP_OUI, (byte) 0x06, data); + } + private void doUpstreamHotspotDetectionTest(final int id, final String displayName, - final String ssid, final byte[] oui, final byte type, final byte[] data) - throws Exception { + final String ssid, final byte[] oui, final byte type, final byte[] data, + final boolean expectMetered) throws Exception { final ScanResultInfo info = makeScanResultInfo(id, ssid, TEST_DEFAULT_BSSID, oui, type, data); final long currentTime = System.currentTimeMillis(); @@ -1615,10 +1637,8 @@ public class IpClientIntegrationTest { 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) { + + if (expectMetered) { assertEquals(lease.vendorInfo, DhcpPacket.VENDOR_INFO_ANDROID_METERED); } else { assertNull(lease.vendorInfo); @@ -1632,7 +1652,8 @@ public class IpClientIntegrationTest { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", - new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); + new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, + true /* expectMetered */); } @Test @@ -1640,7 +1661,8 @@ public class IpClientIntegrationTest { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdc, "\"ssid\"", "ssid", - new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data); + new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, + false /* expectMetered */); } @Test @@ -1648,7 +1670,8 @@ public class IpClientIntegrationTest { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", - new byte[] { (byte) 0x00, (byte) 0x1A, (byte) 0x11 }, (byte) 0x06, data); + new byte[] { (byte) 0x00, (byte) 0x1A, (byte) 0x11 }, (byte) 0x06, data, + false /* expectMetered */); } @Test @@ -1656,7 +1679,8 @@ public class IpClientIntegrationTest { 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); + new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, + false /* expectMetered */); } @Test @@ -1664,13 +1688,106 @@ public class IpClientIntegrationTest { byte[] data = new byte[10]; new Random().nextBytes(data); doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid", - new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x0a, data); + new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x0a, data, + false /* expectMetered */); } @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); + new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, + true /* expectMetered */); + } + + private void doDhcpRoamingTest(final boolean hasMismatchedIpAddress, final String displayName, + final String ssid, final String bssid, final boolean expectRoaming) throws Exception { + long currentTime = System.currentTimeMillis(); + final ScanResultInfo scanResultInfo = makeScanResultInfo(ssid, bssid); + + doAnswer(invocation -> { + // we don't rely on the Init-Reboot state to renew previous cached IP lease. + // Just return null and force state machine enter INIT state. + return null; + }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any()); + + performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, + true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */, + TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, + true /* isHostnameConfigurationEnabled */, null /* hostname */, + null /* captivePortalApiUrl */, displayName, scanResultInfo); + assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); + + // simulate the roaming by updating bssid. + final Layer2InformationParcelable roamingInfo = new Layer2InformationParcelable(); + roamingInfo.bssid = MacAddress.fromString(TEST_DHCP_ROAM_BSSID); + roamingInfo.l2Key = TEST_DHCP_ROAM_L2KEY; + roamingInfo.groupHint = TEST_DHCP_ROAM_GROUPHINT; + mIpc.updateLayer2Information(roamingInfo); + + currentTime = System.currentTimeMillis(); + reset(mIpMemoryStore); + reset(mCb); + if (!expectRoaming) { + assertIpMemoryNeverStoreNetworkAttributes(); + return; + } + // check DHCPREQUEST broadcast sent to renew IP address. + DhcpPacket packet; + packet = getNextDhcpPacket(); + assertTrue(packet instanceof DhcpRequestPacket); + assertEquals(packet.mClientIp, CLIENT_ADDR); // client IP + assertNull(packet.mRequestedIp); // requested IP option + assertNull(packet.mServerIdentifier); // server ID + + mPacketReader.sendResponse(buildDhcpAckPacket(packet, + hasMismatchedIpAddress ? CLIENT_ADDR_NEW : CLIENT_ADDR, TEST_LEASE_DURATION_S, + (short) TEST_DEFAULT_MTU, false /* rapidcommit */, null /* captivePortalUrl */)); + HandlerUtilsKt.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); + if (hasMismatchedIpAddress) { + // notifyFailure + ArgumentCaptor<DhcpResultsParcelable> captor = + ArgumentCaptor.forClass(DhcpResultsParcelable.class); + verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(captor.capture()); + DhcpResults lease = fromStableParcelable(captor.getValue()); + assertNull(lease); + + // roll back to INIT state. + packet = getNextDhcpPacket(); + assertTrue(packet instanceof DhcpDiscoverPacket); + } else { + assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, + TEST_DEFAULT_MTU); + } + } + + @Test + public void testDhcpRoaming() throws Exception { + doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, + TEST_DHCP_ROAM_SSID, TEST_DEFAULT_BSSID, true /* expectRoaming */); + } + + @Test + public void testDhcpRoaming_invalidBssid() throws Exception { + doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, + TEST_DHCP_ROAM_SSID, TEST_DHCP_ROAM_BSSID, false /* expectRoaming */); + } + + @Test + public void testDhcpRoaming_invalidSsid() throws Exception { + doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, + TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID, false /* expectRoaming */); + } + + @Test + public void testDhcpRoaming_invalidDisplayName() throws Exception { + doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"test-ssid\"" /* display name */, + TEST_DHCP_ROAM_SSID, TEST_DEFAULT_BSSID, false /* expectRoaming */); + } + + @Test + public void testDhcpRoaming_mismatchedLeasedIpAddress() throws Exception { + doDhcpRoamingTest(true /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, + TEST_DHCP_ROAM_SSID, TEST_DEFAULT_BSSID, true /* expectRoaming */); } } |