summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEtan Cohen <etancohen@google.com>2016-10-03 13:46:10 -0700
committerEtan Cohen <etancohen@google.com>2016-10-04 18:01:54 -0700
commit4c172f57fbad84033ef1ef0638f360d33ec7ccf5 (patch)
treeaa9005fafd778089ca8070c8ef9f4e0d010b2de9
parent3f08dd9bfa0e2a9431ebc0c970759349f4f05239 (diff)
[NAN] Use NAN capability information to validate configurations
Validate publish and subscribe configurations and message length using the NAN configuration retrieved from the firmware. (cherry-pick of commit b7383caf0cabd676ca3994d401a5ab7227d1a97c) Bug: 31912101 Test: unit tests Change-Id: I864876c91bf7157fff0c73d5095e78e9b2a6e3c8
-rw-r--r--service/java/com/android/server/wifi/nan/WifiNanDataPathStateManager.java4
-rw-r--r--service/java/com/android/server/wifi/nan/WifiNanNative.java15
-rw-r--r--service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java13
-rw-r--r--service/java/com/android/server/wifi/nan/WifiNanStateManager.java27
-rw-r--r--tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java4
-rw-r--r--tests/wifitests/src/com/android/server/wifi/nan/WifiNanServiceImplTest.java174
6 files changed, 209 insertions, 28 deletions
diff --git a/service/java/com/android/server/wifi/nan/WifiNanDataPathStateManager.java b/service/java/com/android/server/wifi/nan/WifiNanDataPathStateManager.java
index d624d9008..4bcfd1546 100644
--- a/service/java/com/android/server/wifi/nan/WifiNanDataPathStateManager.java
+++ b/service/java/com/android/server/wifi/nan/WifiNanDataPathStateManager.java
@@ -150,12 +150,12 @@ public class WifiNanDataPathStateManager {
public void createAllInterfaces() {
if (VDBG) Log.v(TAG, "createAllInterfaces");
- if (mMgr.mCapabilities == null) {
+ if (mMgr.getCapabilities() == null) {
Log.e(TAG, "createAllInterfaces: capabilities aren't initialized yet!");
return;
}
- for (int i = 0; i < mMgr.mCapabilities.maxNdiInterfaces; ++i) {
+ for (int i = 0; i < mMgr.getCapabilities().maxNdiInterfaces; ++i) {
String name = NAN_INTERFACE_PREFIX + i;
if (mInterfaces.contains(name)) {
Log.e(TAG, "createAllInterfaces(): interface already up, " + name
diff --git a/service/java/com/android/server/wifi/nan/WifiNanNative.java b/service/java/com/android/server/wifi/nan/WifiNanNative.java
index 630bcdc97..ba65d40e5 100644
--- a/service/java/com/android/server/wifi/nan/WifiNanNative.java
+++ b/service/java/com/android/server/wifi/nan/WifiNanNative.java
@@ -19,7 +19,9 @@ package com.android.server.wifi.nan;
import android.net.wifi.nan.ConfigRequest;
import android.net.wifi.nan.PublishConfig;
import android.net.wifi.nan.SubscribeConfig;
+import android.net.wifi.nan.WifiNanCharacteristics;
import android.net.wifi.nan.WifiNanDiscoverySessionCallback;
+import android.os.Bundle;
import android.util.Log;
import com.android.server.wifi.WifiNative;
@@ -89,6 +91,19 @@ public class WifiNanNative {
public int maxAppInfoLen;
public int maxQueuedTransmitMessages;
+ /**
+ * Converts the internal capabilities to a parcelable & potentially app-facing
+ * characteristics bundle. Only some of the information is exposed.
+ */
+ public WifiNanCharacteristics toPublicCharacteristics() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(WifiNanCharacteristics.KEY_MAX_SERVICE_NAME_LENGTH, maxServiceNameLen);
+ bundle.putInt(WifiNanCharacteristics.KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH,
+ maxServiceSpecificInfoLen);
+ bundle.putInt(WifiNanCharacteristics.KEY_MAX_MATCH_FILTER_LENGTH, maxMatchFilterLen);
+ return new WifiNanCharacteristics(bundle);
+ }
+
@Override
public String toString() {
return "Capabilities [maxConcurrentNanClusters=" + maxConcurrentNanClusters
diff --git a/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java b/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java
index f84eb5b5a..fe8f919fb 100644
--- a/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java
+++ b/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java
@@ -252,7 +252,7 @@ public class WifiNanServiceImpl extends IWifiNanManager.Stub {
if (publishConfig == null) {
throw new IllegalArgumentException("PublishConfig must not be null");
}
- publishConfig.validate();
+ publishConfig.assertValid(mStateManager.getCharacteristics());
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -272,7 +272,7 @@ public class WifiNanServiceImpl extends IWifiNanManager.Stub {
if (publishConfig == null) {
throw new IllegalArgumentException("PublishConfig must not be null");
}
- publishConfig.validate();
+ publishConfig.assertValid(mStateManager.getCharacteristics());
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -296,7 +296,7 @@ public class WifiNanServiceImpl extends IWifiNanManager.Stub {
if (subscribeConfig == null) {
throw new IllegalArgumentException("SubscribeConfig must not be null");
}
- subscribeConfig.validate();
+ subscribeConfig.assertValid(mStateManager.getCharacteristics());
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -316,7 +316,7 @@ public class WifiNanServiceImpl extends IWifiNanManager.Stub {
if (subscribeConfig == null) {
throw new IllegalArgumentException("SubscribeConfig must not be null");
}
- subscribeConfig.validate();
+ subscribeConfig.assertValid(mStateManager.getCharacteristics());
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -334,6 +334,11 @@ public class WifiNanServiceImpl extends IWifiNanManager.Stub {
enforceAccessPermission();
enforceChangePermission();
+ if (message != null
+ && message.length > mStateManager.getCharacteristics().getMaxServiceNameLength()) {
+ throw new IllegalArgumentException(
+ "Message length longer than supported by device characteristics");
+ }
if (retryCount < 0 || retryCount > WifiNanDiscoveryBaseSession.getMaxSendRetryCount()) {
throw new IllegalArgumentException("Invalid 'retryCount' must be non-negative "
+ "and <= WifiNanDiscoveryBaseSession.MAX_SEND_RETRY_COUNT");
diff --git a/service/java/com/android/server/wifi/nan/WifiNanStateManager.java b/service/java/com/android/server/wifi/nan/WifiNanStateManager.java
index 28095c832..b6bd6a788 100644
--- a/service/java/com/android/server/wifi/nan/WifiNanStateManager.java
+++ b/service/java/com/android/server/wifi/nan/WifiNanStateManager.java
@@ -24,6 +24,7 @@ import android.net.wifi.nan.IWifiNanDiscoverySessionCallback;
import android.net.wifi.nan.IWifiNanEventCallback;
import android.net.wifi.nan.PublishConfig;
import android.net.wifi.nan.SubscribeConfig;
+import android.net.wifi.nan.WifiNanCharacteristics;
import android.net.wifi.nan.WifiNanManager;
import android.os.Bundle;
import android.os.Looper;
@@ -179,7 +180,8 @@ public class WifiNanStateManager {
* handler thread: no need to use a lock.
*/
private Context mContext;
- /* package */ WifiNanNative.Capabilities mCapabilities;
+ private volatile WifiNanNative.Capabilities mCapabilities;
+ private volatile WifiNanCharacteristics mCharacteristics = null;
private WifiNanStateMachine mSm;
private WifiNanRttStateManager mRtt;
private WifiNanDataPathStateManager mDataPathMgr;
@@ -241,6 +243,24 @@ public class WifiNanStateManager {
return mClients.get(clientId);
}
+ /**
+ * Get the capabilities.
+ */
+ public WifiNanNative.Capabilities getCapabilities() {
+ return mCapabilities;
+ }
+
+ /**
+ * Get the public characteristics derived from the capabilities. Use lazy initialization.
+ */
+ public WifiNanCharacteristics getCharacteristics() {
+ if (mCharacteristics == null && mCapabilities != null) {
+ mCharacteristics = mCapabilities.toPublicCharacteristics();
+ }
+
+ return mCharacteristics;
+ }
+
/*
* COMMANDS
*/
@@ -404,7 +424,7 @@ public class WifiNanStateManager {
/**
* Get the capabilities of the current NAN firmware.
*/
- public void getCapabilities() {
+ public void queryCapabilities() {
Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND);
msg.arg1 = COMMAND_TYPE_GET_CAPABILITIES;
mSm.sendMessage(msg);
@@ -1941,7 +1961,7 @@ public class WifiNanStateManager {
WifiNanNative.getInstance().deInitNan(); // force a re-init of NAN HAL
mUsageEnabled = true;
- getCapabilities();
+ queryCapabilities();
createAllDataPathInterfaces();
sendNanStateChangedBroadcast(true);
}
@@ -2282,6 +2302,7 @@ public class WifiNanStateManager {
}
mCapabilities = capabilities;
+ mCharacteristics = null;
}
private void onCreateDataPathInterfaceResponseLocal(Message command, boolean success,
diff --git a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java
index 13e3dd41c..50f7a11c7 100644
--- a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java
@@ -168,7 +168,7 @@ public class WifiNanDataPathStateManagerTest {
InOrder inOrder = inOrder(mMockNative);
// (1) get capabilities
- mDut.getCapabilities();
+ mDut.queryCapabilities();
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
@@ -701,7 +701,7 @@ public class WifiNanDataPathStateManagerTest {
collector.checkThat("factory name", "WIFI_NAN_FACTORY", equalTo(strCaptor.getValue()));
// (1) get capabilities
- mDut.getCapabilities();
+ mDut.queryCapabilities();
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
diff --git a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanServiceImplTest.java
index 13912e9b6..86d388b25 100644
--- a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanServiceImplTest.java
@@ -36,6 +36,7 @@ import android.net.wifi.nan.IWifiNanDiscoverySessionCallback;
import android.net.wifi.nan.IWifiNanEventCallback;
import android.net.wifi.nan.PublishConfig;
import android.net.wifi.nan.SubscribeConfig;
+import android.net.wifi.nan.WifiNanCharacteristics;
import android.os.IBinder;
import android.os.Looper;
import android.test.suitebuilder.annotation.SmallTest;
@@ -56,6 +57,8 @@ import java.lang.reflect.Field;
*/
@SmallTest
public class WifiNanServiceImplTest {
+ private static final int MAX_LENGTH = 255;
+
private WifiNanServiceImplSpy mDut;
private int mDefaultUid = 1500;
@@ -104,6 +107,7 @@ public class WifiNanServiceImplTest {
when(mContextMock.getPackageManager()).thenReturn(mPackageManagerMock);
when(mPackageManagerMock.hasSystemFeature(PackageManager.FEATURE_WIFI_NAN))
.thenReturn(true);
+ when(mNanStateManagerMock.getCharacteristics()).thenReturn(getCharacteristics());
installMockNanStateManager();
@@ -323,16 +327,38 @@ public class WifiNanServiceImplTest {
* name.
*/
@Test(expected = IllegalArgumentException.class)
- public void testPublishBadServiceName() {
- PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
- "Including invalid characters - spaces").build();
- int clientId = doConnect();
- IWifiNanDiscoverySessionCallback mockCallback = mock(
- IWifiNanDiscoverySessionCallback.class);
+ public void testPublishInvalidServiceName() {
+ doBadPublishConfiguration("Including invalid characters - spaces", null, null);
+ }
- mDut.publish(clientId, publishConfig, mockCallback);
+ /**
+ * Validate that publish() verifies the input PublishConfig and fails on a "very long"
+ * service name.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testPublishServiceNameTooLong() {
+ byte[] byteArray = new byte[MAX_LENGTH + 1];
+ for (int i = 0; i < MAX_LENGTH + 1; ++i) {
+ byteArray[i] = 'a';
+ }
+ doBadPublishConfiguration(new String(byteArray), null, null);
+ }
- verify(mNanStateManagerMock).publish(clientId, publishConfig, mockCallback);
+ /**
+ * Validate that publish() verifies the input PublishConfig and fails on a "very long" ssi.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testPublishSsiTooLong() {
+ doBadPublishConfiguration("correctservicename", new byte[MAX_LENGTH + 1], null);
+ }
+
+ /**
+ * Validate that publish() verifies the input PublishConfig and fails on a "very long" match
+ * filter.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testPublishMatchFilterTooLong() {
+ doBadPublishConfiguration("correctservicename", null, new byte[MAX_LENGTH + 1]);
}
/**
@@ -351,6 +377,21 @@ public class WifiNanServiceImplTest {
}
/**
+ * Validate updatePublish() error checking.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testUpdatePublishInvalid() {
+ int sessionId = 1232;
+ PublishConfig publishConfig = new PublishConfig.Builder()
+ .setServiceName("something with spaces").build();
+ int clientId = doConnect();
+
+ mDut.updatePublish(clientId, sessionId, publishConfig);
+
+ verify(mNanStateManagerMock).updatePublish(clientId, sessionId, publishConfig);
+ }
+
+ /**
* Validate subscribe() - correct pass-through args.
*/
@Test
@@ -371,20 +412,58 @@ public class WifiNanServiceImplTest {
* name.
*/
@Test(expected = IllegalArgumentException.class)
- public void testSubscribeBadServiceName() {
- SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(
- "InvalidServiceCharacters__").build();
+ public void testSubscribeInvalidServiceName() {
+ doBadSubscribeConfiguration("Including invalid characters - spaces", null, null);
+ }
+
+ /**
+ * Validate that subscribe() verifies the input SubscribeConfig and fails on a "very long"
+ * service name.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSubscribeServiceNameTooLong() {
+ byte[] byteArray = new byte[MAX_LENGTH + 1];
+ for (int i = 0; i < MAX_LENGTH + 1; ++i) {
+ byteArray[i] = 'a';
+ }
+ doBadSubscribeConfiguration(new String(byteArray), null, null);
+ }
+
+ /**
+ * Validate that subscribe() verifies the input SubscribeConfig and fails on a "very long" ssi.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSubscribeSsiTooLong() {
+ doBadSubscribeConfiguration("correctservicename", new byte[MAX_LENGTH + 1], null);
+ }
+
+ /**
+ * Validate that subscribe() verifies the input SubscribeConfig and fails on a "very long" match
+ * filter.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSubscribeMatchFilterTooLong() {
+ doBadSubscribeConfiguration("correctservicename", null, new byte[MAX_LENGTH + 1]);
+ }
+
+ /**
+ * Validate updateSubscribe() error checking.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testUpdateSubscribeInvalid() {
+ int sessionId = 1232;
+ SubscribeConfig subscribeConfig = new SubscribeConfig.Builder()
+ .setServiceName("something.valid")
+ .setServiceSpecificInfo(new byte[MAX_LENGTH + 1]).build();
int clientId = doConnect();
- IWifiNanDiscoverySessionCallback mockCallback = mock(
- IWifiNanDiscoverySessionCallback.class);
- mDut.subscribe(clientId, subscribeConfig, mockCallback);
+ mDut.updateSubscribe(clientId, sessionId, subscribeConfig);
- verify(mNanStateManagerMock).subscribe(clientId, subscribeConfig, mockCallback);
+ verify(mNanStateManagerMock).updateSubscribe(clientId, sessionId, subscribeConfig);
}
/**
- * Validate updateSubscribe() - correct pass-through args.
+ * Validate updateSubscribe() validates configuration.
*/
@Test
public void testUpdateSubscribe() {
@@ -405,7 +484,24 @@ public class WifiNanServiceImplTest {
public void testSendMessage() {
int sessionId = 2394;
int peerId = 2032;
- byte[] message = new byte[23];
+ byte[] message = new byte[MAX_LENGTH];
+ int messageId = 2043;
+ int clientId = doConnect();
+
+ mDut.sendMessage(clientId, sessionId, peerId, message, messageId, 0);
+
+ verify(mNanStateManagerMock).sendMessage(clientId, sessionId, peerId, message, messageId,
+ 0);
+ }
+
+ /**
+ * Validate sendMessage() validates that message length is correct.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSendMessageTooLong() {
+ int sessionId = 2394;
+ int peerId = 2032;
+ byte[] message = new byte[MAX_LENGTH + 1];
int messageId = 2043;
int clientId = doConnect();
@@ -492,6 +588,32 @@ public class WifiNanServiceImplTest {
* Utilities
*/
+ private void doBadPublishConfiguration(String serviceName, byte[] ssi, byte[] matchFilter)
+ throws IllegalArgumentException {
+ PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName)
+ .setServiceSpecificInfo(ssi).setMatchFilter(matchFilter).build();
+ int clientId = doConnect();
+ IWifiNanDiscoverySessionCallback mockCallback = mock(
+ IWifiNanDiscoverySessionCallback.class);
+
+ mDut.publish(clientId, publishConfig, mockCallback);
+
+ verify(mNanStateManagerMock).publish(clientId, publishConfig, mockCallback);
+ }
+
+ private void doBadSubscribeConfiguration(String serviceName, byte[] ssi, byte[] matchFilter)
+ throws IllegalArgumentException {
+ SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
+ .setServiceSpecificInfo(ssi).setMatchFilter(matchFilter).build();
+ int clientId = doConnect();
+ IWifiNanDiscoverySessionCallback mockCallback = mock(
+ IWifiNanDiscoverySessionCallback.class);
+
+ mDut.subscribe(clientId, subscribeConfig, mockCallback);
+
+ verify(mNanStateManagerMock).subscribe(clientId, subscribeConfig, mockCallback);
+ }
+
private int doConnect() {
String callingPackage = "com.google.somePackage";
@@ -512,6 +634,24 @@ public class WifiNanServiceImplTest {
field.set(null, mNanStateManagerMock);
}
+ private static WifiNanCharacteristics getCharacteristics() {
+ WifiNanNative.Capabilities cap = new WifiNanNative.Capabilities();
+ cap.maxConcurrentNanClusters = 1;
+ cap.maxPublishes = 2;
+ cap.maxSubscribes = 2;
+ cap.maxServiceNameLen = MAX_LENGTH;
+ cap.maxMatchFilterLen = MAX_LENGTH;
+ cap.maxTotalMatchFilterLen = 255;
+ cap.maxServiceSpecificInfoLen = MAX_LENGTH;
+ cap.maxVsaDataLen = 255;
+ cap.maxMeshDataLen = 255;
+ cap.maxNdiInterfaces = 1;
+ cap.maxNdpSessions = 1;
+ cap.maxAppInfoLen = 255;
+ cap.maxQueuedTransmitMessages = 6;
+ return cap.toPublicCharacteristics();
+ }
+
private int getInternalStateUid(int clientId) throws Exception {
Field field = WifiNanServiceImpl.class.getDeclaredField("mUidByClientId");
field.setAccessible(true);