From 4dd87aafc0062d455d5bf0aee7169d2c6b3b3039 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 21 Nov 2019 00:36:14 +0200 Subject: [PATCH 1/2] Tethering: Add WiGig support This change is a combination of following changes: 1) Tethering: add TETHERING_WIGIG type Currently both WIFI and WIGIG use the same tethering type, TETHERING_WIFI. This causes conflicts between the frameworks, when both WIFI and WIGIG SoftAPs are started, one or both will not work. Fix this by using a seperate tethering type for WIGIG. 2) Tethering: remove TETHERING_WIGIG state machine on interface down The wigig state machine relies on a TETHERING_STATE_CHANGED broadcast that is sent when the tethering state machine is first created, during interface up. Currently the tethering state machine is not removed on interface down except for TETHERING_BLUETOOTH, and as a result wigig tethering only works the first time SoftAP is started. In order to fix this, remove the tethering state machine on interface down for TETHERING_WIGIG as well. Bug: 143356416 Test: TetheringCoverageTests Change-Id: Ic4d3aca0ed69234093af7f0206dab3335938c52a Merged-In: Ic4d3aca0ed69234093af7f0206dab3335938c52a --- .../TetheringLib/src/android/net/TetheringManager.java | 8 ++++++++ Tethering/res/values/config.xml | 7 +++++++ Tethering/res/values/overlayable.xml | 1 + Tethering/src/android/net/ip/IpServer.java | 3 ++- .../src/com/android/networkstack/tethering/Tethering.java | 6 +++++- .../networkstack/tethering/TetheringConfiguration.java | 7 +++++++ 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index cc095a0bb4..4f053cb65c 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -171,6 +171,14 @@ public class TetheringManager { */ public static final int TETHERING_ETHERNET = 5; + /** + * WIGIG tethering type. Use a separate type to prevent + * conflicts with TETHERING_WIFI + * This type is only used internally by the tethering module + * @hide + */ + public static final int TETHERING_WIGIG = 6; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index 9269c6f0fd..9b9dcde910 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -42,6 +42,13 @@ "softap\\d" + + + "wigig\\d" + + diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml index 4e2bb1e31b..6a33d55cb0 100644 --- a/Tethering/res/values/overlayable.xml +++ b/Tethering/res/values/overlayable.xml @@ -20,6 +20,7 @@ + diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 35c156304c..8af1797a9d 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -617,7 +617,8 @@ public class IpServer extends StateMachine { final Boolean setIfaceUp; if (mInterfaceType == TetheringManager.TETHERING_WIFI || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P - || mInterfaceType == TetheringManager.TETHERING_ETHERNET) { + || mInterfaceType == TetheringManager.TETHERING_ETHERNET + || mInterfaceType == TetheringManager.TETHERING_WIGIG) { // The WiFi and Ethernet stack has ownership of the interface up/down state. // It is unclear whether the Bluetooth or USB stacks will manage their own // state. diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index c72ac52740..3695ec65d5 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -40,6 +40,7 @@ import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHERING_WIGIG; import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; @@ -495,7 +496,8 @@ public class Tethering { if (up) { maybeTrackNewInterfaceLocked(iface); } else { - if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) { + if (ifaceNameToType(iface) == TETHERING_BLUETOOTH + || ifaceNameToType(iface) == TETHERING_WIGIG) { stopTrackingInterfaceLocked(iface); } else { // Ignore usb0 down after enabling RNDIS. @@ -517,6 +519,8 @@ public class Tethering { if (cfg.isWifi(iface)) { return TETHERING_WIFI; + } else if (cfg.isWigig(iface)) { + return TETHERING_WIGIG; } else if (cfg.isWifiP2p(iface)) { return TETHERING_WIFI_P2P; } else if (cfg.isUsb(iface)) { diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 18b2b7804f..e1771a5613 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -92,6 +92,7 @@ public class TetheringConfiguration { public final String[] tetherableUsbRegexs; public final String[] tetherableWifiRegexs; + public final String[] tetherableWigigRegexs; public final String[] tetherableWifiP2pRegexs; public final String[] tetherableBluetoothRegexs; public final String[] tetherableNcmRegexs; @@ -125,6 +126,7 @@ public class TetheringConfiguration { // us an interface name. Careful consideration needs to be given to // implications for Settings and for provisioning checks. tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs); + tetherableWigigRegexs = getResourceStringArray(res, R.array.config_tether_wigig_regexs); tetherableWifiP2pRegexs = getResourceStringArray( res, R.array.config_tether_wifi_p2p_regexs); tetherableBluetoothRegexs = getResourceStringArray( @@ -167,6 +169,11 @@ public class TetheringConfiguration { return matchesDownstreamRegexs(iface, tetherableWifiRegexs); } + /** Check whether input interface belong to wigig.*/ + public boolean isWigig(String iface) { + return matchesDownstreamRegexs(iface, tetherableWigigRegexs); + } + /** Check whether this interface is Wifi P2P interface. */ public boolean isWifiP2p(String iface) { return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs); From e8141aa9c3f4f2adc744fd6605d783a86938f834 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 24 Jun 2020 03:44:31 +0000 Subject: [PATCH 2/2] tethering: offload: Netlink Req Send netlink request over fd for offload config before completing init sequence. Provides existing conntrack entries to IPA. Resolves issue where there are NAT misses in IPA due to IPA only having the conntrack entries added after tethering starts. Bug: 149109043 Test: OffloadHardwareInterfaceTest Original-Change: https://android-review.googlesource.com/1290954 Merged-In: Iaf3e847e92f205b55f10fa85c17b9f3995d52099 Change-Id: Iaf3e847e92f205b55f10fa85c17b9f3995d52099 --- .../tethering/OffloadHardwareInterface.java | 33 ++++++++++++++++ .../OffloadHardwareInterfaceTest.java | 39 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index fe92204c25..33b9d00e70 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.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.StructNlMsgHdr; import android.net.util.SharedLog; import android.net.util.SocketUtils; import android.os.Handler; @@ -37,9 +41,11 @@ import android.system.OsConstants; 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 @@ public class OffloadHardwareInterface { 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 @@ 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), + (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 @@ public class OffloadHardwareInterface { 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 f8ff1cb29c..c543fad62d 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.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.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.ArgumentCaptor; 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 @@ public final class OffloadHardwareInterfaceTest { @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 @@ public final class OffloadHardwareInterfaceTest { 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;