Assign specific client address to dhcp server

Bug: 141256482
Test: manual
      atest TetheringTests

Change-Id: Ief76c98c843ba5420224cbf0f34464f366c891b7
This commit is contained in:
markchien
2020-02-27 20:27:18 +08:00
parent 6d175120a0
commit 245352ed07
5 changed files with 76 additions and 22 deletions

View File

@@ -520,9 +520,8 @@ public class TetheringManager {
/** /**
* Configure tethering with static IPv4 assignment. * Configure tethering with static IPv4 assignment.
* *
* The clientAddress must be in the localIPv4Address prefix. A DHCP server will be * A DHCP server will be started, but will only be able to offer the client address.
* started, but will only be able to offer the client address. The two addresses must * The two addresses must be in the same prefix.
* be in the same prefix.
* *
* @param localIPv4Address The preferred local IPv4 link address to use. * @param localIPv4Address The preferred local IPv4 link address to use.
* @param clientAddress The static client address. * @param clientAddress The static client address.
@@ -533,10 +532,7 @@ public class TetheringManager {
@NonNull final LinkAddress clientAddress) { @NonNull final LinkAddress clientAddress) {
Objects.requireNonNull(localIPv4Address); Objects.requireNonNull(localIPv4Address);
Objects.requireNonNull(clientAddress); Objects.requireNonNull(clientAddress);
if (localIPv4Address.getPrefixLength() != clientAddress.getPrefixLength() if (!checkStaticAddressConfiguration(localIPv4Address, clientAddress)) {
|| !localIPv4Address.isIpv4() || !clientAddress.isIpv4()
|| !new IpPrefix(localIPv4Address.toString()).equals(
new IpPrefix(clientAddress.toString()))) {
throw new IllegalArgumentException("Invalid server or client addresses"); throw new IllegalArgumentException("Invalid server or client addresses");
} }
@@ -580,6 +576,19 @@ public class TetheringManager {
} }
} }
/**
* Check whether the two addresses are ipv4 and in the same prefix.
* @hide
*/
public static boolean checkStaticAddressConfiguration(
@NonNull final LinkAddress localIPv4Address,
@NonNull final LinkAddress clientAddress) {
return localIPv4Address.getPrefixLength() == clientAddress.getPrefixLength()
&& localIPv4Address.isIpv4() && clientAddress.isIpv4()
&& new IpPrefix(localIPv4Address.toString()).equals(
new IpPrefix(clientAddress.toString()));
}
/** /**
* Get a TetheringRequestParcel from the configuration * Get a TetheringRequestParcel from the configuration
* @hide * @hide

View File

@@ -18,10 +18,12 @@ package android.net.dhcp;
import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
import android.annotation.NonNull;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.util.ArraySet; import android.util.ArraySet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -160,6 +162,17 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel {
return this; return this;
} }
/**
* Set the client address to tell DHCP server only offer this address.
* The client's prefix length is the same as server's.
*
* <p>If not set, the default value is null.
*/
public DhcpServingParamsParcelExt setSingleClientAddr(@Nullable Inet4Address clientAddr) {
this.clientAddr = clientAddr == null ? 0 : inet4AddressToIntHTH(clientAddr);
return this;
}
private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) { private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) {
int[] res = new int[addrs.size()]; int[] res = new int[addrs.size()];
int i = 0; int i = 0;

View File

@@ -18,6 +18,7 @@ package android.net.ip;
import static android.net.InetAddresses.parseNumericAddress; import static android.net.InetAddresses.parseNumericAddress;
import static android.net.RouteInfo.RTN_UNICAST; import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
import static android.net.util.NetworkConstants.FF; import static android.net.util.NetworkConstants.FF;
@@ -492,17 +493,24 @@ public class IpServer extends StateMachine {
} }
} }
private boolean startDhcp(Inet4Address addr, int prefixLen) { private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) {
if (mUsingLegacyDhcp) { if (mUsingLegacyDhcp) {
return true; return true;
} }
final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress();
final int prefixLen = serverLinkAddr.getPrefixLength();
final Inet4Address clientAddr = clientLinkAddr == null ? null :
(Inet4Address) clientLinkAddr.getAddress();
final DhcpServingParamsParcel params; final DhcpServingParamsParcel params;
params = new DhcpServingParamsParcelExt() params = new DhcpServingParamsParcelExt()
.setDefaultRouters(addr) .setDefaultRouters(addr)
.setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
.setDnsServers(addr) .setDnsServers(addr)
.setServerAddr(new LinkAddress(addr, prefixLen)) .setServerAddr(serverLinkAddr)
.setMetered(true); .setMetered(true)
.setSingleClientAddr(clientAddr);
// TODO: also advertise link MTU // TODO: also advertise link MTU
mDhcpServerStartIndex++; mDhcpServerStartIndex++;
@@ -537,9 +545,10 @@ public class IpServer extends StateMachine {
} }
} }
private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) { private boolean configureDhcp(boolean enable, final LinkAddress serverAddr,
final LinkAddress clientAddr) {
if (enable) { if (enable) {
return startDhcp(addr, prefixLen); return startDhcp(serverAddr, clientAddr);
} else { } else {
stopDhcp(); stopDhcp();
return true; return true;
@@ -587,7 +596,7 @@ public class IpServer extends StateMachine {
// code that calls into NetworkManagementService directly. // code that calls into NetworkManagementService directly.
srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR);
mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); return configureDhcp(enabled, mIpv4Address, null /* clientAddress */);
} }
mIpv4Address = new LinkAddress(srvAddr, prefixLen); mIpv4Address = new LinkAddress(srvAddr, prefixLen);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@@ -624,7 +633,7 @@ public class IpServer extends StateMachine {
mLinkProperties.removeRoute(route); mLinkProperties.removeRoute(route);
} }
return configureDhcp(enabled, srvAddr, prefixLen); return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
} }
private String getRandomWifiIPv4Address() { private String getRandomWifiIPv4Address() {
@@ -945,7 +954,14 @@ public class IpServer extends StateMachine {
} }
private void maybeConfigureStaticIp(final TetheringRequestParcel request) { private void maybeConfigureStaticIp(final TetheringRequestParcel request) {
if (request == null) return; // Ignore static address configuration if they are invalid or null. In theory, static
// addresses should not be invalid here because TetheringManager do not allow caller to
// specify invalid static address configuration.
if (request == null || request.localIPv4Address == null
|| request.staticClientAddress == null || !checkStaticAddressConfiguration(
request.localIPv4Address, request.staticClientAddress)) {
return;
}
mStaticIpv4ServerAddr = request.localIPv4Address; mStaticIpv4ServerAddr = request.localIPv4Address;
mStaticIpv4ClientAddr = request.staticClientAddress; mStaticIpv4ClientAddr = request.staticClientAddress;

View File

@@ -42,7 +42,9 @@ import java.util.stream.IntStream;
@SmallTest @SmallTest
public class DhcpServingParamsParcelExtTest { public class DhcpServingParamsParcelExtTest {
private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123"); private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123");
private static final Inet4Address TEST_CLIENT_ADDRESS = inet4Addr("192.168.0.42");
private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b; private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b;
private static final int TEST_CLIENT_ADDRESS_PARCELED = 0xc0a8002a;
private static final int TEST_PREFIX_LENGTH = 17; private static final int TEST_PREFIX_LENGTH = 17;
private static final int TEST_LEASE_TIME_SECS = 120; private static final int TEST_LEASE_TIME_SECS = 120;
private static final int TEST_MTU = 1000; private static final int TEST_MTU = 1000;
@@ -105,6 +107,12 @@ public class DhcpServingParamsParcelExtTest {
assertFalse(mParcel.metered); assertFalse(mParcel.metered);
} }
@Test
public void testSetClientAddr() {
mParcel.setSingleClientAddr(TEST_CLIENT_ADDRESS);
assertEquals(TEST_CLIENT_ADDRESS_PARCELED, mParcel.clientAddr);
}
private static Inet4Address inet4Addr(String addr) { private static Inet4Address inet4Addr(String addr) {
return (Inet4Address) parseNumericAddress(addr); return (Inet4Address) parseNumericAddress(addr);
} }

View File

@@ -38,6 +38,7 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -1651,10 +1652,13 @@ public class TetheringTest {
} }
@Test @Test
public void testRequestStaticServerIp() throws Exception { public void testRequestStaticIp() throws Exception {
final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24"); final LinkAddress serverLinkAddr = new LinkAddress("192.168.0.123/24");
final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24"); final LinkAddress clientLinkAddr = new LinkAddress("192.168.0.42/24");
final String serverAddr = "192.168.20.1"; final String serverAddr = "192.168.0.123";
final int clientAddrParceled = 0xc0a8002a;
final ArgumentCaptor<DhcpServingParamsParcel> dhcpParamsCaptor =
ArgumentCaptor.forClass(DhcpServingParamsParcel.class);
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
serverLinkAddr, clientLinkAddr), null); serverLinkAddr, clientLinkAddr), null);
mLooper.dispatchAll(); mLooper.dispatchAll();
@@ -1663,8 +1667,12 @@ public class TetheringTest {
sendUsbBroadcast(true, true, true, TETHERING_USB); sendUsbBroadcast(true, true, true, TETHERING_USB);
mLooper.dispatchAll(); mLooper.dispatchAll();
verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr))); verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr)));
verify(mIpServerDependencies, times(1)).makeDhcpServer(any(), dhcpParamsCaptor.capture(),
// TODO: test static client address. any());
final DhcpServingParamsParcel params = dhcpParamsCaptor.getValue();
assertEquals(serverAddr, intToInet4AddressHTH(params.serverAddr).getHostAddress());
assertEquals(24, params.serverAddrPrefixLength);
assertEquals(clientAddrParceled, params.clientAddr);
} }
// TODO: Test that a request for hotspot mode doesn't interfere with an // TODO: Test that a request for hotspot mode doesn't interfere with an