summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorEtan Cohen <etancohen@google.com>2017-08-10 09:02:44 -0700
committerEtan Cohen <etancohen@google.com>2017-08-18 07:11:03 -0700
commit8c448d091357f076a0e40371232f18f22df37746 (patch)
tree35c5de274da069c97b16eea334ce459ccfff7534 /service
parent0af8182c7a421108aff122440724ecc5d1e4c6d7 (diff)
[AWARE] Support multiple canonically identical NDP requests
NDP (NAN data-path) connectivity requests may be different but resolve to the same canonic NDP request (e.g. multiple OOB requests to the same peer with the same security - but executed through different clients). Adds mechanism to honor all these requests through a single NDP (can not create multiple identical NDPs) and a single network agent. Bug: 64125969 Test: unit-tests pass Test: new DataPathTest:test_multiple_identical_networks + full suite Change-Id: I98fc75ed4f8269274fbd19302386a17c59b568a1
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java208
1 files changed, 178 insertions, 30 deletions
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
index ead0c5f5e..b20445ae1 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
@@ -33,6 +33,7 @@ import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.RouteInfo;
+import android.net.wifi.aware.WifiAwareAgentNetworkSpecifier;
import android.net.wifi.aware.WifiAwareManager;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
import android.net.wifi.aware.WifiAwareUtils;
@@ -61,6 +62,7 @@ import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -86,7 +88,7 @@ public class WifiAwareDataPathStateManager {
private final WifiAwareStateManager mMgr;
public NetworkInterfaceWrapper mNiWrapper = new NetworkInterfaceWrapper();
- private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
+ private static final NetworkCapabilities sNetworkCapabilitiesFilter = new NetworkCapabilities();
private final Set<String> mInterfaces = new HashSet<>();
private final Map<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation>
mNetworkRequestsCache = new ArrayMap<>();
@@ -114,19 +116,19 @@ public class WifiAwareDataPathStateManager {
mPermissionsWrapper = permissionsWrapper;
mLooper = looper;
- mNetworkCapabilitiesFilter.clearAll();
- mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
- mNetworkCapabilitiesFilter
+ sNetworkCapabilitiesFilter.clearAll();
+ sNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
+ sNetworkCapabilitiesFilter
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
- mNetworkCapabilitiesFilter.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
- mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
- mNetworkCapabilitiesFilter.setSignalStrength(NETWORK_FACTORY_SIGNAL_STRENGTH_AVAIL);
+ sNetworkCapabilitiesFilter.setNetworkSpecifier(new MatchAllNetworkSpecifier());
+ sNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
+ sNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
+ sNetworkCapabilitiesFilter.setSignalStrength(NETWORK_FACTORY_SIGNAL_STRENGTH_AVAIL);
- mNetworkFactory = new WifiAwareNetworkFactory(looper, context, mNetworkCapabilitiesFilter);
+ mNetworkFactory = new WifiAwareNetworkFactory(looper, context, sNetworkCapabilitiesFilter);
mNetworkFactory.setScoreFilter(NETWORK_FACTORY_SCORE_AVAIL);
mNetworkFactory.register();
@@ -146,6 +148,18 @@ public class WifiAwareDataPathStateManager {
return null;
}
+ private Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation>
+ getNetworkRequestByCanonicalDescriptor(CanonicalConnectionInfo cci) {
+ for (Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation> entry :
+ mNetworkRequestsCache.entrySet()) {
+ if (entry.getValue().getCanonicalDescriptor().equals(cci)) {
+ return entry;
+ }
+ }
+
+ return null;
+ }
+
/**
* Create all Aware data-path interfaces which are possible on the device - based on the
* capabilities of the firmware.
@@ -468,7 +482,7 @@ public class WifiAwareDataPathStateManager {
NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_NONE, 0,
NETWORK_TAG, "");
NetworkCapabilities networkCapabilities = new NetworkCapabilities(
- mNetworkCapabilitiesFilter);
+ sNetworkCapabilitiesFilter);
LinkProperties linkProperties = new LinkProperties();
boolean interfaceUsedByAnotherNdp = isInterfaceUpAndUsedByAnotherNdp(nnri);
@@ -481,6 +495,7 @@ public class WifiAwareDataPathStateManager {
+ ": can't configure network - "
+ e);
mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
return networkSpecifier;
}
} else {
@@ -490,8 +505,8 @@ public class WifiAwareDataPathStateManager {
}
}
- if (!mNiWrapper.configureAgentProperties(nnri, networkSpecifier, ndpId, networkInfo,
- networkCapabilities, linkProperties)) {
+ if (!mNiWrapper.configureAgentProperties(nnri, nnri.equivalentSpecifiers, ndpId,
+ networkInfo, networkCapabilities, linkProperties)) {
return networkSpecifier;
}
@@ -578,6 +593,7 @@ public class WifiAwareDataPathStateManager {
nnri.networkSpecifier.isOutOfBand(), nnri.startTimestamp);
mMgr.endDataPath(nnri.ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
}
private class WifiAwareNetworkFactory extends NetworkFactory {
@@ -638,6 +654,18 @@ public class WifiAwareDataPathStateManager {
return false;
}
+ // check to see if a canonical version exists
+ Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation> primaryRequest =
+ getNetworkRequestByCanonicalDescriptor(nnri.getCanonicalDescriptor());
+ if (primaryRequest != null) {
+ if (VDBG) {
+ Log.v(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
+ + ", already has a primary request=" + primaryRequest.getKey());
+ }
+ primaryRequest.getValue().updateToSupportNewRequest(networkSpecifier);
+ return false;
+ }
+
mNetworkRequestsCache.put(networkSpecifier, nnri);
return true;
@@ -725,19 +753,28 @@ public class WifiAwareDataPathStateManager {
return;
}
- if (nnri.networkSpecifier.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
- && nnri.state
- > AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE) {
- mMgr.endDataPath(nnri.ndpId);
- }
- if (nnri.networkSpecifier.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
- && nnri.state
- > AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_REQUEST) {
- mMgr.endDataPath(nnri.ndpId);
+ /*
+ * Since there's no agent it means we're in the process of setting up the NDP.
+ * However, it is possible that there were other equivalent requests for this NDP. We
+ * should keep going in that case.
+ */
+ nnri.removeSupportForRequest(networkSpecifier);
+ if (nnri.equivalentSpecifiers.isEmpty()) {
+ if (VDBG) {
+ Log.v(TAG, "releaseNetworkFor: there are no further requests, networkRequest="
+ + networkRequest);
+ }
+ if (nnri.ndpId != 0) { // 0 is never a valid ID!
+ if (VDBG) Log.v(TAG, "releaseNetworkFor: in progress NDP being terminated");
+ mMgr.endDataPath(nnri.ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
+ }
+ } else {
+ if (VDBG) {
+ Log.v(TAG, "releaseNetworkFor: equivalent requests exist - not terminating "
+ + "networkRequest=" + networkRequest);
+ }
}
-
- // Will get a callback (on both initiator and responder) when data-path actually
- // terminated. At that point will inform the agent and will clear the cache.
}
}
@@ -858,6 +895,7 @@ public class WifiAwareDataPathStateManager {
static final int STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE = 103;
static final int STATE_RESPONDER_WAIT_FOR_REQUEST = 104;
static final int STATE_RESPONDER_WAIT_FOR_RESPOND_RESPONSE = 105;
+ static final int STATE_TERMINATING = 106;
public int state;
@@ -866,13 +904,55 @@ public class WifiAwareDataPathStateManager {
public int pubSubId = 0;
public int peerInstanceId = 0;
public byte[] peerDiscoveryMac = null;
- public int ndpId;
+ public int ndpId = 0; // 0 is never a valid ID!
public byte[] peerDataMac;
public WifiAwareNetworkSpecifier networkSpecifier;
public long startTimestamp = 0; // request is made (initiator) / get request (responder)
public WifiAwareNetworkAgent networkAgent;
+ /* A collection of specifiers which are equivalent to the current request and are
+ * supported by it's agent. This list DOES include the original (first) network specifier
+ * (which is stored separately above).
+ */
+ public Set<WifiAwareNetworkSpecifier> equivalentSpecifiers = new HashSet<>();
+
+ void updateToSupportNewRequest(WifiAwareNetworkSpecifier ns) {
+ if (VDBG) Log.v(TAG, "updateToSupportNewRequest: ns=" + ns);
+ if (equivalentSpecifiers.add(ns) && state == STATE_CONFIRMED) {
+ if (networkAgent == null) {
+ Log.wtf(TAG, "updateToSupportNewRequest: null agent in CONFIRMED state!?");
+ return;
+ }
+
+ networkAgent.sendNetworkCapabilities(getNetworkCapabilities());
+ }
+ }
+
+ void removeSupportForRequest(WifiAwareNetworkSpecifier ns) {
+ if (VDBG) Log.v(TAG, "removeSupportForRequest: ns=" + ns);
+ equivalentSpecifiers.remove(ns);
+
+ // we will not update the agent:
+ // 1. this will only get called before the agent is created
+ // 2. connectivity service does not allow (WTF) updates with reduced capabilities
+ }
+
+ private NetworkCapabilities getNetworkCapabilities() {
+ NetworkCapabilities nc = new NetworkCapabilities(sNetworkCapabilitiesFilter);
+ nc.setNetworkSpecifier(new WifiAwareAgentNetworkSpecifier(equivalentSpecifiers.toArray(
+ new WifiAwareNetworkSpecifier[equivalentSpecifiers.size()])));
+ return nc;
+ }
+
+ /**
+ * Returns a canonical descriptor for the network request.
+ */
+ CanonicalConnectionInfo getCanonicalDescriptor() {
+ return new CanonicalConnectionInfo(peerDiscoveryMac, networkSpecifier.pmk,
+ networkSpecifier.sessionId, networkSpecifier.passphrase);
+ }
+
static AwareNetworkRequestInformation processNetworkSpecifier(WifiAwareNetworkSpecifier ns,
WifiAwareStateManager mgr, WifiPermissionsWrapper permissionWrapper) {
int uid, pubSubId = 0;
@@ -1002,6 +1082,7 @@ public class WifiAwareDataPathStateManager {
nnri.peerInstanceId = peerInstanceId;
nnri.peerDiscoveryMac = peerMac;
nnri.networkSpecifier = ns;
+ nnri.equivalentSpecifiers.add(ns);
return nnri;
}
@@ -1018,7 +1099,69 @@ public class WifiAwareDataPathStateManager {
", ndpId=").append(ndpId).append(", peerDataMac=").append(
peerDataMac == null ? ""
: String.valueOf(HexEncoding.encode(peerDataMac))).append(
- ", startTimestamp=").append(startTimestamp);
+ ", startTimestamp=").append(startTimestamp).append(", equivalentSpecifiers=[");
+ for (WifiAwareNetworkSpecifier ns: equivalentSpecifiers) {
+ sb.append(ns.toString()).append(", ");
+ }
+ return sb.append("]").toString();
+ }
+ }
+
+ /**
+ * A canonical (unique) descriptor of the peer connection.
+ */
+ static class CanonicalConnectionInfo {
+ CanonicalConnectionInfo(byte[] peerDiscoveryMac, byte[] pmk, int sessionId,
+ String passphrase) {
+ this.peerDiscoveryMac = peerDiscoveryMac;
+ this.pmk = pmk;
+ this.sessionId = sessionId;
+ this.passphrase = passphrase;
+ }
+
+ public final byte[] peerDiscoveryMac;
+
+ /*
+ * Security configuration matching:
+ * - open: pmk/passphrase = null
+ * - pmk: pmk != null, passphrase = null
+ * - passphrase: passphrase != null, sessionId used (==0 for OOB), pmk=null
+ */
+ public final byte[] pmk;
+
+ public final int sessionId;
+ public final String passphrase;
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(Arrays.hashCode(peerDiscoveryMac), Arrays.hashCode(pmk), sessionId,
+ passphrase);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof CanonicalConnectionInfo)) {
+ return false;
+ }
+
+ CanonicalConnectionInfo lhs = (CanonicalConnectionInfo) obj;
+
+ return Arrays.equals(peerDiscoveryMac, lhs.peerDiscoveryMac) && Arrays.equals(pmk,
+ lhs.pmk) && TextUtils.equals(passphrase, lhs.passphrase)
+ && sessionId == lhs.sessionId;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("CanonicalConnectionInfo: [");
+ sb.append("peerDiscoveryMac=").append(peerDiscoveryMac == null ? ""
+ : String.valueOf(HexEncoding.encode(peerDiscoveryMac))).append("pmk=").append(
+ pmk == null ? "" : "*").append("sessionId=").append(sessionId).append(
+ "passphrase=").append(passphrase == null ? "" : "*").append("]");
return sb.toString();
}
}
@@ -1033,8 +1176,9 @@ public class WifiAwareDataPathStateManager {
* name. Delegated to enable mocking.
*/
public boolean configureAgentProperties(AwareNetworkRequestInformation nnri,
- WifiAwareNetworkSpecifier networkSpecifier, int ndpId, NetworkInfo networkInfo,
- NetworkCapabilities networkCapabilities, LinkProperties linkProperties) {
+ Set<WifiAwareNetworkSpecifier> networkSpecifiers, int ndpId,
+ NetworkInfo networkInfo, NetworkCapabilities networkCapabilities,
+ LinkProperties linkProperties) {
// find link-local address
InetAddress linkLocal = null;
NetworkInterface ni;
@@ -1044,12 +1188,14 @@ public class WifiAwareDataPathStateManager {
Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
+ ": can't get network interface - " + e);
mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
return false;
}
if (ni == null) {
Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
+ ": can't get network interface (null)");
mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
return false;
}
Enumeration<InetAddress> addresses = ni.getInetAddresses();
@@ -1064,6 +1210,7 @@ public class WifiAwareDataPathStateManager {
if (linkLocal == null) {
Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri + ": no link local addresses");
mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
return false;
}
@@ -1071,7 +1218,8 @@ public class WifiAwareDataPathStateManager {
networkInfo.setIsAvailable(true);
networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
- networkCapabilities.setNetworkSpecifier(networkSpecifier);
+ networkCapabilities.setNetworkSpecifier(new WifiAwareAgentNetworkSpecifier(
+ networkSpecifiers.toArray(new WifiAwareNetworkSpecifier[0])));
linkProperties.setInterfaceName(nnri.interfaceName);
linkProperties.addLinkAddress(new LinkAddress(linkLocal, 64));
@@ -1088,7 +1236,7 @@ public class WifiAwareDataPathStateManager {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("WifiAwareDataPathStateManager:");
pw.println(" mInterfaces: " + mInterfaces);
- pw.println(" mNetworkCapabilitiesFilter: " + mNetworkCapabilitiesFilter);
+ pw.println(" sNetworkCapabilitiesFilter: " + sNetworkCapabilitiesFilter);
pw.println(" mNetworkRequestsCache: " + mNetworkRequestsCache);
pw.println(" mNetworkFactory:");
mNetworkFactory.dump(fd, pw, args);