Merge changes I40c22e2f,Id189676b,I9fb3be17,I63ca1668,I208bcd3f, ... into mainline-prod
* changes: Add shared jarjar rule for tethering tests Remove unused testutils lib from tethering tests Fix OffloadHardwareInterfaceTest. tethering: offload: Netlink Req NfGen tethering: DAD Proxy Daemon Add tethering privileged test
This commit is contained in:
committed by
Android (Google) Code Review
commit
38b7e2b257
@@ -17,17 +17,62 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <error.h>
|
#include <error.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
#include <nativehelper/JNIHelp.h>
|
#include <nativehelper/JNIHelp.h>
|
||||||
#include <nativehelper/ScopedUtfChars.h>
|
#include <nativehelper/ScopedUtfChars.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <netinet/ether.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
#include <netinet/icmp6.h>
|
#include <netinet/icmp6.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define LOG_TAG "TetheringUtils"
|
#define LOG_TAG "TetheringUtils"
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
|
static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt);
|
||||||
|
static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr);
|
||||||
|
static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
|
||||||
|
|
||||||
|
static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32_t type) {
|
||||||
|
sock_filter filter_code[] = {
|
||||||
|
// Check header is ICMPv6.
|
||||||
|
BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeaderOffset),
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
|
||||||
|
|
||||||
|
// Check ICMPv6 type.
|
||||||
|
BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, type, 0, 1),
|
||||||
|
|
||||||
|
// Accept or reject.
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, 0xffff),
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
const sock_fprog filter = {
|
||||||
|
sizeof(filter_code) / sizeof(filter_code[0]),
|
||||||
|
filter_code,
|
||||||
|
};
|
||||||
|
|
||||||
|
int fd = jniGetFDFromFileDescriptor(env, javaFd);
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
|
||||||
|
jniThrowExceptionFmt(env, "java/net/SocketException",
|
||||||
|
"setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void android_net_util_setupNaSocket(JNIEnv *env, jobject clazz, jobject javaFd)
|
||||||
|
{
|
||||||
|
android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_ADVERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void android_net_util_setupNsSocket(JNIEnv *env, jobject clazz, jobject javaFd)
|
||||||
|
{
|
||||||
|
android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_SOLICIT);
|
||||||
|
}
|
||||||
|
|
||||||
static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
|
static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
|
||||||
jint ifIndex)
|
jint ifIndex)
|
||||||
{
|
{
|
||||||
@@ -124,7 +169,12 @@ static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject j
|
|||||||
*/
|
*/
|
||||||
static const JNINativeMethod gMethods[] = {
|
static const JNINativeMethod gMethods[] = {
|
||||||
/* name, signature, funcPtr */
|
/* name, signature, funcPtr */
|
||||||
{ "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket },
|
{ "setupNaSocket", "(Ljava/io/FileDescriptor;)V",
|
||||||
|
(void*) android_net_util_setupNaSocket },
|
||||||
|
{ "setupNsSocket", "(Ljava/io/FileDescriptor;)V",
|
||||||
|
(void*) android_net_util_setupNsSocket },
|
||||||
|
{ "setupRaSocket", "(Ljava/io/FileDescriptor;I)V",
|
||||||
|
(void*) android_net_util_setupRaSocket },
|
||||||
};
|
};
|
||||||
|
|
||||||
int register_android_net_util_TetheringUtils(JNIEnv* env) {
|
int register_android_net_util_TetheringUtils(JNIEnv* env) {
|
||||||
|
|||||||
54
Tethering/src/android/net/ip/DadProxy.java
Normal file
54
Tethering/src/android/net/ip/DadProxy.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.ip;
|
||||||
|
|
||||||
|
import android.net.util.InterfaceParams;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic Duplicate address detection proxy.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class DadProxy {
|
||||||
|
private static final String TAG = DadProxy.class.getSimpleName();
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public static NeighborPacketForwarder naForwarder;
|
||||||
|
public static NeighborPacketForwarder nsForwarder;
|
||||||
|
|
||||||
|
public DadProxy(Handler h, InterfaceParams tetheredIface) {
|
||||||
|
naForwarder = new NeighborPacketForwarder(h, tetheredIface,
|
||||||
|
NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
|
||||||
|
nsForwarder = new NeighborPacketForwarder(h, tetheredIface,
|
||||||
|
NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stop NS/NA Forwarders. */
|
||||||
|
public void stop() {
|
||||||
|
naForwarder.stop();
|
||||||
|
nsForwarder.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set upstream iface on both forwarders. */
|
||||||
|
public void setUpstreamIface(InterfaceParams upstreamIface) {
|
||||||
|
naForwarder.setUpstreamIface(upstreamIface);
|
||||||
|
nsForwarder.setUpstreamIface(upstreamIface);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,6 +51,7 @@ import android.net.util.InterfaceParams;
|
|||||||
import android.net.util.InterfaceSet;
|
import android.net.util.InterfaceSet;
|
||||||
import android.net.util.PrefixUtils;
|
import android.net.util.PrefixUtils;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
@@ -160,6 +161,15 @@ public class IpServer extends StateMachine {
|
|||||||
|
|
||||||
/** Capture IpServer dependencies, for injection. */
|
/** Capture IpServer dependencies, for injection. */
|
||||||
public abstract static class Dependencies {
|
public abstract static class Dependencies {
|
||||||
|
/**
|
||||||
|
* Create a DadProxy instance to be used by IpServer.
|
||||||
|
* To support multiple tethered interfaces concurrently DAD Proxy
|
||||||
|
* needs to be supported per IpServer instead of per upstream.
|
||||||
|
*/
|
||||||
|
public DadProxy getDadProxy(Handler handler, InterfaceParams ifParams) {
|
||||||
|
return new DadProxy(handler, ifParams);
|
||||||
|
}
|
||||||
|
|
||||||
/** Create an IpNeighborMonitor to be used by this IpServer */
|
/** Create an IpNeighborMonitor to be used by this IpServer */
|
||||||
public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log,
|
public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log,
|
||||||
IpNeighborMonitor.NeighborEventConsumer consumer) {
|
IpNeighborMonitor.NeighborEventConsumer consumer) {
|
||||||
@@ -256,6 +266,7 @@ public class IpServer extends StateMachine {
|
|||||||
// Advertisements (otherwise, we do not add them to mLinkProperties at all).
|
// Advertisements (otherwise, we do not add them to mLinkProperties at all).
|
||||||
private LinkProperties mLastIPv6LinkProperties;
|
private LinkProperties mLastIPv6LinkProperties;
|
||||||
private RouterAdvertisementDaemon mRaDaemon;
|
private RouterAdvertisementDaemon mRaDaemon;
|
||||||
|
private DadProxy mDadProxy;
|
||||||
|
|
||||||
// To be accessed only on the handler thread
|
// To be accessed only on the handler thread
|
||||||
private int mDhcpServerStartIndex = 0;
|
private int mDhcpServerStartIndex = 0;
|
||||||
@@ -674,6 +685,13 @@ public class IpServer extends StateMachine {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use ShimUtils instead of explicitly checking the version here.
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R || "S".equals(Build.VERSION.CODENAME)
|
||||||
|
|| "T".equals(Build.VERSION.CODENAME)) {
|
||||||
|
// DAD Proxy starts forwarding packets after IPv6 upstream is present.
|
||||||
|
mDadProxy = mDeps.getDadProxy(getHandler(), mInterfaceParams);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,6 +703,11 @@ public class IpServer extends StateMachine {
|
|||||||
mRaDaemon.stop();
|
mRaDaemon.stop();
|
||||||
mRaDaemon = null;
|
mRaDaemon = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mDadProxy != null) {
|
||||||
|
mDadProxy.stop();
|
||||||
|
mDadProxy = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
|
// IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
|
||||||
@@ -702,11 +725,16 @@ public class IpServer extends StateMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RaParams params = null;
|
RaParams params = null;
|
||||||
int upstreamIfindex = 0;
|
String upstreamIface = null;
|
||||||
|
InterfaceParams upstreamIfaceParams = null;
|
||||||
|
int upstreamIfIndex = 0;
|
||||||
|
|
||||||
if (v6only != null) {
|
if (v6only != null) {
|
||||||
final String upstreamIface = v6only.getInterfaceName();
|
upstreamIface = v6only.getInterfaceName();
|
||||||
|
upstreamIfaceParams = mDeps.getInterfaceParams(upstreamIface);
|
||||||
|
if (upstreamIfaceParams != null) {
|
||||||
|
upstreamIfIndex = upstreamIfaceParams.index;
|
||||||
|
}
|
||||||
params = new RaParams();
|
params = new RaParams();
|
||||||
params.mtu = v6only.getMtu();
|
params.mtu = v6only.getMtu();
|
||||||
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
|
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
|
||||||
@@ -726,15 +754,13 @@ public class IpServer extends StateMachine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
upstreamIfindex = mDeps.getIfindex(upstreamIface);
|
|
||||||
|
|
||||||
// Add upstream index to name mapping for the tether stats usage in the coordinator.
|
// Add upstream index to name mapping for the tether stats usage in the coordinator.
|
||||||
// Although this mapping could be added by both class Tethering and IpServer, adding
|
// Although this mapping could be added by both class Tethering and IpServer, adding
|
||||||
// mapping from IpServer guarantees that the mapping is added before the adding
|
// mapping from IpServer guarantees that the mapping is added before the adding
|
||||||
// forwarding rules. That is because there are different state machines in both
|
// forwarding rules. That is because there are different state machines in both
|
||||||
// classes. It is hard to guarantee the link property update order between multiple
|
// classes. It is hard to guarantee the link property update order between multiple
|
||||||
// state machines.
|
// state machines.
|
||||||
mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface);
|
mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfIndex, upstreamIface);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If v6only is null, we pass in null to setRaParams(), which handles
|
// If v6only is null, we pass in null to setRaParams(), which handles
|
||||||
@@ -743,8 +769,11 @@ public class IpServer extends StateMachine {
|
|||||||
setRaParams(params);
|
setRaParams(params);
|
||||||
mLastIPv6LinkProperties = v6only;
|
mLastIPv6LinkProperties = v6only;
|
||||||
|
|
||||||
updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfindex, null);
|
updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null);
|
||||||
mLastIPv6UpstreamIfindex = upstreamIfindex;
|
mLastIPv6UpstreamIfindex = upstreamIfIndex;
|
||||||
|
if (mDadProxy != null) {
|
||||||
|
mDadProxy.setUpstreamIface(upstreamIfaceParams);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeRoutesFromLocalNetwork(@NonNull final List<RouteInfo> toBeRemoved) {
|
private void removeRoutesFromLocalNetwork(@NonNull final List<RouteInfo> toBeRemoved) {
|
||||||
|
|||||||
180
Tethering/src/android/net/ip/NeighborPacketForwarder.java
Normal file
180
Tethering/src/android/net/ip/NeighborPacketForwarder.java
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.ip;
|
||||||
|
|
||||||
|
import static android.system.OsConstants.AF_INET6;
|
||||||
|
import static android.system.OsConstants.AF_PACKET;
|
||||||
|
import static android.system.OsConstants.ETH_P_IPV6;
|
||||||
|
import static android.system.OsConstants.IPPROTO_RAW;
|
||||||
|
import static android.system.OsConstants.SOCK_DGRAM;
|
||||||
|
import static android.system.OsConstants.SOCK_NONBLOCK;
|
||||||
|
import static android.system.OsConstants.SOCK_RAW;
|
||||||
|
|
||||||
|
import android.net.util.InterfaceParams;
|
||||||
|
import android.net.util.PacketReader;
|
||||||
|
import android.net.util.SocketUtils;
|
||||||
|
import android.net.util.TetheringUtils;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.Os;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic IPv6 Neighbor Advertisement Forwarder.
|
||||||
|
*
|
||||||
|
* Forward NA packets from upstream iface to tethered iface
|
||||||
|
* and NS packets from tethered iface to upstream iface.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class NeighborPacketForwarder extends PacketReader {
|
||||||
|
private final String mTag;
|
||||||
|
|
||||||
|
private FileDescriptor mFd;
|
||||||
|
|
||||||
|
// TODO: get these from NetworkStackConstants.
|
||||||
|
private static final int IPV6_ADDR_LEN = 16;
|
||||||
|
private static final int IPV6_DST_ADDR_OFFSET = 24;
|
||||||
|
private static final int IPV6_HEADER_LEN = 40;
|
||||||
|
private static final int ETH_HEADER_LEN = 14;
|
||||||
|
|
||||||
|
private InterfaceParams mListenIfaceParams, mSendIfaceParams;
|
||||||
|
|
||||||
|
private final int mType;
|
||||||
|
public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
|
||||||
|
public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
|
||||||
|
|
||||||
|
public NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type) {
|
||||||
|
super(h);
|
||||||
|
mTag = NeighborPacketForwarder.class.getSimpleName() + "-"
|
||||||
|
+ tetheredInterface.name + "-" + type;
|
||||||
|
mType = type;
|
||||||
|
|
||||||
|
if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
|
||||||
|
mSendIfaceParams = tetheredInterface;
|
||||||
|
} else {
|
||||||
|
mListenIfaceParams = tetheredInterface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set new upstream iface and start/stop based on new params. */
|
||||||
|
public void setUpstreamIface(InterfaceParams upstreamParams) {
|
||||||
|
final InterfaceParams oldUpstreamParams;
|
||||||
|
|
||||||
|
if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
|
||||||
|
oldUpstreamParams = mListenIfaceParams;
|
||||||
|
mListenIfaceParams = upstreamParams;
|
||||||
|
} else {
|
||||||
|
oldUpstreamParams = mSendIfaceParams;
|
||||||
|
mSendIfaceParams = upstreamParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldUpstreamParams == null && upstreamParams != null) {
|
||||||
|
start();
|
||||||
|
} else if (oldUpstreamParams != null && upstreamParams == null) {
|
||||||
|
stop();
|
||||||
|
} else if (oldUpstreamParams != null && upstreamParams != null
|
||||||
|
&& oldUpstreamParams.index != upstreamParams.index) {
|
||||||
|
stop();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: move NetworkStackUtils.closeSocketQuietly to
|
||||||
|
// frameworks/libs/net/common/device/com/android/net/module/util/[someclass].
|
||||||
|
private void closeSocketQuietly(FileDescriptor fd) {
|
||||||
|
try {
|
||||||
|
SocketUtils.closeSocket(fd);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FileDescriptor createFd() {
|
||||||
|
try {
|
||||||
|
// ICMPv6 packets from modem do not have eth header, so RAW socket cannot be used.
|
||||||
|
// To keep uniformity in both directions PACKET socket can be used.
|
||||||
|
mFd = Os.socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
||||||
|
|
||||||
|
// TODO: convert setup*Socket to setupICMPv6BpfFilter with filter type?
|
||||||
|
if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
|
||||||
|
TetheringUtils.setupNaSocket(mFd);
|
||||||
|
} else if (mType == ICMPV6_NEIGHBOR_SOLICITATION) {
|
||||||
|
TetheringUtils.setupNsSocket(mFd);
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketAddress bindAddress = SocketUtils.makePacketSocketAddress(
|
||||||
|
ETH_P_IPV6, mListenIfaceParams.index);
|
||||||
|
Os.bind(mFd, bindAddress);
|
||||||
|
} catch (ErrnoException | SocketException e) {
|
||||||
|
Log.wtf(mTag, "Failed to create socket", e);
|
||||||
|
closeSocketQuietly(mFd);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Inet6Address getIpv6DestinationAddress(byte[] recvbuf) {
|
||||||
|
Inet6Address dstAddr;
|
||||||
|
try {
|
||||||
|
dstAddr = (Inet6Address) Inet6Address.getByAddress(Arrays.copyOfRange(recvbuf,
|
||||||
|
IPV6_DST_ADDR_OFFSET, IPV6_DST_ADDR_OFFSET + IPV6_ADDR_LEN));
|
||||||
|
} catch (UnknownHostException | ClassCastException impossible) {
|
||||||
|
throw new AssertionError("16-byte array not valid IPv6 address?");
|
||||||
|
}
|
||||||
|
return dstAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handlePacket(byte[] recvbuf, int length) {
|
||||||
|
if (mSendIfaceParams == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The BPF filter should already have checked the length of the packet, but...
|
||||||
|
if (length < IPV6_HEADER_LEN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Inet6Address destv6 = getIpv6DestinationAddress(recvbuf);
|
||||||
|
if (!destv6.isMulticastAddress()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InetSocketAddress dest = new InetSocketAddress(destv6, 0);
|
||||||
|
|
||||||
|
FileDescriptor fd = null;
|
||||||
|
try {
|
||||||
|
fd = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW);
|
||||||
|
SocketUtils.bindSocketToInterface(fd, mSendIfaceParams.name);
|
||||||
|
|
||||||
|
int ret = Os.sendto(fd, recvbuf, 0, length, 0, dest);
|
||||||
|
} catch (ErrnoException | SocketException e) {
|
||||||
|
Log.e(mTag, "handlePacket error: " + e);
|
||||||
|
} finally {
|
||||||
|
closeSocketQuietly(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ package android.net.ip;
|
|||||||
|
|
||||||
import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
|
import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
|
||||||
import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
|
import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
|
||||||
|
import static android.net.util.TetheringUtils.getAllNodesForScopeId;
|
||||||
import static android.system.OsConstants.AF_INET6;
|
import static android.system.OsConstants.AF_INET6;
|
||||||
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
||||||
import static android.system.OsConstants.SOCK_RAW;
|
import static android.system.OsConstants.SOCK_RAW;
|
||||||
@@ -44,7 +45,6 @@ import java.net.Inet6Address;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.nio.BufferOverflowException;
|
import java.nio.BufferOverflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
@@ -92,10 +92,6 @@ public class RouterAdvertisementDaemon {
|
|||||||
|
|
||||||
private static final int DAY_IN_SECONDS = 86_400;
|
private static final int DAY_IN_SECONDS = 86_400;
|
||||||
|
|
||||||
private static final byte[] ALL_NODES = new byte[] {
|
|
||||||
(byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
|
||||||
};
|
|
||||||
|
|
||||||
private final InterfaceParams mInterface;
|
private final InterfaceParams mInterface;
|
||||||
private final InetSocketAddress mAllNodes;
|
private final InetSocketAddress mAllNodes;
|
||||||
|
|
||||||
@@ -240,7 +236,6 @@ public class RouterAdvertisementDaemon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public RouterAdvertisementDaemon(InterfaceParams ifParams) {
|
public RouterAdvertisementDaemon(InterfaceParams ifParams) {
|
||||||
mInterface = ifParams;
|
mInterface = ifParams;
|
||||||
mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
|
mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
|
||||||
@@ -363,15 +358,6 @@ public class RouterAdvertisementDaemon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Inet6Address getAllNodesForScopeId(int scopeId) {
|
|
||||||
try {
|
|
||||||
return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
|
|
||||||
} catch (UnknownHostException uhe) {
|
|
||||||
Log.wtf(TAG, "Failed to construct ff02::1 InetAddress: " + uhe);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte asByte(int value) {
|
private static byte asByte(int value) {
|
||||||
return (byte) value;
|
return (byte) value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,15 @@ package android.net.util;
|
|||||||
|
|
||||||
import android.net.TetherStatsParcel;
|
import android.net.TetherStatsParcel;
|
||||||
import android.net.TetheringRequestParcel;
|
import android.net.TetheringRequestParcel;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +34,24 @@ import java.util.Objects;
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public class TetheringUtils {
|
public class TetheringUtils {
|
||||||
|
public static final byte[] ALL_NODES = new byte[] {
|
||||||
|
(byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures a socket for receiving and sending ICMPv6 neighbor advertisments.
|
||||||
|
* @param fd the socket's {@link FileDescriptor}.
|
||||||
|
*/
|
||||||
|
public static native void setupNaSocket(FileDescriptor fd)
|
||||||
|
throws SocketException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures a socket for receiving and sending ICMPv6 neighbor solicitations.
|
||||||
|
* @param fd the socket's {@link FileDescriptor}.
|
||||||
|
*/
|
||||||
|
public static native void setupNsSocket(FileDescriptor fd)
|
||||||
|
throws SocketException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The object which records offload Tx/Rx forwarded bytes/packets.
|
* The object which records offload Tx/Rx forwarded bytes/packets.
|
||||||
* TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
|
* TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
|
||||||
@@ -129,4 +151,15 @@ public class TetheringUtils {
|
|||||||
&& request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
|
&& request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
|
||||||
&& request.showProvisioningUi == otherRequest.showProvisioningUi;
|
&& request.showProvisioningUi == otherRequest.showProvisioningUi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get inet6 address for all nodes given scope ID. */
|
||||||
|
public static Inet6Address getAllNodesForScopeId(int scopeId) {
|
||||||
|
try {
|
||||||
|
return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
|
||||||
|
} catch (UnknownHostException uhe) {
|
||||||
|
Log.wtf("TetheringUtils", "Failed to construct Inet6Address from "
|
||||||
|
+ Arrays.toString(ALL_NODES) + " and scopedId " + scopeId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
|||||||
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
||||||
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
||||||
import android.net.netlink.NetlinkSocket;
|
import android.net.netlink.NetlinkSocket;
|
||||||
|
import android.net.netlink.StructNfGenMsg;
|
||||||
import android.net.netlink.StructNlMsgHdr;
|
import android.net.netlink.StructNlMsgHdr;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
import android.net.util.SocketUtils;
|
import android.net.util.SocketUtils;
|
||||||
@@ -41,11 +42,12 @@ import android.system.OsConstants;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
@@ -66,11 +68,12 @@ public class OffloadHardwareInterface {
|
|||||||
private static final String NO_IPV4_ADDRESS = "";
|
private static final String NO_IPV4_ADDRESS = "";
|
||||||
private static final String NO_IPV4_GATEWAY = "";
|
private static final String NO_IPV4_GATEWAY = "";
|
||||||
// Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
|
// Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
|
||||||
private static final int NF_NETLINK_CONNTRACK_NEW = 1;
|
public static final int NF_NETLINK_CONNTRACK_NEW = 1;
|
||||||
private static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
|
public static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
|
||||||
private static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
|
public static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
|
||||||
// Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
|
// Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
|
||||||
public static final short NFNL_SUBSYS_CTNETLINK = 1;
|
public static final short NFNL_SUBSYS_CTNETLINK = 1;
|
||||||
|
public static final short IPCTNL_MSG_CT_NEW = 0;
|
||||||
public static final short IPCTNL_MSG_CT_GET = 1;
|
public static final short IPCTNL_MSG_CT_GET = 1;
|
||||||
|
|
||||||
private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
|
private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
|
||||||
@@ -237,7 +240,7 @@ public class OffloadHardwareInterface {
|
|||||||
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
|
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
|
||||||
if (h1 == null) return false;
|
if (h1 == null) return false;
|
||||||
|
|
||||||
sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
|
sendIpv4NfGenMsg(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
|
||||||
(short) (NLM_F_REQUEST | NLM_F_DUMP));
|
(short) (NLM_F_REQUEST | NLM_F_DUMP));
|
||||||
|
|
||||||
final NativeHandle h2 = mDeps.createConntrackSocket(
|
final NativeHandle h2 = mDeps.createConntrackSocket(
|
||||||
@@ -267,16 +270,23 @@ public class OffloadHardwareInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) {
|
public void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) {
|
||||||
final int length = StructNlMsgHdr.STRUCT_SIZE;
|
final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
|
||||||
final byte[] msg = new byte[length];
|
final byte[] msg = new byte[length];
|
||||||
final StructNlMsgHdr nlh = new StructNlMsgHdr();
|
|
||||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
|
final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
|
||||||
|
byteBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
|
final StructNlMsgHdr nlh = new StructNlMsgHdr();
|
||||||
nlh.nlmsg_len = length;
|
nlh.nlmsg_len = length;
|
||||||
nlh.nlmsg_type = type;
|
nlh.nlmsg_type = type;
|
||||||
nlh.nlmsg_flags = flags;
|
nlh.nlmsg_flags = flags;
|
||||||
nlh.nlmsg_seq = 1;
|
nlh.nlmsg_seq = 0;
|
||||||
nlh.pack(byteBuffer);
|
nlh.pack(byteBuffer);
|
||||||
|
|
||||||
|
// Header needs to be added to buffer since a generic netlink request is being sent.
|
||||||
|
final StructNfGenMsg nfh = new StructNfGenMsg((byte) OsConstants.AF_INET);
|
||||||
|
nfh.pack(byteBuffer);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
|
NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
|
||||||
NETLINK_MESSAGE_TIMEOUT_MS);
|
NETLINK_MESSAGE_TIMEOUT_MS);
|
||||||
|
|||||||
24
Tethering/tests/Android.bp
Normal file
24
Tethering/tests/Android.bp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Copyright (C) 2020 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
filegroup {
|
||||||
|
name: "TetheringTestsJarJarRules",
|
||||||
|
srcs: ["jarjar-rules.txt"],
|
||||||
|
visibility: [
|
||||||
|
"//frameworks/base/packages/Tethering/tests:__subpackages__",
|
||||||
|
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -22,7 +22,6 @@ java_defaults {
|
|||||||
static_libs: [
|
static_libs: [
|
||||||
"NetworkStackApiStableLib",
|
"NetworkStackApiStableLib",
|
||||||
"androidx.test.rules",
|
"androidx.test.rules",
|
||||||
"frameworks-base-testutils",
|
|
||||||
"mockito-target-extended-minus-junit4",
|
"mockito-target-extended-minus-junit4",
|
||||||
"net-tests-utils",
|
"net-tests-utils",
|
||||||
"testables",
|
"testables",
|
||||||
@@ -83,6 +82,7 @@ android_test {
|
|||||||
// For NetworkStackUtils included in NetworkStackBase
|
// For NetworkStackUtils included in NetworkStackBase
|
||||||
"libnetworkstackutilsjni",
|
"libnetworkstackutilsjni",
|
||||||
],
|
],
|
||||||
|
jarjar_rules: ":TetheringTestsJarJarRules",
|
||||||
compile_multilib: "both",
|
compile_multilib: "both",
|
||||||
manifest: "AndroidManifest_coverage.xml",
|
manifest: "AndroidManifest_coverage.xml",
|
||||||
}
|
}
|
||||||
@@ -9,3 +9,11 @@ rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.
|
|||||||
rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
|
rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
|
||||||
|
|
||||||
rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
|
rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
|
||||||
|
|
||||||
|
# Classes from net-utils-framework-common
|
||||||
|
rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1
|
||||||
|
|
||||||
|
# TODO: either stop using frameworks-base-testutils or remove the unit test classes it contains.
|
||||||
|
# TestableLooper from "testables" can be used instead of TestLooper from frameworks-base-testutils.
|
||||||
|
zap android.os.test.TestLooperTest*
|
||||||
|
zap com.android.test.filters.SelectTestTests*
|
||||||
49
Tethering/tests/privileged/Android.bp
Normal file
49
Tethering/tests/privileged/Android.bp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Copyright (C) 2020 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
java_defaults {
|
||||||
|
name: "TetheringPrivilegedTestsJniDefaults",
|
||||||
|
jni_libs: [
|
||||||
|
"libdexmakerjvmtiagent",
|
||||||
|
"libstaticjvmtiagent",
|
||||||
|
"libtetherutilsjni",
|
||||||
|
],
|
||||||
|
jni_uses_sdk_apis: true,
|
||||||
|
visibility: ["//visibility:private"],
|
||||||
|
}
|
||||||
|
|
||||||
|
android_test {
|
||||||
|
name: "TetheringPrivilegedTests",
|
||||||
|
defaults: [
|
||||||
|
"TetheringPrivilegedTestsJniDefaults",
|
||||||
|
],
|
||||||
|
srcs: [
|
||||||
|
"src/**/*.java",
|
||||||
|
"src/**/*.kt",
|
||||||
|
],
|
||||||
|
certificate: "networkstack",
|
||||||
|
platform_apis: true,
|
||||||
|
test_suites: [
|
||||||
|
"device-tests",
|
||||||
|
"mts",
|
||||||
|
],
|
||||||
|
static_libs: [
|
||||||
|
"androidx.test.rules",
|
||||||
|
"net-tests-utils",
|
||||||
|
"TetheringApiCurrentLib",
|
||||||
|
],
|
||||||
|
compile_multilib: "both",
|
||||||
|
}
|
||||||
32
Tethering/tests/privileged/AndroidManifest.xml
Normal file
32
Tethering/tests/privileged/AndroidManifest.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.networkstack.tethering.tests.privileged"
|
||||||
|
android:sharedUserId="android.uid.networkstack">
|
||||||
|
|
||||||
|
<!-- Note: do not add any privileged or signature permissions that are granted
|
||||||
|
to the network stack and its shared uid apps. Otherwise, the test APK will
|
||||||
|
install, but when the device is rebooted, it will bootloop because this
|
||||||
|
test APK is not in the privileged permission allow list -->
|
||||||
|
|
||||||
|
<application android:debuggable="true">
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
</application>
|
||||||
|
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
android:targetPackage="com.android.networkstack.tethering.tests.privileged"
|
||||||
|
android:label="Tethering privileged tests">
|
||||||
|
</instrumentation>
|
||||||
|
</manifest>
|
||||||
338
Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
Normal file
338
Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.ip;
|
||||||
|
|
||||||
|
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
||||||
|
import static android.system.OsConstants.IPPROTO_TCP;
|
||||||
|
|
||||||
|
import static com.android.internal.util.BitUtils.uint16;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.app.Instrumentation;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.INetd;
|
||||||
|
import android.net.InetAddresses;
|
||||||
|
import android.net.MacAddress;
|
||||||
|
import android.net.TestNetworkInterface;
|
||||||
|
import android.net.TestNetworkManager;
|
||||||
|
import android.net.util.InterfaceParams;
|
||||||
|
import android.net.util.IpUtils;
|
||||||
|
import android.net.util.TetheringUtils;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.Os;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.testutils.TapPacketReader;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class DadProxyTest {
|
||||||
|
private static final int DATA_BUFFER_LEN = 4096;
|
||||||
|
private static final int PACKET_TIMEOUT_MS = 5_000;
|
||||||
|
|
||||||
|
// TODO: make NetworkStackConstants accessible to this test and use the constant from there.
|
||||||
|
private static final int ETHER_SRC_ADDR_OFFSET = 6;
|
||||||
|
|
||||||
|
private DadProxy mProxy;
|
||||||
|
TestNetworkInterface mUpstreamTestIface, mTetheredTestIface;
|
||||||
|
private InterfaceParams mUpstreamParams, mTetheredParams;
|
||||||
|
private HandlerThread mHandlerThread;
|
||||||
|
private Handler mHandler;
|
||||||
|
private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader;
|
||||||
|
private FileDescriptor mUpstreamTapFd, mTetheredTapFd;
|
||||||
|
|
||||||
|
private static INetd sNetd;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setupOnce() {
|
||||||
|
System.loadLibrary("tetherutilsjni");
|
||||||
|
|
||||||
|
final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
|
||||||
|
final IBinder netdIBinder =
|
||||||
|
(IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE);
|
||||||
|
sNetd = INetd.Stub.asInterface(netdIBinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mHandlerThread = new HandlerThread(getClass().getSimpleName());
|
||||||
|
mHandlerThread.start();
|
||||||
|
mHandler = new Handler(mHandlerThread.getLooper());
|
||||||
|
|
||||||
|
setupTapInterfaces();
|
||||||
|
|
||||||
|
// Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
|
||||||
|
DadProxy mProxy = setupProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
if (mHandlerThread != null) {
|
||||||
|
mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket
|
||||||
|
mHandler.post(mTetheredPacketReader::stop); // Also closes the socket
|
||||||
|
mUpstreamTapFd = null;
|
||||||
|
mTetheredTapFd = null;
|
||||||
|
mHandlerThread.quitSafely();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTetheredParams != null) {
|
||||||
|
sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
|
||||||
|
}
|
||||||
|
if (mUpstreamParams != null) {
|
||||||
|
sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUpstreamTestIface != null) {
|
||||||
|
try {
|
||||||
|
Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor());
|
||||||
|
} catch (ErrnoException e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTetheredTestIface != null) {
|
||||||
|
try {
|
||||||
|
Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor());
|
||||||
|
} catch (ErrnoException e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestNetworkInterface setupTapInterface() {
|
||||||
|
final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
|
||||||
|
AtomicReference<TestNetworkInterface> iface = new AtomicReference<>();
|
||||||
|
|
||||||
|
inst.getUiAutomation().adoptShellPermissionIdentity();
|
||||||
|
try {
|
||||||
|
final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService(
|
||||||
|
Context.TEST_NETWORK_SERVICE);
|
||||||
|
iface.set(tnm.createTapInterface());
|
||||||
|
} finally {
|
||||||
|
inst.getUiAutomation().dropShellPermissionIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
return iface.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupTapInterfaces() {
|
||||||
|
// Create upstream test iface.
|
||||||
|
mUpstreamTestIface = setupTapInterface();
|
||||||
|
mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName());
|
||||||
|
assertNotNull(mUpstreamParams);
|
||||||
|
mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor();
|
||||||
|
mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd,
|
||||||
|
DATA_BUFFER_LEN);
|
||||||
|
mHandler.post(mUpstreamPacketReader::start);
|
||||||
|
|
||||||
|
// Create tethered test iface.
|
||||||
|
mTetheredTestIface = setupTapInterface();
|
||||||
|
mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName());
|
||||||
|
assertNotNull(mTetheredParams);
|
||||||
|
mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor();
|
||||||
|
mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd,
|
||||||
|
DATA_BUFFER_LEN);
|
||||||
|
mHandler.post(mTetheredPacketReader::start);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int IPV6_HEADER_LEN = 40;
|
||||||
|
private static final int ETH_HEADER_LEN = 14;
|
||||||
|
private static final int ICMPV6_NA_NS_LEN = 24;
|
||||||
|
private static final int LL_TARGET_OPTION_LEN = 8;
|
||||||
|
private static final int ICMPV6_CHECKSUM_OFFSET = 2;
|
||||||
|
private static final int ETHER_TYPE_IPV6 = 0x86dd;
|
||||||
|
|
||||||
|
// TODO: move the IpUtils code to frameworks/lib/net and link it statically.
|
||||||
|
private static int checksumFold(int sum) {
|
||||||
|
while (sum > 0xffff) {
|
||||||
|
sum = (sum >> 16) + (sum & 0xffff);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: move the IpUtils code to frameworks/lib/net and link it statically.
|
||||||
|
private static short checksumAdjust(short checksum, short oldWord, short newWord) {
|
||||||
|
checksum = (short) ~checksum;
|
||||||
|
int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord));
|
||||||
|
return (short) ~tempSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: move the IpUtils code to frameworks/lib/net and link it statically.
|
||||||
|
private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset,
|
||||||
|
int transportLen) {
|
||||||
|
// The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses
|
||||||
|
// 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental
|
||||||
|
// checksum adjustment for the change in the next header byte.
|
||||||
|
short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen);
|
||||||
|
return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteBuffer createDadPacket(int type) {
|
||||||
|
// Refer to buildArpPacket()
|
||||||
|
int icmpLen = ICMPV6_NA_NS_LEN
|
||||||
|
+ (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT
|
||||||
|
? LL_TARGET_OPTION_LEN : 0);
|
||||||
|
final ByteBuffer buf = ByteBuffer.allocate(icmpLen + IPV6_HEADER_LEN + ETH_HEADER_LEN);
|
||||||
|
|
||||||
|
// Ethernet header.
|
||||||
|
final MacAddress srcMac = MacAddress.fromString("33:33:ff:66:77:88");
|
||||||
|
buf.put(srcMac.toByteArray());
|
||||||
|
final MacAddress dstMac = MacAddress.fromString("01:02:03:04:05:06");
|
||||||
|
buf.put(dstMac.toByteArray());
|
||||||
|
buf.putShort((short) ETHER_TYPE_IPV6);
|
||||||
|
|
||||||
|
// IPv6 header
|
||||||
|
byte[] version = {(byte) 0x60, 0x00, 0x00, 0x00};
|
||||||
|
buf.put(version); // Version
|
||||||
|
buf.putShort((byte) icmpLen); // Length
|
||||||
|
buf.put((byte) IPPROTO_ICMPV6); // Next header
|
||||||
|
buf.put((byte) 0xff); // Hop limit
|
||||||
|
|
||||||
|
final byte[] target =
|
||||||
|
InetAddresses.parseNumericAddress("fe80::1122:3344:5566:7788").getAddress();
|
||||||
|
final byte[] src;
|
||||||
|
final byte[] dst;
|
||||||
|
if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION) {
|
||||||
|
src = InetAddresses.parseNumericAddress("::").getAddress();
|
||||||
|
dst = InetAddresses.parseNumericAddress("ff02::1:ff66:7788").getAddress();
|
||||||
|
} else {
|
||||||
|
src = target;
|
||||||
|
dst = TetheringUtils.ALL_NODES;
|
||||||
|
}
|
||||||
|
buf.put(src);
|
||||||
|
buf.put(dst);
|
||||||
|
|
||||||
|
// ICMPv6 Header
|
||||||
|
buf.put((byte) type); // Type
|
||||||
|
buf.put((byte) 0x00); // Code
|
||||||
|
buf.putShort((short) 0); // Checksum
|
||||||
|
buf.putInt(0); // Reserved
|
||||||
|
buf.put(target);
|
||||||
|
|
||||||
|
if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT) {
|
||||||
|
//NA packet has LL target address
|
||||||
|
//ICMPv6 Option
|
||||||
|
buf.put((byte) 0x02); // Type
|
||||||
|
buf.put((byte) 0x01); // Length
|
||||||
|
byte[] ll_target = MacAddress.fromString("01:02:03:04:05:06").toByteArray();
|
||||||
|
buf.put(ll_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate checksum field
|
||||||
|
final int transportOffset = ETH_HEADER_LEN + IPV6_HEADER_LEN;
|
||||||
|
final short checksum = icmpv6Checksum(buf, ETH_HEADER_LEN, transportOffset, icmpLen);
|
||||||
|
buf.putShort(transportOffset + ICMPV6_CHECKSUM_OFFSET, checksum);
|
||||||
|
|
||||||
|
buf.flip();
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DadProxy setupProxy() throws Exception {
|
||||||
|
DadProxy proxy = new DadProxy(mHandler, mTetheredParams);
|
||||||
|
mHandler.post(() -> proxy.setUpstreamIface(mUpstreamParams));
|
||||||
|
|
||||||
|
// Upstream iface is added to local network to simplify test case.
|
||||||
|
// Otherwise the test needs to create and destroy a network for the upstream iface.
|
||||||
|
sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
|
||||||
|
sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: change to assert.
|
||||||
|
private boolean waitForPacket(ByteBuffer packet, TapPacketReader reader) {
|
||||||
|
byte[] p;
|
||||||
|
|
||||||
|
while ((p = reader.popPacket(PACKET_TIMEOUT_MS)) != null) {
|
||||||
|
final ByteBuffer buffer = ByteBuffer.wrap(p);
|
||||||
|
|
||||||
|
if (buffer.compareTo(packet) == 0) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDstMac(ByteBuffer buf, MacAddress mac) {
|
||||||
|
buf.put(mac.toByteArray());
|
||||||
|
buf.rewind();
|
||||||
|
}
|
||||||
|
private void updateSrcMac(ByteBuffer buf, InterfaceParams ifaceParams) {
|
||||||
|
buf.position(ETHER_SRC_ADDR_OFFSET);
|
||||||
|
buf.put(ifaceParams.macAddr.toByteArray());
|
||||||
|
buf.rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNaForwardingFromUpstreamToTether() throws Exception {
|
||||||
|
ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
|
||||||
|
|
||||||
|
mUpstreamPacketReader.sendResponse(na);
|
||||||
|
updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
|
||||||
|
updateSrcMac(na, mTetheredParams);
|
||||||
|
assertTrue(waitForPacket(na, mTetheredPacketReader));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// TODO: remove test once DAD works in both directions.
|
||||||
|
public void testNaForwardingFromTetherToUpstream() throws Exception {
|
||||||
|
ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
|
||||||
|
|
||||||
|
mTetheredPacketReader.sendResponse(na);
|
||||||
|
updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
|
||||||
|
updateSrcMac(na, mTetheredParams);
|
||||||
|
assertFalse(waitForPacket(na, mUpstreamPacketReader));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNsForwardingFromTetherToUpstream() throws Exception {
|
||||||
|
ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
|
||||||
|
|
||||||
|
mTetheredPacketReader.sendResponse(ns);
|
||||||
|
updateSrcMac(ns, mUpstreamParams);
|
||||||
|
assertTrue(waitForPacket(ns, mUpstreamPacketReader));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// TODO: remove test once DAD works in both directions.
|
||||||
|
public void testNsForwardingFromUpstreamToTether() throws Exception {
|
||||||
|
ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
|
||||||
|
|
||||||
|
mUpstreamPacketReader.sendResponse(ns);
|
||||||
|
updateSrcMac(ns, mUpstreamParams);
|
||||||
|
assertFalse(waitForPacket(ns, mTetheredPacketReader));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.tethering;
|
||||||
|
|
||||||
|
import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
|
||||||
|
import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
|
||||||
|
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||||
|
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_GET;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_NEW;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.NFNL_SUBSYS_CTNETLINK;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_DESTROY;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_NEW;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.net.netlink.StructNlMsgHdr;
|
||||||
|
import android.net.util.SharedLog;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.NativeHandle;
|
||||||
|
import android.system.Os;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class ConntrackSocketTest {
|
||||||
|
private static final long TIMEOUT = 500;
|
||||||
|
|
||||||
|
private HandlerThread mHandlerThread;
|
||||||
|
private Handler mHandler;
|
||||||
|
private final SharedLog mLog = new SharedLog("privileged-test");
|
||||||
|
|
||||||
|
private OffloadHardwareInterface mOffloadHw;
|
||||||
|
private OffloadHardwareInterface.Dependencies mDeps;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mHandlerThread = new HandlerThread(getClass().getSimpleName());
|
||||||
|
mHandlerThread.start();
|
||||||
|
mHandler = new Handler(mHandlerThread.getLooper());
|
||||||
|
|
||||||
|
// Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
|
||||||
|
mDeps = new OffloadHardwareInterface.Dependencies(mLog);
|
||||||
|
mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIpv4ConntrackSocket() throws Exception {
|
||||||
|
// Set up server and connect.
|
||||||
|
final InetSocketAddress anyAddress = new InetSocketAddress(
|
||||||
|
InetAddress.getByName("127.0.0.1"), 0);
|
||||||
|
final ServerSocket serverSocket = new ServerSocket();
|
||||||
|
serverSocket.bind(anyAddress);
|
||||||
|
final SocketAddress theAddress = serverSocket.getLocalSocketAddress();
|
||||||
|
|
||||||
|
// Make a connection to the server.
|
||||||
|
final Socket socket = new Socket();
|
||||||
|
socket.connect(theAddress);
|
||||||
|
final Socket acceptedSocket = serverSocket.accept();
|
||||||
|
|
||||||
|
final NativeHandle handle = mDeps.createConntrackSocket(
|
||||||
|
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
|
||||||
|
mOffloadHw.sendIpv4NfGenMsg(handle,
|
||||||
|
(short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
|
||||||
|
(short) (NLM_F_REQUEST | NLM_F_DUMP));
|
||||||
|
|
||||||
|
boolean foundConntrackEntry = false;
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_RECV_BUFSIZE);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (Os.read(handle.getFileDescriptor(), buffer) > 0) {
|
||||||
|
buffer.flip();
|
||||||
|
|
||||||
|
// TODO: ConntrackMessage should get a parse API like StructNlMsgHdr
|
||||||
|
// so we can confirm that the conntrack added is for the TCP connection above.
|
||||||
|
final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(buffer);
|
||||||
|
assertNotNull(nlmsghdr);
|
||||||
|
|
||||||
|
// As long as 1 conntrack entry is found test case will pass, even if it's not
|
||||||
|
// the from the TCP connection above.
|
||||||
|
if (nlmsghdr.nlmsg_type == ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW)) {
|
||||||
|
foundConntrackEntry = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
socket.close();
|
||||||
|
serverSocket.close();
|
||||||
|
}
|
||||||
|
assertTrue("Did not receive any NFNL_SUBSYS_CTNETLINK/IPCTNL_MSG_CT_NEW message",
|
||||||
|
foundConntrackEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,7 +70,6 @@ java_defaults {
|
|||||||
"libdexmakerjvmtiagent",
|
"libdexmakerjvmtiagent",
|
||||||
"libstaticjvmtiagent",
|
"libstaticjvmtiagent",
|
||||||
],
|
],
|
||||||
jarjar_rules: "jarjar-rules.txt",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Library containing the unit tests. This is used by the coverage test target to pull in the
|
// Library containing the unit tests. This is used by the coverage test target to pull in the
|
||||||
@@ -91,6 +90,7 @@ android_test {
|
|||||||
"device-tests",
|
"device-tests",
|
||||||
"mts",
|
"mts",
|
||||||
],
|
],
|
||||||
|
jarjar_rules: ":TetheringTestsJarJarRules",
|
||||||
defaults: ["TetheringTestsDefaults"],
|
defaults: ["TetheringTestsDefaults"],
|
||||||
compile_multilib: "both",
|
compile_multilib: "both",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ import android.net.util.InterfaceParams;
|
|||||||
import android.net.util.InterfaceSet;
|
import android.net.util.InterfaceSet;
|
||||||
import android.net.util.PrefixUtils;
|
import android.net.util.PrefixUtils;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
@@ -101,8 +102,12 @@ import com.android.networkstack.tethering.BpfCoordinator;
|
|||||||
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
||||||
import com.android.networkstack.tethering.PrivateAddressCoordinator;
|
import com.android.networkstack.tethering.PrivateAddressCoordinator;
|
||||||
import com.android.networkstack.tethering.TetheringConfiguration;
|
import com.android.networkstack.tethering.TetheringConfiguration;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
@@ -121,6 +126,9 @@ import java.util.List;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public class IpServerTest {
|
public class IpServerTest {
|
||||||
|
@Rule
|
||||||
|
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
|
||||||
|
|
||||||
private static final String IFACE_NAME = "testnet1";
|
private static final String IFACE_NAME = "testnet1";
|
||||||
private static final String UPSTREAM_IFACE = "upstream0";
|
private static final String UPSTREAM_IFACE = "upstream0";
|
||||||
private static final String UPSTREAM_IFACE2 = "upstream1";
|
private static final String UPSTREAM_IFACE2 = "upstream1";
|
||||||
@@ -133,6 +141,11 @@ public class IpServerTest {
|
|||||||
|
|
||||||
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
|
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
|
||||||
IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
|
IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
|
||||||
|
private static final InterfaceParams UPSTREAM_IFACE_PARAMS = new InterfaceParams(
|
||||||
|
UPSTREAM_IFACE, UPSTREAM_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
|
||||||
|
private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams(
|
||||||
|
UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.ALL_ZEROS_ADDRESS,
|
||||||
|
1500 /* defaultMtu */);
|
||||||
|
|
||||||
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
|
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
|
||||||
|
|
||||||
@@ -143,6 +156,7 @@ public class IpServerTest {
|
|||||||
@Mock private IpServer.Callback mCallback;
|
@Mock private IpServer.Callback mCallback;
|
||||||
@Mock private SharedLog mSharedLog;
|
@Mock private SharedLog mSharedLog;
|
||||||
@Mock private IDhcpServer mDhcpServer;
|
@Mock private IDhcpServer mDhcpServer;
|
||||||
|
@Mock private DadProxy mDadProxy;
|
||||||
@Mock private RouterAdvertisementDaemon mRaDaemon;
|
@Mock private RouterAdvertisementDaemon mRaDaemon;
|
||||||
@Mock private IpNeighborMonitor mIpNeighborMonitor;
|
@Mock private IpNeighborMonitor mIpNeighborMonitor;
|
||||||
@Mock private IpServer.Dependencies mDependencies;
|
@Mock private IpServer.Dependencies mDependencies;
|
||||||
@@ -166,8 +180,11 @@ public class IpServerTest {
|
|||||||
|
|
||||||
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
|
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
|
||||||
boolean usingBpfOffload) throws Exception {
|
boolean usingBpfOffload) throws Exception {
|
||||||
|
when(mDependencies.getDadProxy(any(), any())).thenReturn(mDadProxy);
|
||||||
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
|
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
|
||||||
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
|
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
|
||||||
|
when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS);
|
||||||
|
when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2);
|
||||||
|
|
||||||
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX);
|
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX);
|
||||||
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2);
|
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2);
|
||||||
@@ -1107,4 +1124,78 @@ public class IpServerTest {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
public void dadProxyUpdates() throws Exception {
|
||||||
|
InOrder inOrder = inOrder(mDadProxy);
|
||||||
|
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
|
||||||
|
|
||||||
|
// Add an upstream without IPv6.
|
||||||
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(null);
|
||||||
|
|
||||||
|
// Add IPv6 to the upstream.
|
||||||
|
LinkProperties lp = new LinkProperties();
|
||||||
|
lp.setInterfaceName(UPSTREAM_IFACE);
|
||||||
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
|
||||||
|
|
||||||
|
// Change upstream.
|
||||||
|
// New linkproperties is needed, otherwise changing the iface has no impact.
|
||||||
|
LinkProperties lp2 = new LinkProperties();
|
||||||
|
lp2.setInterfaceName(UPSTREAM_IFACE2);
|
||||||
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp2, 0);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS2);
|
||||||
|
|
||||||
|
// Lose IPv6 on the upstream...
|
||||||
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, null, 0);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(null);
|
||||||
|
|
||||||
|
// ... and regain it on a different upstream.
|
||||||
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
|
||||||
|
|
||||||
|
// Lose upstream.
|
||||||
|
dispatchTetherConnectionChanged(null, null, 0);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(null);
|
||||||
|
|
||||||
|
// Regain upstream.
|
||||||
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
|
||||||
|
|
||||||
|
// Stop tethering.
|
||||||
|
mIpServer.stop();
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDadProxyEnabled(boolean expectEnabled) throws Exception {
|
||||||
|
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
|
||||||
|
InOrder inOrder = inOrder(mDadProxy);
|
||||||
|
// Add IPv6 to the upstream.
|
||||||
|
LinkProperties lp = new LinkProperties();
|
||||||
|
lp.setInterfaceName(UPSTREAM_IFACE);
|
||||||
|
if (expectEnabled) {
|
||||||
|
inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
|
||||||
|
} else {
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
}
|
||||||
|
// Stop tethering.
|
||||||
|
mIpServer.stop();
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
if (expectEnabled) {
|
||||||
|
inOrder.verify(mDadProxy).stop();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
verify(mDependencies, never()).getDadProxy(any(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test @IgnoreAfter(Build.VERSION_CODES.R)
|
||||||
|
public void testDadProxyUpdates_DisabledUpToR() throws Exception {
|
||||||
|
checkDadProxyEnabled(false);
|
||||||
|
}
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
public void testDadProxyUpdates_EnabledAfterR() throws Exception {
|
||||||
|
checkDadProxyEnabled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
package com.android.networkstack.tethering;
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
import static android.net.util.TetheringUtils.uint16;
|
import static android.net.util.TetheringUtils.uint16;
|
||||||
import static android.system.OsConstants.SOCK_STREAM;
|
import static android.system.OsConstants.AF_INET;
|
||||||
import static android.system.OsConstants.AF_UNIX;
|
import static android.system.OsConstants.AF_UNIX;
|
||||||
|
import static android.system.OsConstants.SOCK_STREAM;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -35,14 +36,15 @@ import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
|
|||||||
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
||||||
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
||||||
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
||||||
|
import android.net.netlink.StructNfGenMsg;
|
||||||
import android.net.netlink.StructNlMsgHdr;
|
import android.net.netlink.StructNlMsgHdr;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.NativeHandle;
|
import android.os.NativeHandle;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.OsConstants;
|
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
@@ -55,8 +57,8 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@@ -218,7 +220,7 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNetlinkMessage() throws Exception {
|
public void testSendIpv4NfGenMsg() throws Exception {
|
||||||
FileDescriptor writeSocket = new FileDescriptor();
|
FileDescriptor writeSocket = new FileDescriptor();
|
||||||
FileDescriptor readSocket = new FileDescriptor();
|
FileDescriptor readSocket = new FileDescriptor();
|
||||||
try {
|
try {
|
||||||
@@ -229,17 +231,25 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
}
|
}
|
||||||
when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
|
when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
|
||||||
|
|
||||||
mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS);
|
mOffloadHw.sendIpv4NfGenMsg(mNativeHandle, TEST_TYPE, TEST_FLAGS);
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(9823); // Arbitrary value > expectedLen.
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE);
|
|
||||||
int read = Os.read(readSocket, buffer);
|
int read = Os.read(readSocket, buffer);
|
||||||
|
final int expectedLen = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
|
||||||
|
assertEquals(expectedLen, read);
|
||||||
|
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
|
assertEquals(expectedLen, buffer.getInt());
|
||||||
assertEquals(TEST_TYPE, buffer.getShort());
|
assertEquals(TEST_TYPE, buffer.getShort());
|
||||||
assertEquals(TEST_FLAGS, buffer.getShort());
|
assertEquals(TEST_FLAGS, buffer.getShort());
|
||||||
assertEquals(1 /* seq */, buffer.getInt());
|
assertEquals(0 /* seq */, buffer.getInt());
|
||||||
assertEquals(0 /* pid */, buffer.getInt());
|
assertEquals(0 /* pid */, buffer.getInt());
|
||||||
|
assertEquals(AF_INET, buffer.get()); // nfgen_family
|
||||||
|
assertEquals(0 /* error */, buffer.get()); // version
|
||||||
|
assertEquals(0 /* error */, buffer.getShort()); // res_id
|
||||||
|
assertEquals(expectedLen, buffer.position());
|
||||||
}
|
}
|
||||||
|
|
||||||
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
|
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ import android.net.TetheringRequestParcel;
|
|||||||
import android.net.dhcp.DhcpServerCallbacks;
|
import android.net.dhcp.DhcpServerCallbacks;
|
||||||
import android.net.dhcp.DhcpServingParamsParcel;
|
import android.net.dhcp.DhcpServingParamsParcel;
|
||||||
import android.net.dhcp.IDhcpServer;
|
import android.net.dhcp.IDhcpServer;
|
||||||
|
import android.net.ip.DadProxy;
|
||||||
import android.net.ip.IpNeighborMonitor;
|
import android.net.ip.IpNeighborMonitor;
|
||||||
import android.net.ip.IpServer;
|
import android.net.ip.IpServer;
|
||||||
import android.net.ip.RouterAdvertisementDaemon;
|
import android.net.ip.RouterAdvertisementDaemon;
|
||||||
@@ -201,6 +202,7 @@ public class TetheringTest {
|
|||||||
@Mock private CarrierConfigManager mCarrierConfigManager;
|
@Mock private CarrierConfigManager mCarrierConfigManager;
|
||||||
@Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
@Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
||||||
@Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
|
@Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
|
||||||
|
@Mock private DadProxy mDadProxy;
|
||||||
@Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
|
@Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
|
||||||
@Mock private IpNeighborMonitor mIpNeighborMonitor;
|
@Mock private IpNeighborMonitor mIpNeighborMonitor;
|
||||||
@Mock private IDhcpServer mDhcpServer;
|
@Mock private IDhcpServer mDhcpServer;
|
||||||
@@ -285,6 +287,12 @@ public class TetheringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class MockIpServerDependencies extends IpServer.Dependencies {
|
public class MockIpServerDependencies extends IpServer.Dependencies {
|
||||||
|
@Override
|
||||||
|
public DadProxy getDadProxy(
|
||||||
|
Handler handler, InterfaceParams ifParams) {
|
||||||
|
return mDadProxy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
|
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
|
||||||
InterfaceParams ifParams) {
|
InterfaceParams ifParams) {
|
||||||
@@ -849,6 +857,7 @@ public class TetheringTest {
|
|||||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||||
|
|
||||||
sendIPv6TetherUpdates(upstreamState);
|
sendIPv6TetherUpdates(upstreamState);
|
||||||
|
verify(mDadProxy, never()).setUpstreamIface(notNull());
|
||||||
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
|
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
|
||||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
|
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
|
||||||
any(), any());
|
any(), any());
|
||||||
@@ -875,6 +884,8 @@ public class TetheringTest {
|
|||||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||||
|
|
||||||
sendIPv6TetherUpdates(upstreamState);
|
sendIPv6TetherUpdates(upstreamState);
|
||||||
|
// TODO: add interfaceParams to compare in verify.
|
||||||
|
verify(mDadProxy, times(1)).setUpstreamIface(notNull());
|
||||||
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
|
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
|
||||||
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
|
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
|
||||||
}
|
}
|
||||||
@@ -891,6 +902,7 @@ public class TetheringTest {
|
|||||||
any(), any());
|
any(), any());
|
||||||
|
|
||||||
sendIPv6TetherUpdates(upstreamState);
|
sendIPv6TetherUpdates(upstreamState);
|
||||||
|
verify(mDadProxy, times(1)).setUpstreamIface(notNull());
|
||||||
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
|
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
|
||||||
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
|
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
|
||||||
}
|
}
|
||||||
@@ -908,6 +920,7 @@ public class TetheringTest {
|
|||||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||||
|
|
||||||
sendIPv6TetherUpdates(upstreamState);
|
sendIPv6TetherUpdates(upstreamState);
|
||||||
|
verify(mDadProxy, times(1)).setUpstreamIface(notNull());
|
||||||
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
|
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
|
||||||
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
|
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user