Merge "tethering: offload: Netlink Req"
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index fe92204..33b9d00 100644
--- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -16,8 +16,11 @@
package com.android.networkstack.tethering;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import static android.net.util.TetheringUtils.uint16;
+import android.annotation.NonNull;
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
@@ -25,6 +28,7 @@
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.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.net.util.SocketUtils;
import android.os.Handler;
@@ -37,9 +41,11 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.NoSuchElementException;
@@ -63,6 +69,11 @@
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;
+ // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
+ public static final short NFNL_SUBSYS_CTNETLINK = 1;
+ public static final short IPCTNL_MSG_CT_GET = 1;
+
+ private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
private final Handler mHandler;
private final SharedLog mLog;
@@ -226,6 +237,9 @@
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
if (h1 == null) return false;
+ sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
+ (short) (NLM_F_REQUEST | NLM_F_DUMP));
+
final NativeHandle h2 = mDeps.createConntrackSocket(
NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
if (h2 == null) {
@@ -252,6 +266,25 @@
return results.mSuccess;
}
+ @VisibleForTesting
+ public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) {
+ final int length = StructNlMsgHdr.STRUCT_SIZE;
+ final byte[] msg = new byte[length];
+ final StructNlMsgHdr nlh = new StructNlMsgHdr();
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
+ nlh.nlmsg_len = length;
+ nlh.nlmsg_type = type;
+ nlh.nlmsg_flags = flags;
+ nlh.nlmsg_seq = 1;
+ nlh.pack(byteBuffer);
+ try {
+ NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
+ NETLINK_MESSAGE_TIMEOUT_MS);
+ } catch (ErrnoException | InterruptedIOException e) {
+ mLog.e("Unable to send netfilter message, error: " + e);
+ }
+ }
+
private void closeFdInNativeHandle(final NativeHandle h) {
try {
h.close();
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
index f8ff1cb..c543fad 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -17,13 +17,17 @@
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_UNIX;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
@@ -31,11 +35,14 @@
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.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 androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -47,6 +54,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.FileDescriptor;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
@RunWith(AndroidJUnit4.class)
@@ -64,6 +74,10 @@
@Mock private IOffloadControl mIOffloadControl;
@Mock private NativeHandle mNativeHandle;
+ // Random values to test Netlink message.
+ private static final short TEST_TYPE = 184;
+ private static final short TEST_FLAGS = 263;
+
class MyDependencies extends OffloadHardwareInterface.Dependencies {
MyDependencies(SharedLog log) {
super(log);
@@ -203,6 +217,31 @@
eq(uint16(udpParams.dst.port)));
}
+ @Test
+ public void testNetlinkMessage() throws Exception {
+ FileDescriptor writeSocket = new FileDescriptor();
+ FileDescriptor readSocket = new FileDescriptor();
+ try {
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, writeSocket, readSocket);
+ } catch (ErrnoException e) {
+ fail();
+ return;
+ }
+ when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
+
+ mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS);
+
+ ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE);
+ int read = Os.read(readSocket, buffer);
+
+ buffer.flip();
+ assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
+ assertEquals(TEST_TYPE, buffer.getShort());
+ assertEquals(TEST_FLAGS, buffer.getShort());
+ assertEquals(1 /* seq */, buffer.getInt());
+ assertEquals(0 /* pid */, buffer.getInt());
+ }
+
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
final NatTimeoutUpdate params = new NatTimeoutUpdate();
params.proto = proto;