Snap for 10743636 from 43af15894d9f995f15fc0098acfe05569f68940a to mainline-uwb-release Change-Id: I4de5c225dae3dfee6eb516e369be2e0c06c01cbd
diff --git a/Android.bp b/Android.bp index 15b4235..ebe5217 100644 --- a/Android.bp +++ b/Android.bp
@@ -307,7 +307,6 @@ name: "NetworkStackAndroidLibraryDefaults", srcs: [ ":framework-networkstack-shared-srcs", - ":services-connectivity-shared-srcs", ], libs: ["unsupportedappusage"], static_libs: [ @@ -389,7 +388,10 @@ ], // If this library is ever used outside of tests, it should not use "Dhcp*Packet", and specify // its contents explicitly. - visibility: ["//packages/modules/Connectivity/tests/cts/net"], + visibility: [ + "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/Connectivity/tests/cts/net", + ], } java_genrule {
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java index 5378294..e6339a0 100644 --- a/src/android/net/dhcp/DhcpClient.java +++ b/src/android/net/dhcp/DhcpClient.java
@@ -101,11 +101,11 @@ import com.android.net.module.util.InterfaceParams; import com.android.net.module.util.NetworkStackConstants; import com.android.net.module.util.PacketReader; +import com.android.net.module.util.arp.ArpPacket; import com.android.networkstack.R; import com.android.networkstack.apishim.CaptivePortalDataShimImpl; import com.android.networkstack.apishim.SocketUtilsShimImpl; import com.android.networkstack.apishim.common.ShimUtils; -import com.android.networkstack.arp.ArpPacket; import com.android.networkstack.metrics.IpProvisioningMetrics; import com.android.networkstack.util.NetworkStackUtils;
diff --git a/src/android/net/dhcp/DhcpResultsParcelableUtil.java b/src/android/net/dhcp/DhcpResultsParcelableUtil.java index 7075925..3b97546 100644 --- a/src/android/net/dhcp/DhcpResultsParcelableUtil.java +++ b/src/android/net/dhcp/DhcpResultsParcelableUtil.java
@@ -17,15 +17,12 @@ package android.net.dhcp; import static android.net.shared.IpConfigurationParcelableUtil.parcelAddress; -import static android.net.shared.IpConfigurationParcelableUtil.unparcelAddress; import android.net.DhcpResults; import android.net.DhcpResultsParcelable; import androidx.annotation.Nullable; -import java.net.Inet4Address; - /** * A utility class to convert DhcpResults to DhcpResultsParcelable. */ @@ -45,19 +42,4 @@ p.captivePortalApiUrl = results.captivePortalApiUrl; return p; } - - /** - * Convert a DhcpResultsParcelable to DhcpResults. - */ - public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) { - if (p == null) return null; - final DhcpResults results = new DhcpResults(p.baseConfiguration); - results.leaseDuration = p.leaseDuration; - results.mtu = p.mtu; - results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress); - results.vendorInfo = p.vendorInfo; - results.serverHostName = p.serverHostName; - results.captivePortalApiUrl = p.captivePortalApiUrl; - return results; - } }
diff --git a/src/android/net/dhcp6/Dhcp6Client.java b/src/android/net/dhcp6/Dhcp6Client.java index d4b4a21..fa6b1bd 100644 --- a/src/android/net/dhcp6/Dhcp6Client.java +++ b/src/android/net/dhcp6/Dhcp6Client.java
@@ -17,8 +17,8 @@ package android.net.dhcp6; import static android.net.dhcp6.Dhcp6Packet.PrefixDelegation; -import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IFA_F_NODAD; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; import static android.system.OsConstants.SOCK_DGRAM; @@ -28,6 +28,7 @@ import static com.android.net.module.util.NetworkStackConstants.DHCP6_CLIENT_PORT; import static com.android.net.module.util.NetworkStackConstants.DHCP6_SERVER_PORT; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; +import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH; import static com.android.networkstack.apishim.ConstantsShim.IFA_F_MANAGETEMPADDR; import static com.android.networkstack.apishim.ConstantsShim.IFA_F_NOPREFIXROUTE; import static com.android.networkstack.util.NetworkStackUtils.createInet6AddressFromEui64; @@ -107,8 +108,11 @@ private static final int FIRST_TIMEOUT_MS = 1 * SECONDS; private static final int MAX_TIMEOUT_MS = 512 * SECONDS; + // Per rfc8415#section-12, the IAID MUST be consistent across restarts. + // Since currently only one IAID is supported, a well-known value can be used (0). + private static final int IAID = 0; + private int mTransId; - private int mIaId; private long mTransStartMillis; @Nullable private PrefixDelegation mAdvertise; @Nullable private PrefixDelegation mReply; @@ -325,7 +329,7 @@ } private ByteBuffer buildEmptyIaPdOption() { - return Dhcp6Packet.buildIaPdOption(mIaId, 0 /* t1 */, 0 /* t2 */, 0 /* preferred */, + return Dhcp6Packet.buildIaPdOption(IAID, 0 /* t1 */, 0 /* t2 */, 0 /* preferred */, 0 /* valid */, new byte[16] /* empty prefix */, (byte) RFC7421_PREFIX_LENGTH); } @@ -398,19 +402,20 @@ public void enter() { super.enter(); startNewTransaction(); - mIaId = mRandom.nextInt(); } + @Override protected boolean sendPacket() { return sendSolicitPacket(buildEmptyIaPdOption()); } // TODO: support multiple prefixes. + @Override protected void receivePacket(Dhcp6Packet packet) { if (!packet.isValid(mTransId, mClientDuid)) return; if (packet instanceof Dhcp6AdvertisePacket) { mAdvertise = packet.mPrefixDelegation; - if (mAdvertise != null && mAdvertise.iaid == mIaId) { + if (mAdvertise != null && mAdvertise.iaid == IAID) { Log.d(TAG, "Get prefix delegation option from Advertise: " + mAdvertise); mServerDuid = packet.mServerDuid; transitionTo(mRequestState); @@ -422,7 +427,7 @@ return; } final PrefixDelegation pd = packet.mPrefixDelegation; - if (pd != null && pd.iaid == mIaId) { + if (pd != null && pd.iaid == IAID) { Log.d(TAG, "Get prefix delegation option from RapidCommit Reply: " + pd); mReply = pd; mServerDuid = packet.mServerDuid; @@ -437,15 +442,17 @@ * process the Reply message in this state. */ class RequestState extends PacketRetransmittingState { + @Override protected boolean sendPacket() { return sendRequestPacket(buildIaPdOption(mAdvertise)); } + @Override protected void receivePacket(Dhcp6Packet packet) { if (!(packet instanceof Dhcp6ReplyPacket)) return; if (!packet.isValid(mTransId, mClientDuid)) return; final PrefixDelegation pd = packet.mPrefixDelegation; - if (pd != null && pd.iaid == mIaId) { + if (pd != null && pd.iaid == IAID) { Log.d(TAG, "Get prefix delegation option from Reply: " + pd); mReply = pd; transitionTo(mBoundState); @@ -515,7 +522,7 @@ // time it enters BoundState. final Inet6Address address = createInet6AddressFromEui64(prefix, mIface.macAddr.toByteArray()); - final int flags = IFA_F_NOPREFIXROUTE | IFA_F_MANAGETEMPADDR; + final int flags = IFA_F_NOPREFIXROUTE | IFA_F_MANAGETEMPADDR | IFA_F_NODAD; final long now = SystemClock.elapsedRealtime(); final long deprecationTime = now + mReply.ipo.preferred; final long expirationTime = now + mReply.ipo.valid; @@ -556,12 +563,13 @@ startNewTransaction(); } + @Override protected void receivePacket(Dhcp6Packet packet) { if (!(packet instanceof Dhcp6ReplyPacket)) return; if (!packet.isValid(mTransId, mClientDuid)) return; final PrefixDelegation pd = packet.mPrefixDelegation; if (pd != null) { - if (pd.iaid != mIaId + if (pd.iaid != IAID || !(Arrays.equals(pd.ipo.prefix, mReply.ipo.prefix) && pd.ipo.prefixLen == mReply.ipo.prefixLen)) { Log.i(TAG, "Renewal prefix " + HexDump.toHexString(pd.ipo.prefix) @@ -604,6 +612,7 @@ } } + @Override protected boolean sendPacket() { return sendRenewPacket(buildIaPdOption(mReply)); } @@ -615,6 +624,7 @@ * update other configuration parameters. */ class RebindState extends ReacquireState { + @Override protected boolean sendPacket() { return sendRebindPacket(buildIaPdOption(mReply)); }
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index c169ad5..42d177f 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java
@@ -27,7 +27,6 @@ import static android.net.ip.IIpClientCallbacks.DTIM_MULTIPLIER_RESET; import static android.net.ip.IpReachabilityMonitor.INVALID_REACHABILITY_LOSS_TYPE; import static android.net.ip.IpReachabilityMonitor.nudEventTypeToInt; -import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.SocketUtils.makePacketSocketAddress; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.system.OsConstants.AF_PACKET; @@ -39,9 +38,9 @@ import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY; import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; +import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH; import static com.android.net.module.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID; import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_DHCPV6_PREFIX_DELEGATION_VERSION; -import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION; import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION; import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION; import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_MULTICAST_NS_VERSION; @@ -116,6 +115,7 @@ import com.android.net.module.util.InterfaceParams; import com.android.net.module.util.SharedLog; import com.android.net.module.util.SocketUtils; +import com.android.net.module.util.arp.ArpPacket; import com.android.net.module.util.ip.InterfaceController; import com.android.net.module.util.netlink.NetlinkUtils; import com.android.networkstack.R; @@ -123,7 +123,6 @@ import com.android.networkstack.apishim.SocketUtilsShimImpl; import com.android.networkstack.apishim.common.NetworkInformationShim; import com.android.networkstack.apishim.common.ShimUtils; -import com.android.networkstack.arp.ArpPacket; import com.android.networkstack.metrics.IpProvisioningMetrics; import com.android.networkstack.metrics.NetworkQuirkMetrics; import com.android.networkstack.packets.NeighborAdvertisement; @@ -474,6 +473,11 @@ public static final String DUMP_ARG_CONFIRM = "confirm"; + // Sysctl parameter strings. + private static final String ACCEPT_RA = "accept_ra"; + private static final String ACCEPT_RA_DEFRTR = "accept_ra_defrtr"; + private static final String DAD_TRANSMITS = "dad_transmits"; + // Below constants are picked up by MessageUtils and exempt from ProGuard optimization. private static final int CMD_TERMINATE_AFTER_STOP = 1; private static final int CMD_STOP = 2; @@ -664,7 +668,7 @@ private long mStartTimeMillis; private long mIPv6ProvisioningDtimGracePeriodMillis; private MacAddress mCurrentBssid; - private boolean mHasDisabledIpv6OrAcceptRaOnProvLoss; + private boolean mHasDisabledAcceptRaDefrtrOnProvLoss; private Integer mDadTransmits = null; private int mMaxDtimMultiplier = DTIM_MULTIPLIER_RESET; private ApfCapabilities mCurrentApfCapabilities; @@ -1061,11 +1065,6 @@ return bssid; } - private boolean shouldDisableAcceptRaOnProvisioningLoss() { - return mDependencies.isFeatureEnabled(mContext, IPCLIENT_DISABLE_ACCEPT_RA_VERSION, - true /* defaultEnabled */); - } - @Override protected void onQuitting() { mCallback.onQuit(); @@ -1442,39 +1441,26 @@ return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes()); } - private void setIpv6AcceptRa(int acceptRa) { + // Set "/proc/sys/net/ipv6/conf/${iface}/${name}" with the given specific value. + private void setIpv6Sysctl(@NonNull final String name, int value) { try { - mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mInterfaceParams.name, "accept_ra", - Integer.toString(acceptRa)); + mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mInterfaceParams.name, + name, Integer.toString(value)); } catch (Exception e) { - Log.e(mTag, "Failed to set accept_ra to " + acceptRa + ": " + e); + Log.e(mTag, "Failed to set " + name + " to + " + value + ": " + e); } } private Integer getIpv6DadTransmits() { try { return Integer.parseUnsignedInt(mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, - mInterfaceName, "dad_transmits")); + mInterfaceName, DAD_TRANSMITS)); } catch (RemoteException | ServiceSpecificException e) { logError("Couldn't read dad_transmits on " + mInterfaceName, e); return null; } } - private void setIpv6DadTransmits(int dadTransmits) { - try { - mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mInterfaceParams.name, - "dad_transmits", Integer.toString(dadTransmits)); - } catch (Exception e) { - Log.e(mTag, "Failed to set dad_transmits to " + dadTransmits + ": " + e); - } - } - - private void restartIpv6WithAcceptRaDisabled() { - mInterfaceCtrl.disableIPv6(); - startIPv6(0 /* acceptRa */); - } - // TODO: Investigate folding all this into the existing static function // LinkProperties.compareProvisioning() or some other single function that // takes two LinkProperties objects and returns a ProvisioningChange @@ -1524,7 +1510,7 @@ // Note that we can still be disconnected by IpReachabilityMonitor // if the IPv6 default gateway (but not the IPv6 DNS servers; see // accompanying code in IpReachabilityMonitor) is unreachable. - final boolean ignoreIPv6ProvisioningLoss = mHasDisabledIpv6OrAcceptRaOnProvLoss + final boolean ignoreIPv6ProvisioningLoss = mHasDisabledAcceptRaDefrtrOnProvLoss || (mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker && !mCm.shouldAvoidBadWifi()); @@ -1552,31 +1538,27 @@ if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) { // Although link properties have lost IPv6 default route in this case, if IPv4 is still // working with appropriate routes and DNS servers, we can keep the current connection - // without disconnecting from the network, just disable IPv6 or accept_ra parameter on - // that given network until to the next provisioning. + // without disconnecting from the network, just disable accept_ra_defrtr sysctl on that + // given network until to the next provisioning. // // Disabling IPv6 stack will result in all IPv6 connectivity torn down and all IPv6 // sockets being closed, the non-routable IPv6 DNS servers will be stripped out, so // applications will be able to reconnect immediately over IPv4. See b/131781810. // - // Sometimes disabling IPv6 stack might introduce other issues(see b/179222860), - // instead disabling accept_ra will result in only IPv4 provisioning and IPv6 link - // local address left on the interface, so applications will be able to reconnect - // immediately over IPv4 and keep IPv6 link-local capable. + // Sometimes disabling IPv6 stack can cause other problems(see b/179222860), conversely, + // disabling accept_ra_defrtr can still keep the interface IPv6 capable, but no longer + // learns the default router from incoming RA, partial IPv6 connectivity will remain on + // the interface, through which applications can still communicate locally. if (newLp.isIpv4Provisioned()) { - if (shouldDisableAcceptRaOnProvisioningLoss()) { - restartIpv6WithAcceptRaDisabled(); - } else { - mInterfaceCtrl.disableIPv6(); - } + // Restart ipv6 with accept_ra_defrtr set to 0. + mInterfaceCtrl.disableIPv6(); + startIPv6(0 /* accept_ra_defrtr */); + mNetworkQuirkMetrics.setEvent(NetworkQuirkEvent.QE_IPV6_PROVISIONING_ROUTER_LOST); mNetworkQuirkMetrics.statsWrite(); - mHasDisabledIpv6OrAcceptRaOnProvLoss = true; + mHasDisabledAcceptRaDefrtrOnProvLoss = true; delta = PROV_CHANGE_STILL_PROVISIONED; - mLog.log(shouldDisableAcceptRaOnProvisioningLoss() - ? "Disabled accept_ra parameter " - : "Disabled IPv6 stack completely " - + "when the IPv6 default router has gone"); + mLog.log("Disabled accept_ra_defrtr sysctl on loss of IPv6 default router"); } else { delta = PROV_CHANGE_LOST_PROVISIONING; } @@ -2119,13 +2101,15 @@ == ProvisioningConfiguration.IPV6_ADDR_GEN_MODE_EUI64; } - private boolean startIPv6(int acceptRa) { - setIpv6AcceptRa(acceptRa); + private boolean startIPv6(int acceptRaDefrtr) { + setIpv6Sysctl(ACCEPT_RA, + mConfiguration.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL ? 0 : 2); + setIpv6Sysctl(ACCEPT_RA_DEFRTR, acceptRaDefrtr); if (shouldDisableDad()) { final Integer dadTransmits = getIpv6DadTransmits(); if (dadTransmits != null) { mDadTransmits = dadTransmits; - setIpv6DadTransmits(0 /* dad_transmits */); + setIpv6Sysctl(DAD_TRANSMITS, 0 /* dad_transmits */); } } return mInterfaceCtrl.setIPv6PrivacyExtensions(true) @@ -2232,7 +2216,7 @@ private void maybeRestoreDadTransmits() { if (mDadTransmits == null) return; - setIpv6DadTransmits(mDadTransmits); + setIpv6Sysctl(DAD_TRANSMITS, mDadTransmits); mDadTransmits = null; } @@ -2326,7 +2310,7 @@ @Override public void enter() { stopAllIP(); - mHasDisabledIpv6OrAcceptRaOnProvLoss = false; + mHasDisabledAcceptRaDefrtrOnProvLoss = false; mGratuitousNaTargetAddresses.clear(); mMulticastNsSourceAddresses.clear(); @@ -2713,9 +2697,7 @@ mPacketTracker = createPacketTracker(); if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName); - final int acceptRa = - mConfiguration.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL ? 0 : 2; - if (isIpv6Enabled() && !startIPv6(acceptRa)) { + if (isIpv6Enabled() && !startIPv6(1 /* acceptRaDefrtr */)) { doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6); enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6); return; @@ -2802,6 +2784,10 @@ } private void clearIpv6PrefixDelegationAddresses() { + if (mPrefixDelegation == null) { + Log.wtf(mTag, "PrefixDelegation shouldn't be null when DHCPv6 PD fails."); + return; + } final IpPrefix prefix; try { prefix = new IpPrefix(Inet6Address.getByAddress(mPrefixDelegation.ipo.prefix),
diff --git a/src/com/android/networkstack/arp/ArpPacket.java b/src/com/android/networkstack/arp/ArpPacket.java deleted file mode 100644 index a25d7bf..0000000 --- a/src/com/android/networkstack/arp/ArpPacket.java +++ /dev/null
@@ -1,171 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.networkstack.arp; - -import static android.system.OsConstants.ETH_P_ARP; -import static android.system.OsConstants.ETH_P_IP; - -import static com.android.net.module.util.NetworkStackConstants.ARP_ETHER_IPV4_LEN; -import static com.android.net.module.util.NetworkStackConstants.ARP_HWTYPE_ETHER; -import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY; -import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST; -import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; -import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; - -import android.net.MacAddress; - -import com.android.internal.annotations.VisibleForTesting; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; - -/** - * Defines basic data and operations needed to build and parse packets for the - * ARP protocol. - * - * @hide - */ -public class ArpPacket { - private static final String TAG = "ArpPacket"; - - public final short opCode; - public final Inet4Address senderIp; - public final Inet4Address targetIp; - public final MacAddress senderHwAddress; - public final MacAddress targetHwAddress; - - ArpPacket(short opCode, MacAddress senderHwAddress, Inet4Address senderIp, - MacAddress targetHwAddress, Inet4Address targetIp) { - this.opCode = opCode; - this.senderHwAddress = senderHwAddress; - this.senderIp = senderIp; - this.targetHwAddress = targetHwAddress; - this.targetIp = targetIp; - } - - /** - * Build an ARP packet from the required specified parameters. - */ - @VisibleForTesting - public static ByteBuffer buildArpPacket(final byte[] dstMac, final byte[] srcMac, - final byte[] targetIp, final byte[] targetHwAddress, byte[] senderIp, - final short opCode) { - final ByteBuffer buf = ByteBuffer.allocate(ARP_ETHER_IPV4_LEN); - - // Ether header - buf.put(dstMac); - buf.put(srcMac); - buf.putShort((short) ETH_P_ARP); - - // ARP header - buf.putShort((short) ARP_HWTYPE_ETHER); // hrd - buf.putShort((short) ETH_P_IP); // pro - buf.put((byte) ETHER_ADDR_LEN); // hln - buf.put((byte) IPV4_ADDR_LEN); // pln - buf.putShort(opCode); // op - buf.put(srcMac); // sha - buf.put(senderIp); // spa - buf.put(targetHwAddress); // tha - buf.put(targetIp); // tpa - buf.flip(); - return buf; - } - - /** - * Parse an ARP packet from an ByteBuffer object. - */ - @VisibleForTesting - public static ArpPacket parseArpPacket(final byte[] recvbuf, final int length) - throws ParseException { - try { - if (length < ARP_ETHER_IPV4_LEN || recvbuf.length < length) { - throw new ParseException("Invalid packet length: " + length); - } - - final ByteBuffer buffer = ByteBuffer.wrap(recvbuf, 0, length); - byte[] l2dst = new byte[ETHER_ADDR_LEN]; - byte[] l2src = new byte[ETHER_ADDR_LEN]; - buffer.get(l2dst); - buffer.get(l2src); - - final short etherType = buffer.getShort(); - if (etherType != ETH_P_ARP) { - throw new ParseException("Incorrect Ether Type: " + etherType); - } - - final short hwType = buffer.getShort(); - if (hwType != ARP_HWTYPE_ETHER) { - throw new ParseException("Incorrect HW Type: " + hwType); - } - - final short protoType = buffer.getShort(); - if (protoType != ETH_P_IP) { - throw new ParseException("Incorrect Protocol Type: " + protoType); - } - - final byte hwAddrLength = buffer.get(); - if (hwAddrLength != ETHER_ADDR_LEN) { - throw new ParseException("Incorrect HW address length: " + hwAddrLength); - } - - final byte ipAddrLength = buffer.get(); - if (ipAddrLength != IPV4_ADDR_LEN) { - throw new ParseException("Incorrect Protocol address length: " + ipAddrLength); - } - - final short opCode = buffer.getShort(); - if (opCode != ARP_REQUEST && opCode != ARP_REPLY) { - throw new ParseException("Incorrect opCode: " + opCode); - } - - byte[] senderHwAddress = new byte[ETHER_ADDR_LEN]; - byte[] senderIp = new byte[IPV4_ADDR_LEN]; - buffer.get(senderHwAddress); - buffer.get(senderIp); - - byte[] targetHwAddress = new byte[ETHER_ADDR_LEN]; - byte[] targetIp = new byte[IPV4_ADDR_LEN]; - buffer.get(targetHwAddress); - buffer.get(targetIp); - - return new ArpPacket(opCode, MacAddress.fromBytes(senderHwAddress), - (Inet4Address) InetAddress.getByAddress(senderIp), - MacAddress.fromBytes(targetHwAddress), - (Inet4Address) InetAddress.getByAddress(targetIp)); - } catch (IndexOutOfBoundsException e) { - throw new ParseException("Invalid index when wrapping a byte array into a buffer"); - } catch (BufferUnderflowException e) { - throw new ParseException("Invalid buffer position"); - } catch (IllegalArgumentException e) { - throw new ParseException("Invalid MAC address representation"); - } catch (UnknownHostException e) { - throw new ParseException("Invalid IP address of Host"); - } - } - - /** - * Thrown when parsing ARP packet failed. - */ - public static class ParseException extends Exception { - ParseException(String message) { - super(message); - } - } -}
diff --git a/src/com/android/networkstack/util/NetworkStackUtils.java b/src/com/android/networkstack/util/NetworkStackUtils.java index 8fb157c..fe60cdd 100755 --- a/src/com/android/networkstack/util/NetworkStackUtils.java +++ b/src/com/android/networkstack/util/NetworkStackUtils.java
@@ -248,12 +248,6 @@ "ipclient_accept_ipv6_link_local_dns_version"; /** - * Experiment flag to disable accept_ra parameter when IPv6 provisioning loss happens due to - * the default route has gone. - */ - public static final String IPCLIENT_DISABLE_ACCEPT_RA_VERSION = "ipclient_disable_accept_ra"; - - /** * Experiment flag to enable "mcast_resolicit" neighbor parameter in IpReachabilityMonitor, * set it to 3 by default. */
diff --git a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java index 6f30d4c..39eb727 100644 --- a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java +++ b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
@@ -36,7 +36,6 @@ import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; import static android.net.dhcp.DhcpPacket.MIN_V6ONLY_WAIT_MS; -import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable; import static android.net.ip.IIpClientCallbacks.DTIM_MULTIPLIER_RESET; import static android.net.ip.IpClient.CONFIG_IPV6_AUTOCONF_TIMEOUT; import static android.net.ip.IpClientLinkObserver.CLAT_PREFIX; @@ -69,7 +68,6 @@ import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; -import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; import static com.android.net.module.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET; import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; @@ -120,7 +118,6 @@ import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; -import android.net.DhcpResults; import android.net.DhcpResultsParcelable; import android.net.INetd; import android.net.InetAddresses; @@ -172,7 +169,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; -import android.stats.connectivity.NetworkQuirkEvent; import android.stats.connectivity.NudEventType; import android.system.ErrnoException; import android.system.Os; @@ -189,6 +185,7 @@ import com.android.net.module.util.PacketBuilder; import com.android.net.module.util.SharedLog; import com.android.net.module.util.Struct; +import com.android.net.module.util.arp.ArpPacket; import com.android.net.module.util.ip.IpNeighborMonitor; import com.android.net.module.util.ip.IpNeighborMonitor.NeighborEventConsumer; import com.android.net.module.util.netlink.NetlinkUtils; @@ -202,7 +199,6 @@ import com.android.networkstack.apishim.CaptivePortalDataShimImpl; import com.android.networkstack.apishim.ConstantsShim; import com.android.networkstack.apishim.common.ShimUtils; -import com.android.networkstack.arp.ArpPacket; import com.android.networkstack.ipmemorystore.IpMemoryStoreService; import com.android.networkstack.metrics.IpProvisioningMetrics; import com.android.networkstack.metrics.IpReachabilityMonitorMetrics; @@ -2859,14 +2855,14 @@ ArgumentCaptor<DhcpResultsParcelable> captor = ArgumentCaptor.forClass(DhcpResultsParcelable.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(captor.capture()); - DhcpResults lease = fromStableParcelable(captor.getValue()); + final DhcpResultsParcelable lease = captor.getValue(); assertNotNull(lease); - assertEquals(lease.getIpAddress().getAddress(), CLIENT_ADDR); - assertEquals(lease.getGateway(), SERVER_ADDR); - assertEquals(1, lease.getDnsServers().size()); - assertTrue(lease.getDnsServers().contains(SERVER_ADDR)); - assertEquals(lease.getServerAddress(), SERVER_ADDR); - assertEquals(lease.getMtu(), TEST_DEFAULT_MTU); + assertEquals(CLIENT_ADDR, lease.baseConfiguration.getIpAddress().getAddress()); + assertEquals(SERVER_ADDR, lease.baseConfiguration.getGateway()); + assertEquals(1, lease.baseConfiguration.getDnsServers().size()); + assertTrue(lease.baseConfiguration.getDnsServers().contains(SERVER_ADDR)); + assertEquals(SERVER_ADDR, InetAddresses.parseNumericAddress(lease.serverAddress)); + assertEquals(TEST_DEFAULT_MTU, lease.mtu); if (expectMetered) { assertEquals(lease.vendorInfo, DhcpPacket.VENDOR_INFO_ANDROID_METERED); @@ -3010,7 +3006,7 @@ ArgumentCaptor<DhcpResultsParcelable> resultsCaptor = ArgumentCaptor.forClass(DhcpResultsParcelable.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(resultsCaptor.capture()); - DhcpResults lease = fromStableParcelable(resultsCaptor.getValue()); + final DhcpResultsParcelable lease = resultsCaptor.getValue(); assertNull(lease); // DhcpClient rolls back to StoppedState instead of INIT state after calling @@ -3110,13 +3106,11 @@ return lp; } - private void doDualStackProvisioning(boolean shouldDisableAcceptRa) throws Exception { + private void doDualStackProvisioning() throws Exception { final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() .withoutIpReachabilityMonitor() .build(); - setFeatureEnabled(NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION, - shouldDisableAcceptRa); // Enable rapid commit to accelerate DHCP handshake to shorten test duration, // not strictly necessary. setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */, @@ -3131,37 +3125,6 @@ performDualStackProvisioning(); } - @Test @SignatureRequiredTest(reason = "signature perms are required due to mocked callabck") - public void testIgnoreIpv6ProvisioningLoss_disableIPv6Stack() throws Exception { - doDualStackProvisioning(false /* shouldDisableAcceptRa */); - - final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>(); - - // Send RA with 0-lifetime and wait until all IPv6-related default route and DNS servers - // have been removed, then verify if there is IPv4-only info left in the LinkProperties. - sendRouterAdvertisementWithZeroRouterLifetime(); - verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange( - argThat(x -> { - final boolean isOnlyIPv4Provisioned = (x.getLinkAddresses().size() == 1 - && x.getDnsServers().size() == 1 - && x.getAddresses().get(0) instanceof Inet4Address - && x.getDnsServers().get(0) instanceof Inet4Address); - - if (!isOnlyIPv4Provisioned) return false; - lpFuture.complete(x); - return true; - })); - final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); - assertNotNull(lp); - assertEquals(lp.getAddresses().get(0), CLIENT_ADDR); - assertEquals(lp.getDnsServers().get(0), SERVER_ADDR); - - final ArgumentCaptor<Integer> quirkEvent = ArgumentCaptor.forClass(Integer.class); - verify(mNetworkQuirkMetricsDeps, timeout(TEST_TIMEOUT_MS)).writeStats(quirkEvent.capture()); - assertEquals((long) quirkEvent.getValue(), - (long) NetworkQuirkEvent.QE_IPV6_PROVISIONING_ROUTER_LOST.ordinal()); - } - private boolean hasRouteTo(@NonNull final LinkProperties lp, @NonNull final String prefix) { return hasRouteTo(lp, prefix, RTN_UNICAST); } @@ -3185,9 +3148,9 @@ return false; } - @Test @SignatureRequiredTest(reason = "signature perms are required due to mocked callabck") - public void testIgnoreIpv6ProvisioningLoss_disableAcceptRa() throws Exception { - doDualStackProvisioning(true /* shouldDisableAcceptRa */); + @Test + public void testIgnoreIpv6ProvisioningLoss_disableAcceptRaDefrtr() throws Exception { + doDualStackProvisioning(); final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>(); @@ -3220,16 +3183,23 @@ assertTrue(hasRouteTo(lp, IPV4_ANY_ADDRESS_PREFIX)); // IPv4 default route assertTrue(lp.getAddresses().get(1).isLinkLocalAddress()); - reset(mCb); + clearInvocations(mCb); - // Send an RA to verify that global IPv6 addresses won't be configured on the interface. + // Send an RA to verify that device gains the IPv6 provisioning without default route and + // off-link DNS server. sendBasicRouterAdvertisement(false /* waitForRs */); - verify(mCb, timeout(TEST_TIMEOUT_MS).times(0)).onLinkPropertiesChange(any()); + verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat( + x -> x.hasGlobalIpv6Address() + // IPv4, IPv6 link local, privacy and stable privacy + && x.getLinkAddresses().size() == 4 + && !x.hasIpv6DefaultRoute() + && x.getDnsServers().size() == 1 + && x.getDnsServers().get(0).equals(SERVER_ADDR))); } @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") public void testDualStackProvisioning() throws Exception { - doDualStackProvisioning(false /* shouldDisableAcceptRa */); + doDualStackProvisioning(); verify(mCb, never()).onProvisioningFailure(any()); } @@ -3450,7 +3420,7 @@ public void testNoFdLeaks() throws Exception { // Shut down and restart IpClient once to ensure that any fds that are opened the first // time it runs do not cause the test to fail. - doDualStackProvisioning(false /* shouldDisableAcceptRa */); + doDualStackProvisioning(); shutdownAndRecreateIpClient(); // Unfortunately we cannot use a large number of iterations as it would make the test run @@ -3458,7 +3428,7 @@ final int iterations = 10; final int before = getNumOpenFds(); for (int i = 0; i < iterations; i++) { - doDualStackProvisioning(false /* shouldDisableAcceptRa */); + doDualStackProvisioning(); shutdownAndRecreateIpClient(); // The last time this loop runs, mIpc will be shut down in tearDown. } @@ -4347,6 +4317,25 @@ } @Test + public void testIPv6LinkLocalOnly_verifyAcceptRaDefrtr() throws Exception { + ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() + .withoutIPv4() + .withIpv6LinkLocalOnly() + .withRandomMacAddress() + .build(); + startIpClientProvisioning(config); + verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); + + clearInvocations(mCb); + + // accept_ra is set to 0 and accept_ra_defrtr is set to 1 in IPv6 link-local only mode, + // send another RA to tap interface, to verify that we should not see any IPv6 provisioning + // although accept_ra_defrtr is set to 1. + sendBasicRouterAdvertisement(false /* waitForRs */); + verify(mCb, never()).onLinkPropertiesChange(argThat(x -> x.isIpv6Provisioned())); + } + + @Test public void testIPv6LinkLocalOnlyAndThenGlobal() throws Exception { ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() .withoutIPv4() @@ -4639,7 +4628,7 @@ } private void runDualStackNetworkDtimMultiplierSetting(final InOrder inOrder) throws Exception { - doDualStackProvisioning(false /* shouldDisableAcceptRa */); + doDualStackProvisioning(); inOrder.verify(mCb).setMaxDtimMultiplier( IpClient.DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER); inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).setMaxDtimMultiplier( @@ -4678,7 +4667,7 @@ verify(mCb, after(10).never()).setMaxDtimMultiplier( IpClient.DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER); - doDualStackProvisioning(false /* shouldDisableAcceptRa */); + doDualStackProvisioning(); verify(mCb, times(1)).setMaxDtimMultiplier( IpClient.DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER); }
diff --git a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt index bff1088..3bba529 100644 --- a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt +++ b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
@@ -58,7 +58,7 @@ return networkStackVersion == 300000000L || networkStackVersion >= 301100000L } - private fun getNetworkStackComponent(connectorAction: String): ComponentName { + private fun getNetworkStackComponent(connectorAction: String?): ComponentName { val connectorIntent = Intent(connectorAction) return connectorIntent.resolveSystemService(context.packageManager, MATCH_SYSTEM_ONLY) ?: fail("TestNetworkStackService not found")
diff --git a/tests/integration/signature/android/net/NetworkStatsIntegrationTest.kt b/tests/integration/signature/android/net/NetworkStatsIntegrationTest.kt index 0f860a8..8b1b046 100644 --- a/tests/integration/signature/android/net/NetworkStatsIntegrationTest.kt +++ b/tests/integration/signature/android/net/NetworkStatsIntegrationTest.kt
@@ -98,7 +98,7 @@ private val packetBridge = runAsShell(MANAGE_TEST_NETWORKS) { PacketBridge(context, INTERNAL_V6ADDR, EXTERNAL_V6ADDR, REMOTE_V6ADDR.address) } - private val cm = context.getSystemService(ConnectivityManager::class.java) + private val cm = context.getSystemService(ConnectivityManager::class.java)!! // Set up DNS server for testing server and DNS64. private val fakeDns = TestDnsServer( @@ -129,7 +129,7 @@ // network stats being counted, which can only be achieved when they are marked as TYPE_TEST. // If the tethering module does not support TYPE_TEST stats, then these tests will need // to be skipped. - fun shouldRunTests() = cm.getNetworkInfo(packetBridge.internalNetwork).type == TYPE_TEST + fun shouldRunTests() = cm.getNetworkInfo(packetBridge.internalNetwork)!!.type == TYPE_TEST @After fun tearDown() { @@ -139,7 +139,7 @@ } private fun waitFor464XlatReady(network: Network): String { - val iface = cm.getLinkProperties(network).interfaceName + val iface = cm.getLinkProperties(network)!!.interfaceName!! // Make a network request to listen to the specific test network. val nr = NetworkRequest.Builder() @@ -152,14 +152,14 @@ // Wait for the stacked address to be available. testCb.eventuallyExpect<LinkPropertiesChanged> { - it.lp.stackedLinks?.getOrNull(0)?.linkAddresses?.getOrNull(0) != null + it.lp.stackedLinks.getOrNull(0)?.linkAddresses?.getOrNull(0) != null } return iface } private val Network.mtu: Int get() { - val lp = cm.getLinkProperties(this) + val lp = cm.getLinkProperties(this)!! val mtuStacked = if (lp.stackedLinks[0]?.mtu != 0) lp.stackedLinks[0].mtu else DEFAULT_MTU val mtuInterface = if (lp.mtu != 0) lp.mtu else DEFAULT_MTU return mtuInterface.coerceAtMost(mtuStacked) @@ -408,7 +408,7 @@ tag: Int, queryApi: (nsm: NetworkStatsManager, template: NetworkTemplate) -> NetworkStats ): BareStats { - val nsm = context.getSystemService(NetworkStatsManager::class.java) + val nsm = context.getSystemService(NetworkStatsManager::class.java)!! nsm.forceUpdate() val testTemplate = NetworkTemplate.Builder(MATCH_TEST) .setWifiNetworkKeys(setOf(iface)).build()
diff --git a/tests/unit/src/android/net/dhcp/DhcpResultsParcelableUtilTest.java b/tests/unit/src/android/net/dhcp/DhcpResultsParcelableUtilTest.java index 5e160ad..2810301 100644 --- a/tests/unit/src/android/net/dhcp/DhcpResultsParcelableUtilTest.java +++ b/tests/unit/src/android/net/dhcp/DhcpResultsParcelableUtilTest.java
@@ -17,8 +17,8 @@ package android.net.dhcp; import static android.net.InetAddresses.parseNumericAddress; -import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable; import static android.net.dhcp.DhcpResultsParcelableUtil.toStableParcelable; +import static android.net.shared.IpConfigurationParcelableUtil.unparcelAddress; import static com.android.testutils.MiscAsserts.assertFieldCountEquals; @@ -26,9 +26,12 @@ import static org.junit.Assert.assertTrue; import android.net.DhcpResults; +import android.net.DhcpResultsParcelable; import android.net.LinkAddress; import android.net.shared.IpConfigurationParcelableUtil; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -65,63 +68,90 @@ } @Test - public void testParcelUnparcelDhcpResults() { - doDhcpResultsParcelUnparcelTest(); + public void testParcelDhcpResults() { + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_NullIpAddress() { mDhcpResults.ipAddress = null; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_NullGateway() { mDhcpResults.gateway = null; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_NullDomains() { mDhcpResults.domains = null; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_EmptyDomains() { mDhcpResults.domains = ""; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_NullServerAddress() { mDhcpResults.serverAddress = null; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_NullVendorInfo() { mDhcpResults.vendorInfo = null; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_NullServerHostName() { mDhcpResults.serverHostName = null; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } @Test public void testParcelUnparcelDhcpResults_NullCaptivePortalApiUrl() { mDhcpResults.captivePortalApiUrl = null; - doDhcpResultsParcelUnparcelTest(); + doDhcpResultsParcelTest(); } - private void doDhcpResultsParcelUnparcelTest() { + private void doDhcpResultsParcelTest() { final DhcpResults unparceled = fromStableParcelable(toStableParcelable(mDhcpResults)); + setFieldsLostWhileParceling(unparceled); assertEquals(mDhcpResults, unparceled); } + private static void setFieldsLostWhileParceling(@NonNull DhcpResults unparceledResults) { + // TODO: add other fields that are not part of DhcpResultsParcelable here + // e.g. if the dmnsrchList field is added, + // parceledResults.dmnsrchList.addAll(mDhcpResults.dmnSrchList); + } + + /** + * Convert a DhcpResultsParcelable to DhcpResults. + */ + private static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) { + if (p == null) return null; + final DhcpResults results = new DhcpResults(p.baseConfiguration); + results.leaseDuration = p.leaseDuration; + results.mtu = p.mtu; + results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress); + results.vendorInfo = p.vendorInfo; + results.serverHostName = p.serverHostName; + results.captivePortalApiUrl = p.captivePortalApiUrl; + // DhcpResultsParcelable is only used to fill the legacy DhcpInfo class in Wifi, so it + // should not be extended with any new field. Some fields maybe part of DhcpResults, but + // not DhcpResultsParcelable, as DhcpResults is used internally in NetworkStack, but + // DhcpResultsParcelable is used to provide info to wifi (for building DhcpInfo) + + return results; + } + @Test public void testToString() { final String str = toStableParcelable(mDhcpResults).toString();
diff --git a/tests/unit/src/com/android/networkstack/arp/ArpPacketTest.java b/tests/unit/src/com/android/networkstack/arp/ArpPacketTest.java deleted file mode 100644 index dd7ba6a..0000000 --- a/tests/unit/src/com/android/networkstack/arp/ArpPacketTest.java +++ /dev/null
@@ -1,199 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.networkstack.arp; - -import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST; -import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; -import static com.android.testutils.MiscAsserts.assertThrows; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import android.net.InetAddresses; -import android.net.MacAddress; -import android.net.dhcp.DhcpPacket; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.nio.ByteBuffer; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public final class ArpPacketTest { - - private static final Inet4Address TEST_IPV4_ADDR = - (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.2"); - private static final Inet4Address INADDR_ANY = - (Inet4Address) InetAddresses.parseNumericAddress("0.0.0.0"); - private static final byte[] TEST_SENDER_MAC_ADDR = new byte[] { - 0x00, 0x1a, 0x11, 0x22, 0x33, 0x33 }; - private static final byte[] TEST_TARGET_MAC_ADDR = new byte[] { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - private static final byte[] TEST_ARP_PROBE = new byte[] { - // dst mac address - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - // src mac address - (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, - // ether type - (byte) 0x08, (byte) 0x06, - // hardware type - (byte) 0x00, (byte) 0x01, - // protocol type - (byte) 0x08, (byte) 0x00, - // hardware address size - (byte) 0x06, - // protocol address size - (byte) 0x04, - // opcode - (byte) 0x00, (byte) 0x01, - // sender mac address - (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, - // sender IP address - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - // target mac address - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - // target IP address - (byte) 0xc0, (byte) 0xa8, (byte) 0x01, (byte) 0x02, - }; - - private static final byte[] TEST_ARP_ANNOUNCE = new byte[] { - // dst mac address - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - // src mac address - (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, - // ether type - (byte) 0x08, (byte) 0x06, - // hardware type - (byte) 0x00, (byte) 0x01, - // protocol type - (byte) 0x08, (byte) 0x00, - // hardware address size - (byte) 0x06, - // protocol address size - (byte) 0x04, - // opcode - (byte) 0x00, (byte) 0x01, - // sender mac address - (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, - // sender IP address - (byte) 0xc0, (byte) 0xa8, (byte) 0x01, (byte) 0x02, - // target mac address - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - // target IP address - (byte) 0xc0, (byte) 0xa8, (byte) 0x01, (byte) 0x02, - }; - - private static final byte[] TEST_ARP_PROBE_TRUNCATED = new byte[] { - // dst mac address - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - // src mac address - (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, - // ether type - (byte) 0x08, (byte) 0x06, - // hardware type - (byte) 0x00, (byte) 0x01, - // protocol type - (byte) 0x08, (byte) 0x00, - // hardware address size - (byte) 0x06, - // protocol address size - (byte) 0x04, - // opcode - (byte) 0x00, - }; - - private static final byte[] TEST_ARP_PROBE_TRUNCATED_MAC = new byte[] { - // dst mac address - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - // src mac address - (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, - // ether type - (byte) 0x08, (byte) 0x06, - // hardware type - (byte) 0x00, (byte) 0x01, - // protocol type - (byte) 0x08, (byte) 0x00, - // hardware address size - (byte) 0x06, - // protocol address size - (byte) 0x04, - // opcode - (byte) 0x00, (byte) 0x01, - // sender mac address - (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, - }; - - @Test - public void testBuildArpProbePacket() throws Exception { - final ByteBuffer arpProbe = ArpPacket.buildArpPacket(DhcpPacket.ETHER_BROADCAST, - TEST_SENDER_MAC_ADDR, TEST_IPV4_ADDR.getAddress(), new byte[ETHER_ADDR_LEN], - INADDR_ANY.getAddress(), (short) ARP_REQUEST); - assertArrayEquals(arpProbe.array(), TEST_ARP_PROBE); - } - - @Test - public void testBuildArpAnnouncePacket() throws Exception { - final ByteBuffer arpAnnounce = ArpPacket.buildArpPacket(DhcpPacket.ETHER_BROADCAST, - TEST_SENDER_MAC_ADDR, TEST_IPV4_ADDR.getAddress(), new byte[ETHER_ADDR_LEN], - TEST_IPV4_ADDR.getAddress(), (short) ARP_REQUEST); - assertArrayEquals(arpAnnounce.array(), TEST_ARP_ANNOUNCE); - } - - @Test - public void testParseArpProbePacket() throws Exception { - final ArpPacket packet = ArpPacket.parseArpPacket(TEST_ARP_PROBE, TEST_ARP_PROBE.length); - assertEquals(packet.opCode, ARP_REQUEST); - assertEquals(packet.senderHwAddress, MacAddress.fromBytes(TEST_SENDER_MAC_ADDR)); - assertEquals(packet.targetHwAddress, MacAddress.fromBytes(TEST_TARGET_MAC_ADDR)); - assertEquals(packet.senderIp, INADDR_ANY); - assertEquals(packet.targetIp, TEST_IPV4_ADDR); - } - - @Test - public void testParseArpAnnouncePacket() throws Exception { - final ArpPacket packet = ArpPacket.parseArpPacket(TEST_ARP_ANNOUNCE, - TEST_ARP_ANNOUNCE.length); - assertEquals(packet.opCode, ARP_REQUEST); - assertEquals(packet.senderHwAddress, MacAddress.fromBytes(TEST_SENDER_MAC_ADDR)); - assertEquals(packet.targetHwAddress, MacAddress.fromBytes(TEST_TARGET_MAC_ADDR)); - assertEquals(packet.senderIp, TEST_IPV4_ADDR); - assertEquals(packet.targetIp, TEST_IPV4_ADDR); - } - - @Test - public void testParseArpPacket_invalidByteBufferParameters() throws Exception { - assertThrows(ArpPacket.ParseException.class, () -> ArpPacket.parseArpPacket( - TEST_ARP_PROBE, 0)); - } - - @Test - public void testParseArpPacket_truncatedPacket() throws Exception { - assertThrows(ArpPacket.ParseException.class, () -> ArpPacket.parseArpPacket( - TEST_ARP_PROBE_TRUNCATED, TEST_ARP_PROBE_TRUNCATED.length)); - } - - @Test - public void testParseArpPacket_truncatedMacAddress() throws Exception { - assertThrows(ArpPacket.ParseException.class, () -> ArpPacket.parseArpPacket( - TEST_ARP_PROBE_TRUNCATED_MAC, TEST_ARP_PROBE_TRUNCATED.length)); - } -}
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java index ddab8c7..c362044 100644 --- a/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java +++ b/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java
@@ -17,6 +17,8 @@ package com.android.networkstack.netlink; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -27,6 +29,7 @@ import org.junit.runner.RunWith; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.LinkedHashMap; import java.util.Map; @@ -49,38 +52,38 @@ "07" + // option = TCPI_OPT_WSCALE|TCPI_OPT_SACK|TCPI_OPT_TIMESTAMPS "88" + // wscale = 8 "00" + // delivery_rate_app_limited = 0 - "001B914A" + // rto = 1806666 + "4A911B00" + // rto = 1806666 "00000000" + // ato = 0 - "0000052E" + // sndMss = 1326 - "00000218" + // rcvMss = 536 + "2E050000" + // sndMss = 1326 + "18020000" + // rcvMss = 536 "00000000" + // unsacked = 0 "00000000" + // acked = 0 "00000000" + // lost = 0 "00000000" + // retrans = 0 "00000000" + // fackets = 0 - "000000BB" + // lastDataSent = 187 + "BB000000" + // lastDataSent = 187 "00000000" + // lastAckSent = 0 - "000000BB" + // lastDataRecv = 187 - "000000BB" + // lastDataAckRecv = 187 - "000005DC" + // pmtu = 1500 - "00015630" + // rcvSsthresh = 87600 - "00092C3E" + // rttt = 601150 - "0004961F" + // rttvar = 300575 - "00000578" + // sndSsthresh = 1400 - "0000000A" + // sndCwnd = 10 - "000005A8" + // advmss = 1448 - "00000003" + // reordering = 3 + "BB000000" + // lastDataRecv = 187 + "BB00000000" + // lastDataAckRecv = 187 + "DC0500" + // pmtu = 1500 + "30560100" + // rcvSsthresh = 87600 + "3E2C0900" + // rttt = 601150 + "1F960400" + // rttvar = 300575 + "78050000" + // sndSsthresh = 1400 + "0A000000" + // sndCwnd = 10 + "A8050000" + // advmss = 1448 + "02000000" + // reordering = 3 "00000000" + // rcvrtt = 0 - "00015630" + // rcvspace = 87600 + "30560100" + // rcvspace = 87600 "00000000" + // totalRetrans = 0 - "000000000000AC53" + // pacingRate = 44115 + "53AC000000000000" + // pacingRate = 44115 "FFFFFFFFFFFFFFFF" + // maxPacingRate = 18446744073709551615 - "0000000000000001" + // bytesAcked = 1 + "0100000000000001" + // bytesAcked = 1 "0000000000000000" + // bytesReceived = 0 - "00000002" + // SegsOut = 2 - "00000001" + // SegsIn = 1 + "02000000" + // SegsOut = 2 + "01000000" + // SegsIn = 1 "00000000" + // NotSentBytes = 0 - "00092C3E" + // minRtt = 601150 + "3E2C0900" + // minRtt = 601150 "00000000" + // DataSegsIn = 0 "00000000" + // DataSegsOut = 0 "0000000000000000" + // deliverRate = 0 @@ -102,21 +105,29 @@ @Test public void testParseTcpInfo() { final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); + // Android is always little-endian. Refer to https://developer.android.com/ndk/guides/abis. + buffer.order(ByteOrder.nativeOrder()); // Length is less than required - final TcpInfo nullInfo = TcpInfo.parse(buffer, SHORT_TEST_TCP_INFO); - assertEquals(nullInfo, null); + assertNull(TcpInfo.parse(buffer, SHORT_TEST_TCP_INFO)); + assertEquals(TEST_TCPINFO, TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1)); - final TcpInfo parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1); - assertEquals(parsedInfo, TEST_TCPINFO); + // Make a data that TcpInfo is not started from the beginning of the buffer. + final ByteBuffer buffer2 = ByteBuffer.wrap(TCP_INFO_BYTES); + buffer2.order(ByteOrder.nativeOrder()); + // Move to certain position. + buffer2.position(2); + // Parsing is started in an incorrect position. This results in a failed parsing. + assertNotEquals(TEST_TCPINFO, TcpInfo.parse(buffer2, TCP_INFO_LENGTH_V1)); - // Make a data that TcpInfo is not started from the begining of the buffer. - final ByteBuffer bufferWithHeader = + // Make a TcpInfo with extra tcp info fields. Parsing is only performed with + // TCP_INFO_LENGTH_V1 length. Result is the same as parsing with TCP_INFO_BYTES. + final ByteBuffer bufferExtraInfo = ByteBuffer.allocate(EXPANDED_TCP_INFO_BYTES.length + TCP_INFO_BYTES.length); - bufferWithHeader.put(EXPANDED_TCP_INFO_BYTES); - bufferWithHeader.put(TCP_INFO_BYTES); - final TcpInfo infoWithHeader = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1); - bufferWithHeader.position(EXPANDED_TCP_INFO_BYTES.length); - assertEquals(parsedInfo, TEST_TCPINFO); + bufferExtraInfo.order(ByteOrder.nativeOrder()); + bufferExtraInfo.put(TCP_INFO_BYTES); + bufferExtraInfo.put(EXPANDED_TCP_INFO_BYTES); + bufferExtraInfo.position(0); + assertEquals(TEST_TCPINFO, TcpInfo.parse(bufferExtraInfo, TCP_INFO_LENGTH_V1)); } @Test @@ -130,25 +141,27 @@ @Test public void testParseTcpInfoExpanded() { final ByteBuffer buffer = ByteBuffer.wrap(EXPANDED_TCP_INFO_BYTES); + // Android is always little-endian. Refer to https://developer.android.com/ndk/guides/abis. + buffer.order(ByteOrder.nativeOrder()); final TcpInfo parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1 + EXPANDED_TCP_INFO_LENGTH); - assertEquals(parsedInfo, TEST_TCPINFO); + assertEquals(TEST_TCPINFO, parsedInfo); assertEquals(buffer.limit(), buffer.position()); // reset the index. buffer.position(0); final TcpInfo parsedInfoShorterLen = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1); - assertEquals(parsedInfoShorterLen, TEST_TCPINFO); + assertEquals(TEST_TCPINFO, parsedInfoShorterLen); assertEquals(TCP_INFO_LENGTH_V1, buffer.position()); } @Test public void testTcpStateName() { - assertEquals(TcpInfo.getTcpStateName(4), TCP_FIN_WAIT1); - assertEquals(TcpInfo.getTcpStateName(1), TCP_ESTABLISHED); - assertEquals(TcpInfo.getTcpStateName(2), TCP_SYN_SENT); - assertEquals(TcpInfo.getTcpStateName(20), UNKNOWN_20); + assertEquals(TCP_FIN_WAIT1, TcpInfo.getTcpStateName(4)); + assertEquals(TCP_ESTABLISHED, TcpInfo.getTcpStateName(1)); + assertEquals(TCP_SYN_SENT, TcpInfo.getTcpStateName(2)); + assertEquals(UNKNOWN_20, TcpInfo.getTcpStateName(20)); } private static final String MALFORMED_TCP_INFO_HEX = @@ -166,12 +179,8 @@ @Test public void testMalformedTcpInfo() { final ByteBuffer buffer = ByteBuffer.wrap(MALFORMED_TCP_INFO_BYTES); - - TcpInfo parsedInfo = TcpInfo.parse(buffer, SHORT_TEST_TCP_INFO); - assertEquals(parsedInfo, null); - - parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1); - assertEquals(parsedInfo, null); + assertNull(TcpInfo.parse(buffer, SHORT_TEST_TCP_INFO)); + assertNull(TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1)); } // Make a TcpInfo contains only first 8 bytes.
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java index 4cf6f34..cd948b3 100644 --- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -76,6 +76,7 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.after; @@ -550,8 +551,8 @@ return null; } }).when(mCleartextDnsNetwork).openConnection(any()); - doReturn(new ArrayMap<>()).when(mHttpConnection).getRequestProperties(); - doReturn(new ArrayMap<>()).when(mHttpsConnection).getRequestProperties(); + initHttpConnection(mHttpConnection); + initHttpConnection(mHttpsConnection); mFakeDns = new FakeDns(); mFakeDns.startMocking(); @@ -608,6 +609,18 @@ } } + private void initHttpConnection(HttpURLConnection connection) { + doReturn(new ArrayMap<>()).when(connection).getRequestProperties(); + // Explicitly set the HttpURLConnection methods so that these will not interact with real + // methods to prevent threading issue in the test. + doReturn(new HashMap<>()).when(connection).getHeaderFields(); + doNothing().when(connection).setInstanceFollowRedirects(anyBoolean()); + doNothing().when(connection).setConnectTimeout(anyInt()); + doNothing().when(connection).setReadTimeout(anyInt()); + doNothing().when(connection).setRequestProperty(any(), any()); + doNothing().when(connection).setUseCaches(anyBoolean()); + } + private void initCallbacks(int interfaceVersion) throws Exception { try { doReturn(interfaceVersion).when(mCallbacks).getInterfaceVersion();