diff options
| author | 2018-12-04 12:13:09 +0900 | |
|---|---|---|
| committer | 2019-01-09 15:42:16 +0900 | |
| commit | 0e3d0923a65d654c57bd0ce24d84a257702e83db (patch) | |
| tree | 1e6af187f61e4165899fb74ab139b25f196b5e3f /services | |
| parent | 5dbf0574365254e9b5aee3919b5ee0563a92ba80 (diff) | |
Move DhcpServer to NetworkStack app
Test: atest FrameworksNetTests && atest NetworkStackTests
Bug: b/112869080
Change-Id: I96c40e63e9ceb37b67705bdd4d120307e114715b
Diffstat (limited to 'services')
12 files changed, 140 insertions, 1770 deletions
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 9dfdddbea18a..eb5be77e4a33 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1837,7 +1837,7 @@ public class Tethering extends BaseNetworkObserver { final TetherState tetherState = new TetherState( new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService, makeControlCallback(), mConfig.enableLegacyDhcpServer, - mDeps.getIpServerDependencies())); + mDeps.getIpServerDependencies(mContext))); mTetherStates.put(iface, tetherState); tetherState.ipServer.start(); } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java index 7daf71dda73b..a42efe960ff9 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -60,8 +60,8 @@ public class TetheringDependencies { /** * Get dependencies to be used by IpServer. */ - public IpServer.Dependencies getIpServerDependencies() { - return new IpServer.Dependencies(); + public IpServer.Dependencies getIpServerDependencies(Context context) { + return new IpServer.Dependencies(context); } /** diff --git a/services/net/Android.bp b/services/net/Android.bp index e0ae68f20483..ae697b7f093a 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -2,3 +2,19 @@ java_library_static { 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 6849cfadc22a..000000000000 --- 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 b3d0512ba447..000000000000 --- 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 6ba7d94117b1..ce8b7e78d0f8 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 @@ import java.util.List; 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 dce8b619494e..000000000000 --- 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 641bba2ed306..000000000000 --- 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 2780814a2f33..000000000000 --- 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 493350d776f3..8b22f68286af 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 class IpServer extends StateMachine { } 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 @@ public class IpServer extends StateMachine { 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 @@ public class IpServer extends StateMachine { // 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 @@ public class IpServer extends StateMachine { 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; - } - - mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), mIfaceName, params, - mLog.forSubComponent("DHCP")); - mDhcpServer.start(); + 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 + + 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 3defe56939f5..c183b81362dc 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 @@ public final class NetworkConstants { * - 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 74bc1470293f..8b7b59d20978 100644 --- a/services/net/java/android/net/util/SharedLog.java +++ b/services/net/java/android/net/util/SharedLog.java @@ -32,6 +32,7 @@ import java.util.StringJoiner; * * 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 { |