1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.dhcp; 18 19 import static android.net.InetAddresses.parseNumericAddress; 20 import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; 21 import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; 22 import static android.net.dhcp.DhcpPacket.INADDR_ANY; 23 import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; 24 import static android.net.dhcp.DhcpServer.CMD_RECEIVE_PACKET; 25 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; 26 import static android.net.util.NetworkStackUtils.DHCP_RAPID_COMMIT_VERSION; 27 28 import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; 29 30 import static junit.framework.Assert.assertEquals; 31 import static junit.framework.Assert.assertFalse; 32 import static junit.framework.Assert.assertNotNull; 33 import static junit.framework.Assert.assertTrue; 34 35 import static org.mockito.ArgumentMatchers.any; 36 import static org.mockito.ArgumentMatchers.eq; 37 import static org.mockito.ArgumentMatchers.isNull; 38 import static org.mockito.Mockito.doNothing; 39 import static org.mockito.Mockito.never; 40 import static org.mockito.Mockito.times; 41 import static org.mockito.Mockito.verify; 42 import static org.mockito.Mockito.when; 43 44 import android.annotation.NonNull; 45 import android.annotation.Nullable; 46 import android.content.Context; 47 import android.net.INetworkStackStatusCallback; 48 import android.net.IpPrefix; 49 import android.net.LinkAddress; 50 import android.net.MacAddress; 51 import android.net.dhcp.DhcpLeaseRepository.InvalidAddressException; 52 import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException; 53 import android.net.dhcp.DhcpServer.Clock; 54 import android.net.dhcp.DhcpServer.Dependencies; 55 import android.net.util.SharedLog; 56 import android.os.ConditionVariable; 57 import android.testing.AndroidTestingRunner; 58 59 import androidx.test.filters.SmallTest; 60 61 import com.android.net.module.util.Inet4AddressUtils; 62 import com.android.testutils.HandlerUtils; 63 64 import org.junit.After; 65 import org.junit.Before; 66 import org.junit.Test; 67 import org.junit.runner.RunWith; 68 import org.mockito.ArgumentCaptor; 69 import org.mockito.Captor; 70 import org.mockito.Mock; 71 import org.mockito.MockitoAnnotations; 72 73 import java.net.Inet4Address; 74 import java.nio.ByteBuffer; 75 import java.util.Arrays; 76 import java.util.Collection; 77 import java.util.Collections; 78 import java.util.HashSet; 79 import java.util.Set; 80 81 @RunWith(AndroidTestingRunner.class) 82 @SmallTest 83 public class DhcpServerTest { 84 private static final String TEST_IFACE = "testiface"; 85 86 private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2"); 87 private static final int TEST_PREFIX_LENGTH = 20; 88 private static final LinkAddress TEST_SERVER_LINKADDR = new LinkAddress( 89 TEST_SERVER_ADDR, TEST_PREFIX_LENGTH); 90 private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>( 91 Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124"))); 92 private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>( 93 Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127"))); 94 private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>( 95 Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201"))); 96 private static final long TEST_LEASE_TIME_SECS = 3600L; 97 private static final int TEST_MTU = 1500; 98 private static final String TEST_HOSTNAME = "testhostname"; 99 100 private static final int TEST_TRANSACTION_ID = 123; 101 private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 }; 102 private static final MacAddress TEST_CLIENT_MAC = MacAddress.fromBytes(TEST_CLIENT_MAC_BYTES); 103 private static final Inet4Address TEST_CLIENT_ADDR = parseAddr("192.168.0.42"); 104 105 private static final long TEST_CLOCK_TIME = 1234L; 106 private static final int TEST_LEASE_EXPTIME_SECS = 3600; 107 private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC, 108 TEST_CLIENT_ADDR, TEST_PREFIX_LENGTH, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, 109 null /* hostname */); 110 private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC, 111 TEST_CLIENT_ADDR, TEST_PREFIX_LENGTH, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, 112 TEST_HOSTNAME); 113 private static final int TEST_TIMEOUT_MS = 10000; 114 115 @NonNull @Mock 116 private Context mContext; 117 @NonNull @Mock 118 private Dependencies mDeps; 119 @NonNull @Mock 120 private DhcpLeaseRepository mRepository; 121 @NonNull @Mock 122 private Clock mClock; 123 @NonNull @Mock 124 private DhcpPacketListener mPacketListener; 125 @NonNull @Mock 126 private IDhcpEventCallbacks mEventCallbacks; 127 128 @NonNull @Captor 129 private ArgumentCaptor<ByteBuffer> mSentPacketCaptor; 130 @NonNull @Captor 131 private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor; 132 133 @NonNull 134 private MyDhcpServer mServer; 135 136 @Nullable 137 private String mPrevShareClassloaderProp; 138 139 private class MyDhcpServer extends DhcpServer { 140 private final ConditionVariable mCv = new ConditionVariable(false); 141 MyDhcpServer(Context context, String ifName, DhcpServingParams params, SharedLog log, Dependencies deps)142 MyDhcpServer(Context context, String ifName, DhcpServingParams params, SharedLog log, 143 Dependencies deps) { 144 super(context, ifName, params, log, deps); 145 } 146 147 @Override onQuitting()148 protected void onQuitting() { 149 super.onQuitting(); 150 mCv.open(); 151 } 152 waitForShutdown()153 public void waitForShutdown() { 154 assertTrue(mCv.block(TEST_TIMEOUT_MS)); 155 } 156 } 157 158 private final INetworkStackStatusCallback mAssertSuccessCallback = 159 new INetworkStackStatusCallback.Stub() { 160 @Override 161 public void onStatusAvailable(int statusCode) { 162 assertEquals(STATUS_SUCCESS, statusCode); 163 } 164 165 @Override 166 public int getInterfaceVersion() { 167 return this.VERSION; 168 } 169 170 @Override 171 public String getInterfaceHash() { 172 return this.HASH; 173 } 174 }; 175 makeServingParams()176 private DhcpServingParams makeServingParams() throws Exception { 177 return new DhcpServingParams.Builder() 178 .setDefaultRouters(TEST_DEFAULT_ROUTERS) 179 .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS) 180 .setDnsServers(TEST_DNS_SERVERS) 181 .setServerAddr(TEST_SERVER_LINKADDR) 182 .setLinkMtu(TEST_MTU) 183 .setExcludedAddrs(TEST_EXCLUDED_ADDRS) 184 .setChangePrefixOnDecline(false) 185 .build(); 186 } 187 startServer()188 private void startServer() throws Exception { 189 mServer.start(mAssertSuccessCallback); 190 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 191 } 192 193 @Before setUp()194 public void setUp() throws Exception { 195 MockitoAnnotations.initMocks(this); 196 197 when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository); 198 when(mDeps.makeClock()).thenReturn(mClock); 199 when(mDeps.makePacketListener(any())).thenReturn(mPacketListener); 200 when(mDeps.isFeatureEnabled(eq(mContext), eq(DHCP_RAPID_COMMIT_VERSION))).thenReturn(true); 201 doNothing().when(mDeps) 202 .sendPacket(any(), mSentPacketCaptor.capture(), mResponseDstAddrCaptor.capture()); 203 when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME); 204 when(mPacketListener.start()).thenReturn(true); 205 206 mServer = new MyDhcpServer(mContext, TEST_IFACE, makeServingParams(), 207 new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps); 208 } 209 210 @After tearDown()211 public void tearDown() throws Exception { 212 verify(mRepository, never()).addLeaseCallbacks(eq(null)); 213 mServer.stop(mAssertSuccessCallback); 214 mServer.waitForShutdown(); 215 verify(mPacketListener, times(1)).stop(); 216 } 217 218 @Test testStart()219 public void testStart() throws Exception { 220 startServer(); 221 222 verify(mPacketListener, times(1)).start(); 223 } 224 225 @Test testStartWithCallbacks()226 public void testStartWithCallbacks() throws Exception { 227 mServer.start(mAssertSuccessCallback, mEventCallbacks); 228 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 229 verify(mRepository).addLeaseCallbacks(eq(mEventCallbacks)); 230 } 231 232 @Test testDiscover()233 public void testDiscover() throws Exception { 234 startServer(); 235 236 // TODO: refactor packet construction to eliminate unnecessary/confusing/duplicate fields 237 when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC), 238 eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */)) 239 .thenReturn(TEST_LEASE); 240 241 final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, 242 (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, 243 false /* broadcast */, INADDR_ANY /* srcIp */, false /* rapidCommit */); 244 mServer.sendMessage(CMD_RECEIVE_PACKET, discover); 245 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 246 247 assertResponseSentTo(TEST_CLIENT_ADDR); 248 final DhcpOfferPacket packet = assertOffer(getPacket()); 249 assertMatchesTestLease(packet); 250 } 251 252 @Test testDiscover_RapidCommit()253 public void testDiscover_RapidCommit() throws Exception { 254 startServer(); 255 256 when(mDeps.isFeatureEnabled(eq(mContext), eq(DHCP_RAPID_COMMIT_VERSION))).thenReturn(true); 257 when(mRepository.getCommittedLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC), 258 eq(INADDR_ANY) /* relayAddr */, isNull() /* hostname */)).thenReturn(TEST_LEASE); 259 260 final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, 261 (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, 262 false /* broadcast */, INADDR_ANY /* srcIp */, true /* rapidCommit */); 263 mServer.sendMessage(CMD_RECEIVE_PACKET, discover); 264 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 265 266 assertResponseSentTo(TEST_CLIENT_ADDR); 267 final DhcpAckPacket packet = assertAck(getPacket()); 268 assertMatchesTestLease(packet); 269 } 270 271 @Test testDiscover_OutOfAddresses()272 public void testDiscover_OutOfAddresses() throws Exception { 273 startServer(); 274 275 when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC), 276 eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */)) 277 .thenThrow(new OutOfAddressesException("Test exception")); 278 279 final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, 280 (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, 281 false /* broadcast */, INADDR_ANY /* srcIp */, false /* rapidCommit */); 282 mServer.sendMessage(CMD_RECEIVE_PACKET, discover); 283 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 284 285 assertResponseSentTo(INADDR_BROADCAST); 286 final DhcpNakPacket packet = assertNak(getPacket()); 287 assertMatchesClient(packet); 288 } 289 makeRequestSelectingPacket()290 private DhcpRequestPacket makeRequestSelectingPacket() { 291 final DhcpRequestPacket request = new DhcpRequestPacket(TEST_TRANSACTION_ID, 292 (short) 0 /* secs */, INADDR_ANY /* clientIp */, INADDR_ANY /* relayIp */, 293 TEST_CLIENT_MAC_BYTES, false /* broadcast */); 294 request.mServerIdentifier = TEST_SERVER_ADDR; 295 request.mRequestedIp = TEST_CLIENT_ADDR; 296 return request; 297 } 298 299 @Test testRequest_Selecting_Ack()300 public void testRequest_Selecting_Ack() throws Exception { 301 startServer(); 302 303 when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC), 304 eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */, 305 eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME))) 306 .thenReturn(TEST_LEASE_WITH_HOSTNAME); 307 308 final DhcpRequestPacket request = makeRequestSelectingPacket(); 309 request.mHostName = TEST_HOSTNAME; 310 request.mRequestedParams = new byte[] { DHCP_HOST_NAME }; 311 mServer.sendMessage(CMD_RECEIVE_PACKET, request); 312 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 313 314 assertResponseSentTo(TEST_CLIENT_ADDR); 315 final DhcpAckPacket packet = assertAck(getPacket()); 316 assertMatchesTestLease(packet, TEST_HOSTNAME); 317 } 318 319 @Test testRequest_Selecting_Nak()320 public void testRequest_Selecting_Nak() throws Exception { 321 startServer(); 322 323 when(mRepository.requestLease(isNull(), eq(TEST_CLIENT_MAC), 324 eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */, 325 eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */)) 326 .thenThrow(new InvalidAddressException("Test error")); 327 328 final DhcpRequestPacket request = makeRequestSelectingPacket(); 329 mServer.sendMessage(CMD_RECEIVE_PACKET, request); 330 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 331 332 assertResponseSentTo(INADDR_BROADCAST); 333 final DhcpNakPacket packet = assertNak(getPacket()); 334 assertMatchesClient(packet); 335 } 336 337 @Test testRelease()338 public void testRelease() throws Exception { 339 startServer(); 340 341 final DhcpReleasePacket release = new DhcpReleasePacket(TEST_TRANSACTION_ID, 342 TEST_SERVER_ADDR, TEST_CLIENT_ADDR, 343 INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES); 344 mServer.sendMessage(CMD_RECEIVE_PACKET, release); 345 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 346 347 verify(mRepository, times(1)) 348 .releaseLease(isNull(), eq(TEST_CLIENT_MAC), eq(TEST_CLIENT_ADDR)); 349 } 350 351 @Test testDecline_LeaseDoesNotExist()352 public void testDecline_LeaseDoesNotExist() throws Exception { 353 when(mRepository.markAndReleaseDeclinedLease(isNull(), eq(TEST_CLIENT_MAC), 354 eq(TEST_CLIENT_ADDR))).thenReturn(false); 355 356 startServer(); 357 runOnReceivedDeclinePacket(); 358 verify(mEventCallbacks, never()).onNewPrefixRequest(any()); 359 } 360 runOnReceivedDeclinePacket()361 private void runOnReceivedDeclinePacket() throws Exception { 362 when(mRepository.getCommittedLeases()).thenReturn( 363 Arrays.asList(new DhcpLease(null, TEST_CLIENT_MAC, TEST_CLIENT_ADDR, 364 TEST_PREFIX_LENGTH, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, 365 TEST_HOSTNAME))); 366 final DhcpDeclinePacket decline = new DhcpDeclinePacket(TEST_TRANSACTION_ID, 367 (short) 0 /* secs */, INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */, 368 INADDR_ANY /* nextIp */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, 369 TEST_CLIENT_ADDR /* requestedIp */, TEST_SERVER_ADDR /* serverIdentifier */); 370 mServer.sendMessage(CMD_RECEIVE_PACKET, decline); 371 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 372 373 verify(mRepository).markAndReleaseDeclinedLease(isNull(), eq(TEST_CLIENT_MAC), 374 eq(TEST_CLIENT_ADDR)); 375 } 376 toIntArray(@onNull Collection<Inet4Address> addrs)377 private int[] toIntArray(@NonNull Collection<Inet4Address> addrs) { 378 return addrs.stream().mapToInt(Inet4AddressUtils::inet4AddressToIntHTH).toArray(); 379 } 380 updateServingParams(Set<Inet4Address> defaultRouters, Set<Inet4Address> dnsServers, Set<Inet4Address> excludedAddrs, LinkAddress serverAddr, boolean changePrefixOnDecline)381 private void updateServingParams(Set<Inet4Address> defaultRouters, 382 Set<Inet4Address> dnsServers, Set<Inet4Address> excludedAddrs, LinkAddress serverAddr, 383 boolean changePrefixOnDecline) throws Exception { 384 final DhcpServingParamsParcel params = new DhcpServingParamsParcel(); 385 params.serverAddr = inet4AddressToIntHTH((Inet4Address) serverAddr.getAddress()); 386 params.serverAddrPrefixLength = serverAddr.getPrefixLength(); 387 params.defaultRouters = toIntArray(defaultRouters); 388 params.dnsServers = toIntArray(dnsServers); 389 params.excludedAddrs = toIntArray(excludedAddrs); 390 params.dhcpLeaseTimeSecs = TEST_LEASE_EXPTIME_SECS; 391 params.linkMtu = TEST_MTU; 392 params.metered = true; 393 params.changePrefixOnDecline = changePrefixOnDecline; 394 395 mServer.updateParams(params, mAssertSuccessCallback); 396 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 397 } 398 399 @Test testChangePrefixOnDecline()400 public void testChangePrefixOnDecline() throws Exception { 401 when(mRepository.markAndReleaseDeclinedLease(isNull(), eq(TEST_CLIENT_MAC), 402 eq(TEST_CLIENT_ADDR))).thenReturn(true); 403 404 mServer.start(mAssertSuccessCallback, mEventCallbacks); 405 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 406 verify(mRepository).addLeaseCallbacks(eq(mEventCallbacks)); 407 408 // Enable changePrefixOnDecline 409 updateServingParams(TEST_DEFAULT_ROUTERS, TEST_DNS_SERVERS, TEST_EXCLUDED_ADDRS, 410 TEST_SERVER_LINKADDR, true /* changePrefixOnDecline */); 411 412 runOnReceivedDeclinePacket(); 413 final IpPrefix servingPrefix = DhcpServingParams.makeIpPrefix(TEST_SERVER_LINKADDR); 414 verify(mEventCallbacks).onNewPrefixRequest(eq(servingPrefix)); 415 416 final Inet4Address serverAddr = parseAddr("192.168.51.129"); 417 final LinkAddress srvLinkAddr = new LinkAddress(serverAddr, 24); 418 final Set<Inet4Address> srvAddr = new HashSet<>(Collections.singletonList(serverAddr)); 419 final Set<Inet4Address> excludedAddrs = new HashSet<>( 420 Arrays.asList(parseAddr("192.168.51.200"), parseAddr("192.168.51.201"))); 421 422 // Simulate IpServer updates the serving params with a new prefix. 423 updateServingParams(srvAddr, srvAddr, excludedAddrs, srvLinkAddr, 424 true /* changePrefixOnDecline */); 425 426 final Inet4Address clientAddr = parseAddr("192.168.51.42"); 427 final DhcpLease lease = new DhcpLease(null, TEST_CLIENT_MAC, 428 clientAddr, 24 /*prefixLen*/, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, 429 null /* hostname */); 430 when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC), 431 eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */)) 432 .thenReturn(lease); 433 434 // Test discover packet 435 final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, 436 (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, 437 false /* broadcast */, INADDR_ANY /* srcIp */, false /* rapidCommit */); 438 mServer.sendMessage(CMD_RECEIVE_PACKET, discover); 439 HandlerUtils.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS); 440 assertResponseSentTo(clientAddr); 441 final DhcpOfferPacket packet = assertOffer(getPacket()); 442 assertMatchesLease(packet, serverAddr, clientAddr, null); 443 } 444 445 /* TODO: add more tests once packet construction is refactored, including: 446 * - usage of giaddr 447 * - usage of broadcast bit 448 * - other request states (init-reboot/renewing/rebinding) 449 */ 450 assertMatchesLease(@onNull DhcpPacket packet, @NonNull Inet4Address srvAddr, @NonNull Inet4Address clientAddr, @Nullable String hostname)451 private void assertMatchesLease(@NonNull DhcpPacket packet, @NonNull Inet4Address srvAddr, 452 @NonNull Inet4Address clientAddr, @Nullable String hostname) { 453 assertMatchesClient(packet); 454 assertFalse(packet.hasExplicitClientId()); 455 assertEquals(srvAddr, packet.mServerIdentifier); 456 assertEquals(clientAddr, packet.mYourIp); 457 assertNotNull(packet.mLeaseTime); 458 assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime); 459 assertEquals(hostname, packet.mHostName); 460 } 461 assertMatchesTestLease(@onNull DhcpPacket packet, @Nullable String hostname)462 private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) { 463 assertMatchesLease(packet, TEST_SERVER_ADDR, TEST_CLIENT_ADDR, hostname); 464 } 465 assertMatchesTestLease(@onNull DhcpPacket packet)466 private void assertMatchesTestLease(@NonNull DhcpPacket packet) { 467 assertMatchesTestLease(packet, null); 468 } 469 assertMatchesClient(@onNull DhcpPacket packet)470 private void assertMatchesClient(@NonNull DhcpPacket packet) { 471 assertEquals(TEST_TRANSACTION_ID, packet.mTransId); 472 assertEquals(TEST_CLIENT_MAC, MacAddress.fromBytes(packet.mClientMac)); 473 } 474 assertResponseSentTo(@onNull Inet4Address addr)475 private void assertResponseSentTo(@NonNull Inet4Address addr) { 476 assertEquals(addr, mResponseDstAddrCaptor.getValue()); 477 } 478 assertNak(@ullable DhcpPacket packet)479 private static DhcpNakPacket assertNak(@Nullable DhcpPacket packet) { 480 assertTrue(packet instanceof DhcpNakPacket); 481 return (DhcpNakPacket) packet; 482 } 483 assertAck(@ullable DhcpPacket packet)484 private static DhcpAckPacket assertAck(@Nullable DhcpPacket packet) { 485 assertTrue(packet instanceof DhcpAckPacket); 486 return (DhcpAckPacket) packet; 487 } 488 assertOffer(@ullable DhcpPacket packet)489 private static DhcpOfferPacket assertOffer(@Nullable DhcpPacket packet) { 490 assertTrue(packet instanceof DhcpOfferPacket); 491 return (DhcpOfferPacket) packet; 492 } 493 getPacket()494 private DhcpPacket getPacket() throws Exception { 495 verify(mDeps, times(1)).sendPacket(any(), any(), any()); 496 return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP, 497 new byte[0] /* optionsToSkip */); 498 } 499 parseAddr(@ullable String inet4Addr)500 private static Inet4Address parseAddr(@Nullable String inet4Addr) { 501 return (Inet4Address) parseNumericAddress(inet4Addr); 502 } 503 } 504