diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java
index 9bb4f9aded3ef95780d465a1a9cb5f57b18a4ea9..22dfbe8dfde708b49815e9579ea6fd6414f194a5 100644
--- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java
+++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java
@@ -29,6 +29,7 @@ import java.net.UnknownHostException;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
+import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 import javax.net.SocketFactory;
@@ -48,6 +49,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
 import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
 import static org.briarproject.bramble.util.IoUtils.tryToClose;
 import static org.briarproject.bramble.util.LogUtils.logException;
+import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
 
 @NotNullByDefault
 class AndroidLanTcpPlugin extends LanTcpPlugin {
@@ -55,6 +57,13 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
 	private static final Logger LOG =
 			getLogger(AndroidLanTcpPlugin.class.getName());
 
+	/**
+	 * The interface name is used as a heuristic for deciding whether the
+	 * device is providing a wifi access point.
+	 */
+	private static final Pattern AP_INTERFACE_NAME =
+			Pattern.compile("^(wlan|ap|p2p)[-0-9]");
+
 	private final Executor connectionStatusExecutor;
 	private final ConnectivityManager connectivityManager;
 	@Nullable
@@ -130,17 +139,14 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
 		if (info != null && info.getIpAddress() != 0) {
 			return new Pair<>(intToInetAddress(info.getIpAddress()), false);
 		}
-		List<InterfaceAddress> ifAddrs = getLocalInterfaceAddresses();
-		// If we're providing a normal access point, return its address
-		for (InterfaceAddress ifAddr : ifAddrs) {
-			if (isAndroidWifiApAddress(ifAddr)) {
-				return new Pair<>(ifAddr.getAddress(), true);
-			}
-		}
-		// If we're providing a wifi direct access point, return its address
-		for (InterfaceAddress ifAddr : ifAddrs) {
-			if (isAndroidWifiDirectApAddress(ifAddr)) {
-				return new Pair<>(ifAddr.getAddress(), true);
+		// If we're providing an access point, return its address
+		for (NetworkInterface iface : getNetworkInterfaces()) {
+			if (AP_INTERFACE_NAME.matcher(iface.getName()).find()) {
+				for (InterfaceAddress ifAddr : iface.getInterfaceAddresses()) {
+					if (isPossibleWifiApInterface(ifAddr)) {
+						return new Pair<>(ifAddr.getAddress(), true);
+					}
+				}
 			}
 		}
 		// Not connected to wifi
@@ -148,33 +154,18 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
 	}
 
 	/**
-	 * Returns true if the given address belongs to a network provided by an
-	 * Android access point (including the access point's own address).
+	 * Returns true if the given address may belong to an interface providing
+	 * a wifi access point (including wifi direct legacy mode access points).
 	 * <p>
-	 * The access point's address is usually 192.168.43.1, but at least one
-	 * device (Honor 8A) may use other addresses in the range 192.168.43.0/24.
-	 */
-	private boolean isAndroidWifiApAddress(InterfaceAddress ifAddr) {
-		if (ifAddr.getNetworkPrefixLength() != 24) return false;
-		byte[] ip = ifAddr.getAddress().getAddress();
-		return ip.length == 4
-				&& ip[0] == (byte) 192
-				&& ip[1] == (byte) 168
-				&& ip[2] == (byte) 43;
-	}
-
-	/**
-	 * Returns true if the given address belongs to a network provided by an
-	 * Android wifi direct legacy mode access point (including the access
-	 * point's own address).
+	 * This method may return true for wifi client interfaces as well, but
+	 * we've already checked for a wifi client connection above.
 	 */
-	private boolean isAndroidWifiDirectApAddress(InterfaceAddress ifAddr) {
+	private boolean isPossibleWifiApInterface(InterfaceAddress ifAddr) {
 		if (ifAddr.getNetworkPrefixLength() != 24) return false;
 		byte[] ip = ifAddr.getAddress().getAddress();
 		return ip.length == 4
 				&& ip[0] == (byte) 192
-				&& ip[1] == (byte) 168
-				&& ip[2] == (byte) 49;
+				&& ip[1] == (byte) 168;
 	}
 
 	/**
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/NetworkUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/NetworkUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2ad5ef883c611b9b2eb8736156c96949e5fef5f
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/util/NetworkUtils.java
@@ -0,0 +1,34 @@
+package org.briarproject.bramble.util;
+
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.logging.Logger;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.list;
+import static java.util.logging.Level.WARNING;
+import static java.util.logging.Logger.getLogger;
+import static org.briarproject.bramble.util.LogUtils.logException;
+
+@NotNullByDefault
+public class NetworkUtils {
+
+	private static final Logger LOG = getLogger(NetworkUtils.class.getName());
+
+	public static List<NetworkInterface> getNetworkInterfaces() {
+		try {
+			Enumeration<NetworkInterface> ifaces =
+					NetworkInterface.getNetworkInterfaces();
+			// Despite what the docs say, the return value can be null
+			//noinspection ConstantConditions
+			return ifaces == null ? emptyList() : list(ifaces);
+		} catch (SocketException e) {
+			logException(LOG, WARNING, e);
+			return emptyList();
+		}
+	}
+}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java
index 5b1acb376a206da847b9641230a29c06fbae4728..baa0502550c4a2207446cf59c5931ae34e2cab77 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java
@@ -28,11 +28,9 @@ import java.net.InterfaceAddress;
 import java.net.NetworkInterface;
 import java.net.ServerSocket;
 import java.net.Socket;
-import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Enumeration;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -53,7 +51,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
 import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
 import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
 import static org.briarproject.bramble.util.IoUtils.tryToClose;
-import static org.briarproject.bramble.util.LogUtils.logException;
+import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
 import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
 import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
 
@@ -98,7 +96,6 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
 	/**
 	 * Returns true if connections to the given address can be attempted.
 	 */
-	@SuppressWarnings("BooleanMethodIsAlwaysInverted")
 	protected abstract boolean isConnectable(InterfaceAddress local,
 			InetSocketAddress remote);
 
@@ -398,17 +395,6 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
 		return addrs;
 	}
 
-	private List<NetworkInterface> getNetworkInterfaces() {
-		try {
-			Enumeration<NetworkInterface> ifaces =
-					NetworkInterface.getNetworkInterfaces();
-			return ifaces == null ? emptyList() : list(ifaces);
-		} catch (SocketException e) {
-			logException(LOG, WARNING, e);
-			return emptyList();
-		}
-	}
-
 	@Override
 	public void eventOccurred(Event e) {
 		if (e instanceof SettingsUpdatedEvent) {
diff --git a/bramble-java/src/main/java/org/briarproject/bramble/network/JavaNetworkManager.java b/bramble-java/src/main/java/org/briarproject/bramble/network/JavaNetworkManager.java
index ee46bd11bc45115c403bf1f7e107321bc695f3be..72ccbab2f48e1fee26aca9398e5a1a066f783627 100644
--- a/bramble-java/src/main/java/org/briarproject/bramble/network/JavaNetworkManager.java
+++ b/bramble-java/src/main/java/org/briarproject/bramble/network/JavaNetworkManager.java
@@ -9,16 +9,15 @@ import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
-import java.util.Enumeration;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
-import static java.net.NetworkInterface.getNetworkInterfaces;
 import static java.util.Collections.list;
 import static java.util.logging.Level.WARNING;
 import static java.util.logging.Logger.getLogger;
 import static org.briarproject.bramble.util.LogUtils.logException;
+import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
 
 @MethodsNotNullByDefault
 @ParametersNotNullByDefault
@@ -35,19 +34,14 @@ class JavaNetworkManager implements NetworkManager {
 	public NetworkStatus getNetworkStatus() {
 		boolean connected = false, hasIpv4 = false, hasIpv6Unicast = false;
 		try {
-			Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
-			if (interfaces == null) {
-				LOG.info("No network interfaces");
-			} else {
-				for (NetworkInterface i : list(interfaces)) {
-					if (i.isLoopback() || !i.isUp()) continue;
-					for (InetAddress addr : list(i.getInetAddresses())) {
-						connected = true;
-						if (addr instanceof Inet4Address) {
-							hasIpv4 = true;
-						} else if (!addr.isMulticastAddress()) {
-							hasIpv6Unicast = true;
-						}
+			for (NetworkInterface i : getNetworkInterfaces()) {
+				if (i.isLoopback() || !i.isUp()) continue;
+				for (InetAddress addr : list(i.getInetAddresses())) {
+					connected = true;
+					if (addr instanceof Inet4Address) {
+						hasIpv4 = true;
+					} else if (!addr.isMulticastAddress()) {
+						hasIpv6Unicast = true;
 					}
 				}
 			}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/WebServerManager.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/WebServerManager.java
index c5a720b37ed07b5b11d2b1987fd0f23799b958da..60240a9968cdacc13da3cb70b063e4f5542e83bc 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/WebServerManager.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/WebServerManager.java
@@ -14,9 +14,6 @@ import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InterfaceAddress;
 import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Enumeration;
-import java.util.List;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
@@ -24,12 +21,11 @@ import javax.inject.Inject;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
-import static java.util.Collections.emptyList;
-import static java.util.Collections.list;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 import static java.util.logging.Logger.getLogger;
 import static org.briarproject.bramble.util.LogUtils.logException;
+import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
 import static org.briarproject.briar.android.hotspot.WebServer.PORT;
 
 @MethodsNotNullByDefault
@@ -112,16 +108,4 @@ class WebServerManager {
 		}
 		return null;
 	}
-
-	private static List<NetworkInterface> getNetworkInterfaces() {
-		try {
-			Enumeration<NetworkInterface> ifaces =
-					NetworkInterface.getNetworkInterfaces();
-			return ifaces == null ? emptyList() : list(ifaces);
-		} catch (SocketException e) {
-			logException(LOG, WARNING, e);
-			return emptyList();
-		}
-	}
-
 }