Move DhcpServer to NetworkStack app
Test: atest FrameworksNetTests && atest NetworkStackTests
Bug: b/112869080
Change-Id: I96c40e63e9ceb37b67705bdd4d120307e114715b
diff --git a/services/net/Android.bp b/services/net/Android.bp
index e0ae68f..ae697b7 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -2,3 +2,19 @@
name: "services.net",
srcs: ["java/**/*.java"],
}
+
+// TODO: move to networking module with DhcpClient and remove lib
+java_library {
+ name: "dhcp-packet-lib",
+ srcs: [
+ "java/android/net/dhcp/*Packet.java",
+ ]
+}
+
+// TODO: move to networking module with IpNeighborMonitor/ConnectivityPacketTracker and remove lib
+java_library {
+ name: "frameworks-net-shared-utils",
+ srcs: [
+ "java/android/net/util/FdEventsReader.java",
+ ]
+}
\ No newline at end of file
diff --git a/services/net/java/android/net/dhcp/DhcpLease.java b/services/net/java/android/net/dhcp/DhcpLease.java
deleted file mode 100644
index 6849cfa..0000000
--- a/services/net/java/android/net/dhcp/DhcpLease.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.MacAddress;
-import android.os.SystemClock;
-import android.text.TextUtils;
-
-import com.android.internal.util.HexDump;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * An IPv4 address assignment done through DHCPv4.
- * @hide
- */
-public class DhcpLease {
- public static final long EXPIRATION_NEVER = Long.MAX_VALUE;
- public static final String HOSTNAME_NONE = null;
-
- @Nullable
- private final byte[] mClientId;
- @NonNull
- private final MacAddress mHwAddr;
- @NonNull
- private final Inet4Address mNetAddr;
- /**
- * Expiration time for the lease, to compare with {@link SystemClock#elapsedRealtime()}.
- */
- private final long mExpTime;
- @Nullable
- private final String mHostname;
-
- public DhcpLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
- @NonNull Inet4Address netAddr, long expTime, @Nullable String hostname) {
- mClientId = (clientId == null ? null : Arrays.copyOf(clientId, clientId.length));
- mHwAddr = hwAddr;
- mNetAddr = netAddr;
- mExpTime = expTime;
- mHostname = hostname;
- }
-
- /**
- * Get the clientId associated with this lease, if any.
- *
- * <p>If the lease is not associated to a clientId, this returns null.
- */
- @Nullable
- public byte[] getClientId() {
- if (mClientId == null) {
- return null;
- }
- return Arrays.copyOf(mClientId, mClientId.length);
- }
-
- @NonNull
- public MacAddress getHwAddr() {
- return mHwAddr;
- }
-
- @Nullable
- public String getHostname() {
- return mHostname;
- }
-
- @NonNull
- public Inet4Address getNetAddr() {
- return mNetAddr;
- }
-
- public long getExpTime() {
- return mExpTime;
- }
-
- /**
- * Push back the expiration time of this lease. If the provided time is sooner than the original
- * expiration time, the lease time will not be updated.
- *
- * <p>The lease hostname is updated with the provided one if set.
- * @return A {@link DhcpLease} with expiration time set to max(expTime, currentExpTime)
- */
- public DhcpLease renewedLease(long expTime, @Nullable String hostname) {
- return new DhcpLease(mClientId, mHwAddr, mNetAddr, Math.max(expTime, mExpTime),
- (hostname == null ? mHostname : hostname));
- }
-
- /**
- * Determine whether this lease matches a client with the specified parameters.
- * @param clientId clientId of the client if any, or null otherwise.
- * @param hwAddr Hardware address of the client.
- */
- public boolean matchesClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
- if (mClientId != null) {
- return Arrays.equals(mClientId, clientId);
- } else {
- return clientId == null && mHwAddr.equals(hwAddr);
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof DhcpLease)) {
- return false;
- }
- final DhcpLease other = (DhcpLease) obj;
- return Arrays.equals(mClientId, other.mClientId)
- && mHwAddr.equals(other.mHwAddr)
- && mNetAddr.equals(other.mNetAddr)
- && mExpTime == other.mExpTime
- && TextUtils.equals(mHostname, other.mHostname);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mClientId, mHwAddr, mNetAddr, mHostname, mExpTime);
- }
-
- static String clientIdToString(byte[] bytes) {
- if (bytes == null) {
- return "null";
- }
- return HexDump.toHexString(bytes);
- }
-
- static String inet4AddrToString(@Nullable Inet4Address addr) {
- return (addr == null) ? "null" : addr.getHostAddress();
- }
-
- @Override
- public String toString() {
- return String.format("clientId: %s, hwAddr: %s, netAddr: %s, expTime: %d, hostname: %s",
- clientIdToString(mClientId), mHwAddr.toString(), inet4AddrToString(mNetAddr),
- mExpTime, mHostname);
- }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java
deleted file mode 100644
index b3d0512..0000000
--- a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
-import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER;
-import static android.net.dhcp.DhcpLease.inet4AddrToString;
-import static android.net.util.NetworkConstants.IPV4_ADDR_BITS;
-
-import static java.lang.Math.min;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.MacAddress;
-import android.net.dhcp.DhcpServer.Clock;
-import android.net.util.SharedLog;
-import android.util.ArrayMap;
-
-import java.net.Inet4Address;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * A repository managing IPv4 address assignments through DHCPv4.
- *
- * <p>This class is not thread-safe. All public methods should be called on a common thread or
- * use some synchronization mechanism.
- *
- * <p>Methods are optimized for a small number of allocated leases, assuming that most of the time
- * only 2~10 addresses will be allocated, which is the common case. Managing a large number of
- * addresses is supported but will be slower: some operations have complexity in O(num_leases).
- * @hide
- */
-class DhcpLeaseRepository {
- public static final byte[] CLIENTID_UNSPEC = null;
- public static final Inet4Address INETADDR_UNSPEC = null;
-
- @NonNull
- private final SharedLog mLog;
- @NonNull
- private final Clock mClock;
-
- @NonNull
- private IpPrefix mPrefix;
- @NonNull
- private Set<Inet4Address> mReservedAddrs;
- private int mSubnetAddr;
- private int mSubnetMask;
- private int mNumAddresses;
- private long mLeaseTimeMs;
-
- /**
- * Next timestamp when committed or declined leases should be checked for expired ones. This
- * will always be lower than or equal to the time for the first lease to expire: it's OK not to
- * update this when removing entries, but it must always be updated when adding/updating.
- */
- private long mNextExpirationCheck = EXPIRATION_NEVER;
-
- static class DhcpLeaseException extends Exception {
- DhcpLeaseException(String message) {
- super(message);
- }
- }
-
- static class OutOfAddressesException extends DhcpLeaseException {
- OutOfAddressesException(String message) {
- super(message);
- }
- }
-
- static class InvalidAddressException extends DhcpLeaseException {
- InvalidAddressException(String message) {
- super(message);
- }
- }
-
- static class InvalidSubnetException extends DhcpLeaseException {
- InvalidSubnetException(String message) {
- super(message);
- }
- }
-
- /**
- * Leases by IP address
- */
- private final ArrayMap<Inet4Address, DhcpLease> mCommittedLeases = new ArrayMap<>();
-
- /**
- * Map address -> expiration timestamp in ms. Addresses are guaranteed to be valid as defined
- * by {@link #isValidAddress(Inet4Address)}, but are not necessarily otherwise available for
- * assignment.
- */
- private final LinkedHashMap<Inet4Address, Long> mDeclinedAddrs = new LinkedHashMap<>();
-
- DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
- long leaseTimeMs, @NonNull SharedLog log, @NonNull Clock clock) {
- updateParams(prefix, reservedAddrs, leaseTimeMs);
- mLog = log;
- mClock = clock;
- }
-
- public void updateParams(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
- long leaseTimeMs) {
- mPrefix = prefix;
- mReservedAddrs = Collections.unmodifiableSet(new HashSet<>(reservedAddrs));
- mSubnetMask = prefixLengthToV4NetmaskIntHTH(prefix.getPrefixLength());
- mSubnetAddr = inet4AddressToIntHTH((Inet4Address) prefix.getAddress()) & mSubnetMask;
- mNumAddresses = 1 << (IPV4_ADDR_BITS - prefix.getPrefixLength());
- mLeaseTimeMs = leaseTimeMs;
-
- cleanMap(mCommittedLeases);
- cleanMap(mDeclinedAddrs);
- }
-
- /**
- * From a map keyed by {@link Inet4Address}, remove entries where the key is invalid (as
- * specified by {@link #isValidAddress(Inet4Address)}), or is a reserved address.
- */
- private <T> void cleanMap(Map<Inet4Address, T> map) {
- final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- final Inet4Address addr = it.next().getKey();
- if (!isValidAddress(addr) || mReservedAddrs.contains(addr)) {
- it.remove();
- }
- }
- }
-
- /**
- * Get a DHCP offer, to reply to a DHCPDISCOVER. Follows RFC2131 #4.3.1.
- *
- * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
- * @param relayAddr Internet address of the relay (giaddr), can be {@link Inet4Address#ANY}
- * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
- * @param hostname Client-provided hostname, or {@link DhcpLease#HOSTNAME_NONE}
- * @throws OutOfAddressesException The server does not have any available address
- * @throws InvalidSubnetException The lease was requested from an unsupported subnet
- */
- @NonNull
- public DhcpLease getOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
- @NonNull Inet4Address relayAddr, @Nullable Inet4Address reqAddr,
- @Nullable String hostname) throws OutOfAddressesException, InvalidSubnetException {
- final long currentTime = mClock.elapsedRealtime();
- final long expTime = currentTime + mLeaseTimeMs;
-
- removeExpiredLeases(currentTime);
- checkValidRelayAddr(relayAddr);
-
- final DhcpLease currentLease = findByClient(clientId, hwAddr);
- final DhcpLease newLease;
- if (currentLease != null) {
- newLease = currentLease.renewedLease(expTime, hostname);
- mLog.log("Offering extended lease " + newLease);
- // Do not update lease time in the map: the offer is not committed yet.
- } else if (reqAddr != null && isValidAddress(reqAddr) && isAvailable(reqAddr)) {
- newLease = new DhcpLease(clientId, hwAddr, reqAddr, expTime, hostname);
- mLog.log("Offering requested lease " + newLease);
- } else {
- newLease = makeNewOffer(clientId, hwAddr, expTime, hostname);
- mLog.log("Offering new generated lease " + newLease);
- }
- return newLease;
- }
-
- private void checkValidRelayAddr(@Nullable Inet4Address relayAddr)
- throws InvalidSubnetException {
- // As per #4.3.1, addresses are assigned based on the relay address if present. This
- // implementation only assigns addresses if the relayAddr is inside our configured subnet.
- // This also applies when the client requested a specific address for consistency between
- // requests, and with older behavior.
- if (isIpAddrOutsidePrefix(mPrefix, relayAddr)) {
- throw new InvalidSubnetException("Lease requested by relay from outside of subnet");
- }
- }
-
- private static boolean isIpAddrOutsidePrefix(@NonNull IpPrefix prefix,
- @Nullable Inet4Address addr) {
- return addr != null && !addr.equals(Inet4Address.ANY) && !prefix.contains(addr);
- }
-
- @Nullable
- private DhcpLease findByClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
- for (DhcpLease lease : mCommittedLeases.values()) {
- if (lease.matchesClient(clientId, hwAddr)) {
- return lease;
- }
- }
-
- // Note this differs from dnsmasq behavior, which would match by hwAddr if clientId was
- // given but no lease keyed on clientId matched. This would prevent one interface from
- // obtaining multiple leases with different clientId.
- return null;
- }
-
- /**
- * Make a lease conformant to a client DHCPREQUEST or renew the client's existing lease,
- * commit it to the repository and return it.
- *
- * <p>This method always succeeds and commits the lease if it does not throw, and has no side
- * effects if it throws.
- *
- * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
- * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
- * @param sidSet Whether the server identifier was set in the request
- * @return The newly created or renewed lease
- * @throws InvalidAddressException The client provided an address that conflicts with its
- * current configuration, or other committed/reserved leases.
- */
- @NonNull
- public DhcpLease requestLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
- @NonNull Inet4Address clientAddr, @NonNull Inet4Address relayAddr,
- @Nullable Inet4Address reqAddr, boolean sidSet, @Nullable String hostname)
- throws InvalidAddressException, InvalidSubnetException {
- final long currentTime = mClock.elapsedRealtime();
- removeExpiredLeases(currentTime);
- checkValidRelayAddr(relayAddr);
- final DhcpLease assignedLease = findByClient(clientId, hwAddr);
-
- final Inet4Address leaseAddr = reqAddr != null ? reqAddr : clientAddr;
- if (assignedLease != null) {
- if (sidSet && reqAddr != null) {
- // Client in SELECTING state; remove any current lease before creating a new one.
- mCommittedLeases.remove(assignedLease.getNetAddr());
- } else if (!assignedLease.getNetAddr().equals(leaseAddr)) {
- // reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr.
- // reqAddr set with sid not set (INIT-REBOOT): client verifying configuration.
- // In both cases, throw if clientAddr or reqAddr does not match the known lease.
- throw new InvalidAddressException("Incorrect address for client in "
- + (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING"));
- }
- }
-
- // In the init-reboot case, RFC2131 #4.3.2 says that the server must not reply if
- // assignedLease == null, but dnsmasq will let the client use the requested address if
- // available, when configured with --dhcp-authoritative. This is preferable to avoid issues
- // if the server lost the lease DB: the client would not get a reply because the server
- // does not know their lease.
- // Similarly in RENEWING/REBINDING state, create a lease when possible if the
- // client-provided lease is unknown.
- final DhcpLease lease =
- checkClientAndMakeLease(clientId, hwAddr, leaseAddr, hostname, currentTime);
- mLog.logf("DHCPREQUEST assignedLease %s, reqAddr=%s, sidSet=%s: created/renewed lease %s",
- assignedLease, inet4AddrToString(reqAddr), sidSet, lease);
- return lease;
- }
-
- /**
- * Check that the client can request the specified address, make or renew the lease if yes, and
- * commit it.
- *
- * <p>This method always succeeds and returns the lease if it does not throw, and has no
- * side-effect if it throws.
- *
- * @return The newly created or renewed, committed lease
- * @throws InvalidAddressException The client provided an address that conflicts with its
- * current configuration, or other committed/reserved leases.
- */
- private DhcpLease checkClientAndMakeLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
- @NonNull Inet4Address addr, @Nullable String hostname, long currentTime)
- throws InvalidAddressException {
- final long expTime = currentTime + mLeaseTimeMs;
- final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
- if (currentLease != null && !currentLease.matchesClient(clientId, hwAddr)) {
- throw new InvalidAddressException("Address in use");
- }
-
- final DhcpLease lease;
- if (currentLease == null) {
- if (isValidAddress(addr) && !mReservedAddrs.contains(addr)) {
- lease = new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
- } else {
- throw new InvalidAddressException("Lease not found and address unavailable");
- }
- } else {
- lease = currentLease.renewedLease(expTime, hostname);
- }
- commitLease(lease);
- return lease;
- }
-
- private void commitLease(@NonNull DhcpLease lease) {
- mCommittedLeases.put(lease.getNetAddr(), lease);
- maybeUpdateEarliestExpiration(lease.getExpTime());
- }
-
- /**
- * Delete a committed lease from the repository.
- *
- * @return true if a lease matching parameters was found.
- */
- public boolean releaseLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
- @NonNull Inet4Address addr) {
- final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
- if (currentLease == null) {
- mLog.w("Could not release unknown lease for " + inet4AddrToString(addr));
- return false;
- }
- if (currentLease.matchesClient(clientId, hwAddr)) {
- mCommittedLeases.remove(addr);
- mLog.log("Released lease " + currentLease);
- return true;
- }
- mLog.w(String.format("Not releasing lease %s: does not match client (cid %s, hwAddr %s)",
- currentLease, DhcpLease.clientIdToString(clientId), hwAddr));
- return false;
- }
-
- public void markLeaseDeclined(@NonNull Inet4Address addr) {
- if (mDeclinedAddrs.containsKey(addr) || !isValidAddress(addr)) {
- mLog.logf("Not marking %s as declined: already declined or not assignable",
- inet4AddrToString(addr));
- return;
- }
- final long expTime = mClock.elapsedRealtime() + mLeaseTimeMs;
- mDeclinedAddrs.put(addr, expTime);
- mLog.logf("Marked %s as declined expiring %d", inet4AddrToString(addr), expTime);
- maybeUpdateEarliestExpiration(expTime);
- }
-
- /**
- * Get the list of currently valid committed leases in the repository.
- */
- @NonNull
- public List<DhcpLease> getCommittedLeases() {
- removeExpiredLeases(mClock.elapsedRealtime());
- return new ArrayList<>(mCommittedLeases.values());
- }
-
- /**
- * Get the set of addresses that have been marked as declined in the repository.
- */
- @NonNull
- public Set<Inet4Address> getDeclinedAddresses() {
- removeExpiredLeases(mClock.elapsedRealtime());
- return new HashSet<>(mDeclinedAddrs.keySet());
- }
-
- /**
- * Given the expiration time of a new committed lease or declined address, update
- * {@link #mNextExpirationCheck} so it stays lower than or equal to the time for the first lease
- * to expire.
- */
- private void maybeUpdateEarliestExpiration(long expTime) {
- if (expTime < mNextExpirationCheck) {
- mNextExpirationCheck = expTime;
- }
- }
-
- /**
- * Remove expired entries from a map keyed by {@link Inet4Address}.
- *
- * @param tag Type of lease in the map, for logging
- * @param getExpTime Functor returning the expiration time for an object in the map.
- * Must not return null.
- * @return The lowest expiration time among entries remaining in the map
- */
- private <T> long removeExpired(long currentTime, @NonNull Map<Inet4Address, T> map,
- @NonNull String tag, @NonNull Function<T, Long> getExpTime) {
- final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
- long firstExpiration = EXPIRATION_NEVER;
- while (it.hasNext()) {
- final Entry<Inet4Address, T> lease = it.next();
- final long expTime = getExpTime.apply(lease.getValue());
- if (expTime <= currentTime) {
- mLog.logf("Removing expired %s lease for %s (expTime=%s, currentTime=%s)",
- tag, lease.getKey(), expTime, currentTime);
- it.remove();
- } else {
- firstExpiration = min(firstExpiration, expTime);
- }
- }
- return firstExpiration;
- }
-
- /**
- * Go through committed and declined leases and remove the expired ones.
- */
- private void removeExpiredLeases(long currentTime) {
- if (currentTime < mNextExpirationCheck) {
- return;
- }
-
- final long commExp = removeExpired(
- currentTime, mCommittedLeases, "committed", DhcpLease::getExpTime);
- final long declExp = removeExpired(
- currentTime, mDeclinedAddrs, "declined", Function.identity());
-
- mNextExpirationCheck = min(commExp, declExp);
- }
-
- private boolean isAvailable(@NonNull Inet4Address addr) {
- return !mReservedAddrs.contains(addr) && !mCommittedLeases.containsKey(addr);
- }
-
- /**
- * Get the 0-based index of an address in the subnet.
- *
- * <p>Given ordering of addresses 5.6.7.8 < 5.6.7.9 < 5.6.8.0, the index on a subnet is defined
- * so that the first address is 0, the second 1, etc. For example on a /16, 192.168.0.0 -> 0,
- * 192.168.0.1 -> 1, 192.168.1.0 -> 256
- *
- */
- private int getAddrIndex(int addr) {
- return addr & ~mSubnetMask;
- }
-
- private int getAddrByIndex(int index) {
- return mSubnetAddr | index;
- }
-
- /**
- * Get a valid address starting from the supplied one.
- *
- * <p>This only checks that the address is numerically valid for assignment, not whether it is
- * already in use. The return value is always inside the configured prefix, even if the supplied
- * address is not.
- *
- * <p>If the provided address is valid, it is returned as-is. Otherwise, the next valid
- * address (with the ordering in {@link #getAddrIndex(int)}) is returned.
- */
- private int getValidAddress(int addr) {
- final int lastByteMask = 0xff;
- int addrIndex = getAddrIndex(addr); // 0-based index of the address in the subnet
-
- // Some OSes do not handle addresses in .255 or .0 correctly: avoid those.
- final int lastByte = getAddrByIndex(addrIndex) & lastByteMask;
- if (lastByte == lastByteMask) {
- // Avoid .255 address, and .0 address that follows
- addrIndex = (addrIndex + 2) % mNumAddresses;
- } else if (lastByte == 0) {
- // Avoid .0 address
- addrIndex = (addrIndex + 1) % mNumAddresses;
- }
-
- // Do not use first or last address of range
- if (addrIndex == 0 || addrIndex == mNumAddresses - 1) {
- // Always valid and not end of range since prefixLength is at most 30 in serving params
- addrIndex = 1;
- }
- return getAddrByIndex(addrIndex);
- }
-
- /**
- * Returns whether the address is in the configured subnet and part of the assignable range.
- */
- private boolean isValidAddress(Inet4Address addr) {
- final int intAddr = inet4AddressToIntHTH(addr);
- return getValidAddress(intAddr) == intAddr;
- }
-
- private int getNextAddress(int addr) {
- final int addrIndex = getAddrIndex(addr);
- final int nextAddress = getAddrByIndex((addrIndex + 1) % mNumAddresses);
- return getValidAddress(nextAddress);
- }
-
- /**
- * Calculate a first candidate address for a client by hashing the hardware address.
- *
- * <p>This will be a valid address as checked by {@link #getValidAddress(int)}, but may be
- * in use.
- *
- * @return An IPv4 address encoded as 32-bit int
- */
- private int getFirstClientAddress(MacAddress hwAddr) {
- // This follows dnsmasq behavior. Advantages are: clients will often get the same
- // offers for different DISCOVER even if the lease was not yet accepted or has expired,
- // and address generation will generally not need to loop through many allocated addresses
- // until it finds a free one.
- int hash = 0;
- for (byte b : hwAddr.toByteArray()) {
- hash += b + (b << 8) + (b << 16);
- }
- // This implementation will not always result in the same IPs as dnsmasq would give out in
- // Android <= P, because it includes invalid and reserved addresses in mNumAddresses while
- // the configured ranges for dnsmasq did not.
- final int addrIndex = hash % mNumAddresses;
- return getValidAddress(getAddrByIndex(addrIndex));
- }
-
- /**
- * Create a lease that can be offered to respond to a client DISCOVER.
- *
- * <p>This method always succeeds and returns the lease if it does not throw. If no non-declined
- * address is available, it will try to offer the oldest declined address if valid.
- *
- * @throws OutOfAddressesException The server has no address left to offer
- */
- private DhcpLease makeNewOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
- long expTime, @Nullable String hostname) throws OutOfAddressesException {
- int intAddr = getFirstClientAddress(hwAddr);
- // Loop until a free address is found, or there are no more addresses.
- // There is slightly less than this many usable addresses, but some extra looping is OK
- for (int i = 0; i < mNumAddresses; i++) {
- final Inet4Address addr = intToInet4AddressHTH(intAddr);
- if (isAvailable(addr) && !mDeclinedAddrs.containsKey(addr)) {
- return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
- }
- intAddr = getNextAddress(intAddr);
- }
-
- // Try freeing DECLINEd addresses if out of addresses.
- final Iterator<Inet4Address> it = mDeclinedAddrs.keySet().iterator();
- while (it.hasNext()) {
- final Inet4Address addr = it.next();
- it.remove();
- mLog.logf("Out of addresses in address pool: dropped declined addr %s",
- inet4AddrToString(addr));
- // isValidAddress() is always verified for entries in mDeclinedAddrs.
- // However declined addresses may have been requested (typically by the machine that was
- // already using the address) after being declined.
- if (isAvailable(addr)) {
- return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
- }
- }
-
- throw new OutOfAddressesException("No address available for offer");
- }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 6ba7d94..ce8b7e7 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -1,8 +1,5 @@
package android.net.dhcp;
-import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
-import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
-
import android.annotation.Nullable;
import android.net.DhcpResults;
import android.net.LinkAddress;
@@ -37,6 +34,9 @@
public abstract class DhcpPacket {
protected static final String TAG = "DhcpPacket";
+ // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack.
+ private static final int IPV4_MIN_MTU = 68;
+
// dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
// CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
// DHCP client timeout.
diff --git a/services/net/java/android/net/dhcp/DhcpPacketListener.java b/services/net/java/android/net/dhcp/DhcpPacketListener.java
deleted file mode 100644
index dce8b61..0000000
--- a/services/net/java/android/net/dhcp/DhcpPacketListener.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.util.FdEventsReader;
-import android.os.Handler;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-
-/**
- * A {@link FdEventsReader} to receive and parse {@link DhcpPacket}.
- * @hide
- */
-abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> {
- static final class Payload {
- protected final byte[] mBytes = new byte[DhcpPacket.MAX_LENGTH];
- protected Inet4Address mSrcAddr;
- protected int mSrcPort;
- }
-
- DhcpPacketListener(@NonNull Handler handler) {
- super(handler, new Payload());
- }
-
- @Override
- protected int recvBufSize(@NonNull Payload buffer) {
- return buffer.mBytes.length;
- }
-
- @Override
- protected final void handlePacket(@NonNull Payload recvbuf, int length) {
- if (recvbuf.mSrcAddr == null) {
- return;
- }
-
- try {
- final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.mBytes, length,
- DhcpPacket.ENCAP_BOOTP);
- onReceive(packet, recvbuf.mSrcAddr, recvbuf.mSrcPort);
- } catch (DhcpPacket.ParseException e) {
- logParseError(recvbuf.mBytes, length, e);
- }
- }
-
- @Override
- protected int readPacket(@NonNull FileDescriptor fd, @NonNull Payload packetBuffer)
- throws Exception {
- final InetSocketAddress addr = new InetSocketAddress();
- final int read = Os.recvfrom(
- fd, packetBuffer.mBytes, 0, packetBuffer.mBytes.length, 0 /* flags */, addr);
-
- // Buffers with null srcAddr will be dropped in handlePacket()
- packetBuffer.mSrcAddr = inet4AddrOrNull(addr);
- packetBuffer.mSrcPort = addr.getPort();
- return read;
- }
-
- @Nullable
- private static Inet4Address inet4AddrOrNull(@NonNull InetSocketAddress addr) {
- return addr.getAddress() instanceof Inet4Address
- ? (Inet4Address) addr.getAddress()
- : null;
- }
-
- protected abstract void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
- int srcPort);
- protected abstract void logParseError(@NonNull byte[] packet, int length,
- @NonNull DhcpPacket.ParseException e);
-}
diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java
deleted file mode 100644
index 641bba2..0000000
--- a/services/net/java/android/net/dhcp/DhcpServer.java
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
-import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
-import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
-import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_BINDTODEVICE;
-import static android.system.OsConstants.SO_BROADCAST;
-import static android.system.OsConstants.SO_REUSEADDR;
-
-import static java.lang.Integer.toUnsignedLong;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.MacAddress;
-import android.net.NetworkUtils;
-import android.net.TrafficStats;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.HexDump;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-
-/**
- * A DHCPv4 server.
- *
- * <p>This server listens for and responds to packets on a single interface. It considers itself
- * authoritative for all leases on the subnet, which means that DHCP requests for unknown leases of
- * unknown hosts receive a reply instead of being ignored.
- *
- * <p>The server is single-threaded (including send/receive operations): all internal operations are
- * done on the provided {@link Looper}. Public methods are thread-safe and will schedule operations
- * on the looper asynchronously.
- * @hide
- */
-public class DhcpServer {
- private static final String REPO_TAG = "Repository";
-
- // Lease time to transmit to client instead of a negative time in case a lease expired before
- // the server could send it (if the server process is suspended for example).
- private static final int EXPIRED_FALLBACK_LEASE_TIME_SECS = 120;
-
- private static final int CMD_START_DHCP_SERVER = 1;
- private static final int CMD_STOP_DHCP_SERVER = 2;
- private static final int CMD_UPDATE_PARAMS = 3;
-
- @NonNull
- private final ServerHandler mHandler;
- @NonNull
- private final String mIfName;
- @NonNull
- private final DhcpLeaseRepository mLeaseRepo;
- @NonNull
- private final SharedLog mLog;
- @NonNull
- private final Dependencies mDeps;
- @NonNull
- private final Clock mClock;
- @NonNull
- private final DhcpPacketListener mPacketListener;
-
- @Nullable
- private FileDescriptor mSocket;
- @NonNull
- private DhcpServingParams mServingParams;
-
- /**
- * Clock to be used by DhcpServer to track time for lease expiration.
- *
- * <p>The clock should track time as may be measured by clients obtaining a lease. It does not
- * need to be monotonous across restarts of the server as long as leases are cleared when the
- * server is stopped.
- */
- public static class Clock {
- /**
- * @see SystemClock#elapsedRealtime()
- */
- public long elapsedRealtime() {
- return SystemClock.elapsedRealtime();
- }
- }
-
- /**
- * Dependencies for the DhcpServer. Useful to be mocked in tests.
- */
- public interface Dependencies {
- /**
- * Send a packet to the specified datagram socket.
- *
- * @param fd File descriptor of the socket.
- * @param buffer Data to be sent.
- * @param dst Destination address of the packet.
- */
- void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
- @NonNull InetAddress dst) throws ErrnoException, IOException;
-
- /**
- * Create a DhcpLeaseRepository for the server.
- * @param servingParams Parameters used to serve DHCP requests.
- * @param log Log to be used by the repository.
- * @param clock Clock that the repository must use to track time.
- */
- DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
- @NonNull SharedLog log, @NonNull Clock clock);
-
- /**
- * Create a packet listener that will send packets to be processed.
- */
- DhcpPacketListener makePacketListener();
-
- /**
- * Create a clock that the server will use to track time.
- */
- Clock makeClock();
-
- /**
- * Add an entry to the ARP cache table.
- * @param fd Datagram socket file descriptor that must use the new entry.
- */
- void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
- @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException;
- }
-
- private class DependenciesImpl implements Dependencies {
- @Override
- public void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
- @NonNull InetAddress dst) throws ErrnoException, IOException {
- Os.sendto(fd, buffer, 0, dst, DhcpPacket.DHCP_CLIENT);
- }
-
- @Override
- public DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
- @NonNull SharedLog log, @NonNull Clock clock) {
- return new DhcpLeaseRepository(
- DhcpServingParams.makeIpPrefix(servingParams.serverAddr),
- servingParams.excludedAddrs,
- servingParams.dhcpLeaseTimeSecs * 1000, log.forSubComponent(REPO_TAG), clock);
- }
-
- @Override
- public DhcpPacketListener makePacketListener() {
- return new PacketListener();
- }
-
- @Override
- public Clock makeClock() {
- return new Clock();
- }
-
- @Override
- public void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
- @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException {
- NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
- }
- }
-
- private static class MalformedPacketException extends Exception {
- MalformedPacketException(String message, Throwable t) {
- super(message, t);
- }
- }
-
- public DhcpServer(@NonNull Looper looper, @NonNull String ifName,
- @NonNull DhcpServingParams params, @NonNull SharedLog log) {
- this(looper, ifName, params, log, null);
- }
-
- @VisibleForTesting
- DhcpServer(@NonNull Looper looper, @NonNull String ifName,
- @NonNull DhcpServingParams params, @NonNull SharedLog log,
- @Nullable Dependencies deps) {
- if (deps == null) {
- deps = new DependenciesImpl();
- }
- mHandler = new ServerHandler(looper);
- mIfName = ifName;
- mServingParams = params;
- mLog = log;
- mDeps = deps;
- mClock = deps.makeClock();
- mPacketListener = deps.makePacketListener();
- mLeaseRepo = deps.makeLeaseRepository(mServingParams, mLog, mClock);
- }
-
- /**
- * Start listening for and responding to packets.
- */
- public void start() {
- mHandler.sendEmptyMessage(CMD_START_DHCP_SERVER);
- }
-
- /**
- * Update serving parameters. All subsequently received requests will be handled with the new
- * parameters, and current leases that are incompatible with the new parameters are dropped.
- */
- public void updateParams(@NonNull DhcpServingParams params) {
- sendMessage(CMD_UPDATE_PARAMS, params);
- }
-
- /**
- * Stop listening for packets.
- *
- * <p>As the server is stopped asynchronously, some packets may still be processed shortly after
- * calling this method.
- */
- public void stop() {
- mHandler.sendEmptyMessage(CMD_STOP_DHCP_SERVER);
- }
-
- private void sendMessage(int what, @Nullable Object obj) {
- mHandler.sendMessage(mHandler.obtainMessage(what, obj));
- }
-
- private class ServerHandler extends Handler {
- ServerHandler(@NonNull Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(@NonNull Message msg) {
- switch (msg.what) {
- case CMD_UPDATE_PARAMS:
- final DhcpServingParams params = (DhcpServingParams) msg.obj;
- mServingParams = params;
- mLeaseRepo.updateParams(
- DhcpServingParams.makeIpPrefix(mServingParams.serverAddr),
- params.excludedAddrs,
- params.dhcpLeaseTimeSecs);
- break;
- case CMD_START_DHCP_SERVER:
- // This is a no-op if the listener is already started
- mPacketListener.start();
- break;
- case CMD_STOP_DHCP_SERVER:
- // This is a no-op if the listener was not started
- mPacketListener.stop();
- break;
- }
- }
- }
-
- @VisibleForTesting
- void processPacket(@NonNull DhcpPacket packet, int srcPort) {
- final String packetType = packet.getClass().getSimpleName();
- if (srcPort != DHCP_CLIENT) {
- mLog.logf("Ignored packet of type %s sent from client port %d", packetType, srcPort);
- return;
- }
-
- mLog.log("Received packet of type " + packetType);
- final Inet4Address sid = packet.mServerIdentifier;
- if (sid != null && !sid.equals(mServingParams.serverAddr.getAddress())) {
- mLog.log("Packet ignored due to wrong server identifier: " + sid);
- return;
- }
-
- try {
- if (packet instanceof DhcpDiscoverPacket) {
- processDiscover((DhcpDiscoverPacket) packet);
- } else if (packet instanceof DhcpRequestPacket) {
- processRequest((DhcpRequestPacket) packet);
- } else if (packet instanceof DhcpReleasePacket) {
- processRelease((DhcpReleasePacket) packet);
- } else {
- mLog.e("Unknown packet type: " + packet.getClass().getSimpleName());
- }
- } catch (MalformedPacketException e) {
- // Not an internal error: only logging exception message, not stacktrace
- mLog.e("Ignored malformed packet: " + e.getMessage());
- }
- }
-
- private void logIgnoredPacketInvalidSubnet(DhcpLeaseRepository.InvalidSubnetException e) {
- // Not an internal error: only logging exception message, not stacktrace
- mLog.e("Ignored packet from invalid subnet: " + e.getMessage());
- }
-
- private void processDiscover(@NonNull DhcpDiscoverPacket packet)
- throws MalformedPacketException {
- final DhcpLease lease;
- final MacAddress clientMac = getMacAddr(packet);
- try {
- lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac,
- packet.mRelayIp, packet.mRequestedIp, packet.mHostName);
- } catch (DhcpLeaseRepository.OutOfAddressesException e) {
- transmitNak(packet, "Out of addresses to offer");
- return;
- } catch (DhcpLeaseRepository.InvalidSubnetException e) {
- logIgnoredPacketInvalidSubnet(e);
- return;
- }
-
- transmitOffer(packet, lease, clientMac);
- }
-
- private void processRequest(@NonNull DhcpRequestPacket packet) throws MalformedPacketException {
- // If set, packet SID matches with this server's ID as checked in processPacket().
- final boolean sidSet = packet.mServerIdentifier != null;
- final DhcpLease lease;
- final MacAddress clientMac = getMacAddr(packet);
- try {
- lease = mLeaseRepo.requestLease(packet.getExplicitClientIdOrNull(), clientMac,
- packet.mClientIp, packet.mRelayIp, packet.mRequestedIp, sidSet,
- packet.mHostName);
- } catch (DhcpLeaseRepository.InvalidAddressException e) {
- transmitNak(packet, "Invalid requested address");
- return;
- } catch (DhcpLeaseRepository.InvalidSubnetException e) {
- logIgnoredPacketInvalidSubnet(e);
- return;
- }
-
- transmitAck(packet, lease, clientMac);
- }
-
- private void processRelease(@NonNull DhcpReleasePacket packet)
- throws MalformedPacketException {
- final byte[] clientId = packet.getExplicitClientIdOrNull();
- final MacAddress macAddr = getMacAddr(packet);
- // Don't care about success (there is no ACK/NAK); logging is already done in the repository
- mLeaseRepo.releaseLease(clientId, macAddr, packet.mClientIp);
- }
-
- private Inet4Address getAckOrOfferDst(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
- boolean broadcastFlag) {
- // Unless relayed or broadcast, send to client IP if already configured on the client, or to
- // the lease address if the client has no configured address
- if (!isEmpty(request.mRelayIp)) {
- return request.mRelayIp;
- } else if (broadcastFlag) {
- return (Inet4Address) Inet4Address.ALL;
- } else if (!isEmpty(request.mClientIp)) {
- return request.mClientIp;
- } else {
- return lease.getNetAddr();
- }
- }
-
- /**
- * Determine whether the broadcast flag should be set in the BOOTP packet flags. This does not
- * apply to NAK responses, which should always have it set.
- */
- private static boolean getBroadcastFlag(@NonNull DhcpPacket request, @NonNull DhcpLease lease) {
- // No broadcast flag if the client already has a configured IP to unicast to. RFC2131 #4.1
- // has some contradictions regarding broadcast behavior if a client already has an IP
- // configured and sends a request with both ciaddr (renew/rebind) and the broadcast flag
- // set. Sending a unicast response to ciaddr matches previous behavior and is more
- // efficient.
- // If the client has no configured IP, broadcast if requested by the client or if the lease
- // address cannot be used to send a unicast reply either.
- return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr()));
- }
-
- /**
- * Get the hostname from a lease if non-empty and requested in the incoming request.
- * @param request The incoming request.
- * @return The hostname, or null if not requested or empty.
- */
- @Nullable
- private static String getHostnameIfRequested(@NonNull DhcpPacket request,
- @NonNull DhcpLease lease) {
- return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname())
- ? lease.getHostname()
- : null;
- }
-
- private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
- @NonNull MacAddress clientMac) {
- final boolean broadcastFlag = getBroadcastFlag(request, lease);
- final int timeout = getLeaseTimeout(lease);
- final Inet4Address prefixMask =
- getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength());
- final Inet4Address broadcastAddr = getBroadcastAddress(
- mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
- final String hostname = getHostnameIfRequested(request, lease);
- final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
- ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
- request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
- broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
- new ArrayList<>(mServingParams.dnsServers),
- mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
- mServingParams.metered, (short) mServingParams.linkMtu);
-
- return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
- }
-
- private boolean transmitAck(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
- @NonNull MacAddress clientMac) {
- // TODO: replace DhcpPacket's build methods with real builders and use common code with
- // transmitOffer above
- final boolean broadcastFlag = getBroadcastFlag(request, lease);
- final int timeout = getLeaseTimeout(lease);
- final String hostname = getHostnameIfRequested(request, lease);
- final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
- broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp,
- lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout,
- mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
- new ArrayList<>(mServingParams.defaultRouters),
- new ArrayList<>(mServingParams.dnsServers),
- mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
- mServingParams.metered, (short) mServingParams.linkMtu);
-
- return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
- }
-
- private boolean transmitNak(DhcpPacket request, String message) {
- mLog.w("Transmitting NAK: " + message);
- // Always set broadcast flag for NAK: client may not have a correct IP
- final ByteBuffer nakPacket = DhcpPacket.buildNakPacket(
- ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(),
- request.mRelayIp, request.mClientMac, true /* broadcast */, message);
-
- final Inet4Address dst = isEmpty(request.mRelayIp)
- ? (Inet4Address) Inet4Address.ALL
- : request.mRelayIp;
- return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst);
- }
-
- private boolean transmitOfferOrAckPacket(@NonNull ByteBuffer buf, @NonNull DhcpPacket request,
- @NonNull DhcpLease lease, @NonNull MacAddress clientMac, boolean broadcastFlag) {
- mLog.logf("Transmitting %s with lease %s", request.getClass().getSimpleName(), lease);
- // Client may not yet respond to ARP for the lease address, which may be the destination
- // address. Add an entry to the ARP cache to save future ARP probes and make sure the
- // packet reaches its destination.
- if (!addArpEntry(clientMac, lease.getNetAddr())) {
- // Logging for error already done
- return false;
- }
- final Inet4Address dst = getAckOrOfferDst(request, lease, broadcastFlag);
- return transmitPacket(buf, request.getClass().getSimpleName(), dst);
- }
-
- private boolean transmitPacket(@NonNull ByteBuffer buf, @NonNull String packetTypeTag,
- @NonNull Inet4Address dst) {
- try {
- mDeps.sendPacket(mSocket, buf, dst);
- } catch (ErrnoException | IOException e) {
- mLog.e("Can't send packet " + packetTypeTag, e);
- return false;
- }
- return true;
- }
-
- private boolean addArpEntry(@NonNull MacAddress macAddr, @NonNull Inet4Address inetAddr) {
- try {
- mDeps.addArpEntry(inetAddr, macAddr, mIfName, mSocket);
- return true;
- } catch (IOException e) {
- mLog.e("Error adding client to ARP table", e);
- return false;
- }
- }
-
- /**
- * Get the remaining lease time in seconds, starting from {@link Clock#elapsedRealtime()}.
- *
- * <p>This is an unsigned 32-bit integer, so it cannot be read as a standard (signed) Java int.
- * The return value is only intended to be used to populate the lease time field in a DHCP
- * response, considering that lease time is an unsigned 32-bit integer field in DHCP packets.
- *
- * <p>Lease expiration times are tracked internally with millisecond precision: this method
- * returns a rounded down value.
- */
- private int getLeaseTimeout(@NonNull DhcpLease lease) {
- final long remainingTimeSecs = (lease.getExpTime() - mClock.elapsedRealtime()) / 1000;
- if (remainingTimeSecs < 0) {
- mLog.e("Processing expired lease " + lease);
- return EXPIRED_FALLBACK_LEASE_TIME_SECS;
- }
-
- if (remainingTimeSecs >= toUnsignedLong(INFINITE_LEASE)) {
- return INFINITE_LEASE;
- }
-
- return (int) remainingTimeSecs;
- }
-
- /**
- * Get the client MAC address from a packet.
- *
- * @throws MalformedPacketException The address in the packet uses an unsupported format.
- */
- @NonNull
- private MacAddress getMacAddr(@NonNull DhcpPacket packet) throws MalformedPacketException {
- try {
- return MacAddress.fromBytes(packet.getClientMac());
- } catch (IllegalArgumentException e) {
- final String message = "Invalid MAC address in packet: "
- + HexDump.dumpHexString(packet.getClientMac());
- throw new MalformedPacketException(message, e);
- }
- }
-
- private static boolean isEmpty(@Nullable Inet4Address address) {
- return address == null || Inet4Address.ANY.equals(address);
- }
-
- private class PacketListener extends DhcpPacketListener {
- PacketListener() {
- super(mHandler);
- }
-
- @Override
- protected void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
- int srcPort) {
- processPacket(packet, srcPort);
- }
-
- @Override
- protected void logError(@NonNull String msg, Exception e) {
- mLog.e("Error receiving packet: " + msg, e);
- }
-
- @Override
- protected void logParseError(@NonNull byte[] packet, int length,
- @NonNull DhcpPacket.ParseException e) {
- mLog.e("Error parsing packet", e);
- }
-
- @Override
- protected FileDescriptor createFd() {
- // TODO: have and use an API to set a socket tag without going through the thread tag
- final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_DHCP_SERVER);
- try {
- mSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1);
- // SO_BINDTODEVICE actually takes a string. This works because the first member
- // of struct ifreq is a NULL-terminated interface name.
- // TODO: add a setsockoptString()
- Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName);
- Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1);
- Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER);
- NetworkUtils.protectFromVpn(mSocket);
-
- return mSocket;
- } catch (IOException | ErrnoException e) {
- mLog.e("Error creating UDP socket", e);
- DhcpServer.this.stop();
- return null;
- } finally {
- TrafficStats.setThreadStatsTag(oldTag);
- }
- }
- }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpServingParams.java b/services/net/java/android/net/dhcp/DhcpServingParams.java
deleted file mode 100644
index 2780814a..0000000
--- a/services/net/java/android/net/dhcp/DhcpServingParams.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
-import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
-import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
-import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
-
-import static java.lang.Integer.toUnsignedLong;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
-
-import com.google.android.collect.Sets;
-
-import java.net.Inet4Address;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Parameters used by the DhcpServer to serve requests.
- *
- * <p>Instances are immutable. Use {@link DhcpServingParams.Builder} to instantiate.
- * @hide
- */
-public class DhcpServingParams {
- public static final int MTU_UNSET = 0;
- public static final int MIN_PREFIX_LENGTH = 16;
- public static final int MAX_PREFIX_LENGTH = 30;
-
- /** Server inet address and prefix to serve */
- @NonNull
- public final LinkAddress serverAddr;
-
- /**
- * Default routers to be advertised to DHCP clients. May be empty.
- * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
- */
- @NonNull
- public final Set<Inet4Address> defaultRouters;
-
- /**
- * DNS servers to be advertised to DHCP clients. May be empty.
- * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
- */
- @NonNull
- public final Set<Inet4Address> dnsServers;
-
- /**
- * Excluded addresses that the DHCP server is not allowed to assign to clients.
- * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
- */
- @NonNull
- public final Set<Inet4Address> excludedAddrs;
-
- // DHCP uses uint32. Use long for clearer code, and check range when building.
- public final long dhcpLeaseTimeSecs;
- public final int linkMtu;
-
- /**
- * Indicates whether the DHCP server should send the ANDROID_METERED vendor-specific option.
- */
- public final boolean metered;
-
- /**
- * Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
- * missing or invalid.
- */
- public static class InvalidParameterException extends Exception {
- public InvalidParameterException(String message) {
- super(message);
- }
- }
-
- private DhcpServingParams(@NonNull LinkAddress serverAddr,
- @NonNull Set<Inet4Address> defaultRouters,
- @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
- long dhcpLeaseTimeSecs, int linkMtu, boolean metered) {
- this.serverAddr = serverAddr;
- this.defaultRouters = defaultRouters;
- this.dnsServers = dnsServers;
- this.excludedAddrs = excludedAddrs;
- this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
- this.linkMtu = linkMtu;
- this.metered = metered;
- }
-
- /**
- * Create parameters from a stable AIDL-compatible parcel.
- */
- public static DhcpServingParams fromParcelableObject(@NonNull DhcpServingParamsParcel parcel)
- throws InvalidParameterException {
- final LinkAddress serverAddr = new LinkAddress(
- intToInet4AddressHTH(parcel.serverAddr),
- parcel.serverAddrPrefixLength);
- return new Builder()
- .setServerAddr(serverAddr)
- .setDefaultRouters(toInet4AddressSet(parcel.defaultRouters))
- .setDnsServers(toInet4AddressSet(parcel.dnsServers))
- .setExcludedAddrs(toInet4AddressSet(parcel.excludedAddrs))
- .setDhcpLeaseTimeSecs(parcel.dhcpLeaseTimeSecs)
- .setLinkMtu(parcel.linkMtu)
- .setMetered(parcel.metered)
- .build();
- }
-
- private static Set<Inet4Address> toInet4AddressSet(@Nullable int[] addrs) {
- if (addrs == null) {
- return new HashSet<>(0);
- }
-
- final HashSet<Inet4Address> res = new HashSet<>();
- for (int addr : addrs) {
- res.add(intToInet4AddressHTH(addr));
- }
- return res;
- }
-
- @NonNull
- public Inet4Address getServerInet4Addr() {
- return (Inet4Address) serverAddr.getAddress();
- }
-
- /**
- * Get the served prefix mask as an IPv4 address.
- *
- * <p>For example, if the served prefix is 192.168.42.0/24, this will return 255.255.255.0.
- */
- @NonNull
- public Inet4Address getPrefixMaskAsAddress() {
- return getPrefixMaskAsInet4Address(serverAddr.getPrefixLength());
- }
-
- /**
- * Get the server broadcast address.
- *
- * <p>For example, if the server {@link LinkAddress} is 192.168.42.1/24, this will return
- * 192.168.42.255.
- */
- @NonNull
- public Inet4Address getBroadcastAddress() {
- return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength());
- }
-
- /**
- * Utility class to create new instances of {@link DhcpServingParams} while checking validity
- * of the parameters.
- */
- public static class Builder {
- private LinkAddress mServerAddr;
- private Set<Inet4Address> mDefaultRouters;
- private Set<Inet4Address> mDnsServers;
- private Set<Inet4Address> mExcludedAddrs;
- private long mDhcpLeaseTimeSecs;
- private int mLinkMtu = MTU_UNSET;
- private boolean mMetered;
-
- /**
- * Set the server address and served prefix for the DHCP server.
- *
- * <p>This parameter is required.
- */
- public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
- this.mServerAddr = serverAddr;
- return this;
- }
-
- /**
- * Set the default routers to be advertised to DHCP clients.
- *
- * <p>Each router must be inside the served prefix. This may be an empty set, but it must
- * always be set explicitly before building the {@link DhcpServingParams}.
- */
- public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
- this.mDefaultRouters = defaultRouters;
- return this;
- }
-
- /**
- * Set the default routers to be advertised to DHCP clients.
- *
- * <p>Each router must be inside the served prefix. This may be an empty list of routers,
- * but it must always be set explicitly before building the {@link DhcpServingParams}.
- */
- public Builder setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
- return setDefaultRouters(Sets.newArraySet(defaultRouters));
- }
-
- /**
- * Convenience method to build the parameters with no default router.
- *
- * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
- */
- public Builder withNoDefaultRouter() {
- return setDefaultRouters();
- }
-
- /**
- * Set the DNS servers to be advertised to DHCP clients.
- *
- * <p>This may be an empty set, but it must always be set explicitly before building the
- * {@link DhcpServingParams}.
- */
- public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
- this.mDnsServers = dnsServers;
- return this;
- }
-
- /**
- * Set the DNS servers to be advertised to DHCP clients.
- *
- * <p>This may be an empty list of servers, but it must always be set explicitly before
- * building the {@link DhcpServingParams}.
- */
- public Builder setDnsServers(@NonNull Inet4Address... dnsServers) {
- return setDnsServers(Sets.newArraySet(dnsServers));
- }
-
- /**
- * Convenience method to build the parameters with no DNS server.
- *
- * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
- */
- public Builder withNoDnsServer() {
- return setDnsServers();
- }
-
- /**
- * Set excluded addresses that the DHCP server is not allowed to assign to clients.
- *
- * <p>This parameter is optional. DNS servers and default routers are always excluded
- * and do not need to be set here.
- */
- public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
- this.mExcludedAddrs = excludedAddrs;
- return this;
- }
-
- /**
- * Set excluded addresses that the DHCP server is not allowed to assign to clients.
- *
- * <p>This parameter is optional. DNS servers and default routers are always excluded
- * and do not need to be set here.
- */
- public Builder setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
- return setExcludedAddrs(Sets.newArraySet(excludedAddrs));
- }
-
- /**
- * Set the lease time for leases assigned by the DHCP server.
- *
- * <p>This parameter is required.
- */
- public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
- this.mDhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
- return this;
- }
-
- /**
- * Set the link MTU to be advertised to DHCP clients.
- *
- * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
- * is optional and defaults to {@link #MTU_UNSET}.
- */
- public Builder setLinkMtu(int linkMtu) {
- this.mLinkMtu = linkMtu;
- return this;
- }
-
- /**
- * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
- *
- * <p>If not set, the default value is false.
- */
- public Builder setMetered(boolean metered) {
- this.mMetered = metered;
- return this;
- }
-
- /**
- * Create a new {@link DhcpServingParams} instance based on parameters set in the builder.
- *
- * <p>This method has no side-effects. If it does not throw, a valid
- * {@link DhcpServingParams} is returned.
- * @return The constructed parameters.
- * @throws InvalidParameterException At least one parameter is missing or invalid.
- */
- @NonNull
- public DhcpServingParams build() throws InvalidParameterException {
- if (mServerAddr == null) {
- throw new InvalidParameterException("Missing serverAddr");
- }
- if (mDefaultRouters == null) {
- throw new InvalidParameterException("Missing defaultRouters");
- }
- if (mDnsServers == null) {
- // Empty set is OK, but enforce explicitly setting it
- throw new InvalidParameterException("Missing dnsServers");
- }
- if (mDhcpLeaseTimeSecs <= 0 || mDhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
- throw new InvalidParameterException("Invalid lease time: " + mDhcpLeaseTimeSecs);
- }
- if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) {
- throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu);
- }
- if (!mServerAddr.isIPv4()) {
- throw new InvalidParameterException("serverAddr must be IPv4");
- }
- if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH
- || mServerAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
- throw new InvalidParameterException("Prefix length is not in supported range");
- }
-
- final IpPrefix prefix = makeIpPrefix(mServerAddr);
- for (Inet4Address addr : mDefaultRouters) {
- if (!prefix.contains(addr)) {
- throw new InvalidParameterException(String.format(
- "Default router %s is not in server prefix %s", addr, mServerAddr));
- }
- }
-
- final Set<Inet4Address> excl = new HashSet<>();
- if (mExcludedAddrs != null) {
- excl.addAll(mExcludedAddrs);
- }
- excl.add((Inet4Address) mServerAddr.getAddress());
- excl.addAll(mDefaultRouters);
- excl.addAll(mDnsServers);
-
- return new DhcpServingParams(mServerAddr,
- Collections.unmodifiableSet(new HashSet<>(mDefaultRouters)),
- Collections.unmodifiableSet(new HashSet<>(mDnsServers)),
- Collections.unmodifiableSet(excl),
- mDhcpLeaseTimeSecs, mLinkMtu, mMetered);
- }
- }
-
- /**
- * Utility method to create an IpPrefix with the address and prefix length of a LinkAddress.
- */
- @NonNull
- static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
- return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
- }
-}
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 493350d..8b22f68 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -17,20 +17,26 @@
package android.net.ip;
import static android.net.NetworkUtils.numericToInetAddress;
-import static android.net.util.NetworkConstants.asByte;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.util.NetworkConstants.FF;
import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+import static android.net.util.NetworkConstants.asByte;
+import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
+import android.net.INetworkStackStatusCallback;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStack;
import android.net.RouteInfo;
-import android.net.dhcp.DhcpServer;
-import android.net.dhcp.DhcpServingParams;
+import android.net.dhcp.DhcpServerCallbacks;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.DhcpServingParamsParcelExt;
+import android.net.dhcp.IDhcpServer;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
@@ -126,6 +132,10 @@
}
public static class Dependencies {
+ private final Context mContext;
+ public Dependencies(Context context) {
+ mContext = context;
+ }
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
return new RouterAdvertisementDaemon(ifParams);
}
@@ -138,9 +148,12 @@
return NetdService.getInstance();
}
- public DhcpServer makeDhcpServer(Looper looper, String ifName,
- DhcpServingParams params, SharedLog log) {
- return new DhcpServer(looper, ifName, params, log);
+ /**
+ * Create a DhcpServer instance to be used by IpServer.
+ */
+ public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
+ DhcpServerCallbacks cb) {
+ mContext.getSystemService(NetworkStack.class).makeDhcpServer(ifName, params, cb);
}
}
@@ -197,7 +210,10 @@
// Advertisements (otherwise, we do not add them to mLinkProperties at all).
private LinkProperties mLastIPv6LinkProperties;
private RouterAdvertisementDaemon mRaDaemon;
- private DhcpServer mDhcpServer;
+
+ // To be accessed only on the handler thread
+ private int mDhcpServerStartIndex = 0;
+ private IDhcpServer mDhcpServer;
private RaParams mLastRaParams;
public IpServer(
@@ -252,35 +268,109 @@
private boolean startIPv4() { return configureIPv4(true); }
+ /**
+ * Convenience wrapper around INetworkStackStatusCallback to run callbacks on the IpServer
+ * handler.
+ *
+ * <p>Different instances of this class can be created for each call to IDhcpServer methods,
+ * with different implementations of the callback, to differentiate handling of success/error in
+ * each call.
+ */
+ private abstract class OnHandlerStatusCallback extends INetworkStackStatusCallback.Stub {
+ @Override
+ public void onStatusAvailable(int statusCode) {
+ getHandler().post(() -> callback(statusCode));
+ }
+
+ public abstract void callback(int statusCode);
+ }
+
+ private class DhcpServerCallbacksImpl extends DhcpServerCallbacks {
+ private final int mStartIndex;
+
+ private DhcpServerCallbacksImpl(int startIndex) {
+ mStartIndex = startIndex;
+ }
+
+ @Override
+ public void onDhcpServerCreated(int statusCode, IDhcpServer server) throws RemoteException {
+ getHandler().post(() -> {
+ // We are on the handler thread: mDhcpServerStartIndex can be read safely.
+ if (mStartIndex != mDhcpServerStartIndex) {
+ // This start request is obsolete. When the |server| binder token goes out of
+ // scope, the garbage collector will finalize it, which causes the network stack
+ // process garbage collector to collect the server itself.
+ return;
+ }
+
+ if (statusCode != STATUS_SUCCESS) {
+ mLog.e("Error obtaining DHCP server: " + statusCode);
+ handleError();
+ return;
+ }
+
+ mDhcpServer = server;
+ try {
+ mDhcpServer.start(new OnHandlerStatusCallback() {
+ @Override
+ public void callback(int startStatusCode) {
+ if (startStatusCode != STATUS_SUCCESS) {
+ mLog.e("Error starting DHCP server: " + startStatusCode);
+ handleError();
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ });
+ }
+
+ private void handleError() {
+ mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ transitionTo(mInitialState);
+ }
+ }
+
private boolean startDhcp(Inet4Address addr, int prefixLen) {
if (mUsingLegacyDhcp) {
return true;
}
- final DhcpServingParams params;
- try {
- params = new DhcpServingParams.Builder()
- .setDefaultRouters(addr)
- .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
- .setDnsServers(addr)
- .setServerAddr(new LinkAddress(addr, prefixLen))
- .setMetered(true)
- .build();
- // TODO: also advertise link MTU
- } catch (DhcpServingParams.InvalidParameterException e) {
- Log.e(TAG, "Invalid DHCP parameters", e);
- return false;
- }
+ final DhcpServingParamsParcel params;
+ params = new DhcpServingParamsParcelExt()
+ .setDefaultRouters(addr)
+ .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
+ .setDnsServers(addr)
+ .setServerAddr(new LinkAddress(addr, prefixLen))
+ .setMetered(true);
+ // TODO: also advertise link MTU
- mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), mIfaceName, params,
- mLog.forSubComponent("DHCP"));
- mDhcpServer.start();
+ mDhcpServerStartIndex++;
+ mDeps.makeDhcpServer(
+ mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex));
return true;
}
private void stopDhcp() {
+ // Make all previous start requests obsolete so servers are not started later
+ mDhcpServerStartIndex++;
+
if (mDhcpServer != null) {
- mDhcpServer.stop();
- mDhcpServer = null;
+ try {
+ mDhcpServer.stop(new OnHandlerStatusCallback() {
+ @Override
+ public void callback(int statusCode) {
+ if (statusCode != STATUS_SUCCESS) {
+ mLog.e("Error stopping DHCP server: " + statusCode);
+ mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ // Not much more we can do here
+ }
+ }
+ });
+ mDhcpServer = null;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
}
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 3defe56..c183b81 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -16,9 +16,6 @@
package android.net.util;
-import java.nio.ByteBuffer;
-
-
/**
* Networking protocol constants.
*
@@ -81,8 +78,6 @@
* - https://tools.ietf.org/html/rfc791
*/
public static final int IPV4_HEADER_MIN_LEN = 20;
- public static final int IPV4_MIN_MTU = 68;
- public static final int IPV4_MAX_MTU = 65_535;
public static final int IPV4_IHL_MASK = 0xf;
public static final int IPV4_FLAGS_OFFSET = 6;
public static final int IPV4_FRAGMENT_MASK = 0x1fff;
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index 74bc147..8b7b59d 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -32,6 +32,7 @@
*
* All access to class methods other than dump() must be on the same thread.
*
+ * TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated.
* @hide
*/
public class SharedLog {