Merge changes I53ca4b98,I1757fdeb am: 3a463815e2
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1440767 Change-Id: If1d0eb5a1818dd7a9346f8d0d64d5f37ea1b53c2
This commit is contained in:
@@ -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.OffloadCallbackEvent;
|
||||
import android.net.netlink.NetlinkSocket;
|
||||
import android.net.netlink.StructNfGenMsg;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.net.util.SharedLog;
|
||||
import android.net.util.SocketUtils;
|
||||
@@ -41,11 +42,12 @@ import android.system.OsConstants;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@@ -66,11 +68,12 @@ public class OffloadHardwareInterface {
|
||||
private static final String NO_IPV4_ADDRESS = "";
|
||||
private static final String NO_IPV4_GATEWAY = "";
|
||||
// Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
|
||||
private static final int NF_NETLINK_CONNTRACK_NEW = 1;
|
||||
private static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
|
||||
private static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
|
||||
public static final int NF_NETLINK_CONNTRACK_NEW = 1;
|
||||
public static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
|
||||
public static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
|
||||
// Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
|
||||
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;
|
||||
|
||||
private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
|
||||
@@ -237,7 +240,7 @@ public class OffloadHardwareInterface {
|
||||
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
|
||||
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));
|
||||
|
||||
final NativeHandle h2 = mDeps.createConntrackSocket(
|
||||
@@ -267,16 +270,23 @@ public class OffloadHardwareInterface {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) {
|
||||
final int length = StructNlMsgHdr.STRUCT_SIZE;
|
||||
public void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) {
|
||||
final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
|
||||
final byte[] msg = new byte[length];
|
||||
final StructNlMsgHdr nlh = new StructNlMsgHdr();
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
final StructNlMsgHdr nlh = new StructNlMsgHdr();
|
||||
nlh.nlmsg_len = length;
|
||||
nlh.nlmsg_type = type;
|
||||
nlh.nlmsg_flags = flags;
|
||||
nlh.nlmsg_seq = 1;
|
||||
nlh.nlmsg_seq = 0;
|
||||
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 {
|
||||
NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
|
||||
NETLINK_MESSAGE_TIMEOUT_MS);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,9 @@
|
||||
package com.android.networkstack.tethering;
|
||||
|
||||
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.SOCK_STREAM;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
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.NetworkProtocol;
|
||||
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
||||
import android.net.netlink.StructNfGenMsg;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.net.util.SharedLog;
|
||||
import android.os.Handler;
|
||||
import android.os.NativeHandle;
|
||||
import android.os.test.TestLooper;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.OsConstants;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
@@ -55,8 +57,8 @@ import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -218,7 +220,7 @@ public final class OffloadHardwareInterfaceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetlinkMessage() throws Exception {
|
||||
public void testSendIpv4NfGenMsg() throws Exception {
|
||||
FileDescriptor writeSocket = new FileDescriptor();
|
||||
FileDescriptor readSocket = new FileDescriptor();
|
||||
try {
|
||||
@@ -229,17 +231,25 @@ public final class OffloadHardwareInterfaceTest {
|
||||
}
|
||||
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);
|
||||
final int expectedLen = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
|
||||
assertEquals(expectedLen, read);
|
||||
|
||||
buffer.flip();
|
||||
assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
|
||||
assertEquals(expectedLen, buffer.getInt());
|
||||
assertEquals(TEST_TYPE, buffer.getShort());
|
||||
assertEquals(TEST_FLAGS, buffer.getShort());
|
||||
assertEquals(1 /* seq */, buffer.getInt());
|
||||
assertEquals(0 /* seq */, 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) {
|
||||
|
||||
Reference in New Issue
Block a user