diff options
author | Etan Cohen <etancohen@google.com> | 2016-10-03 13:46:10 -0700 |
---|---|---|
committer | Etan Cohen <etancohen@google.com> | 2016-10-04 18:01:54 -0700 |
commit | 4c172f57fbad84033ef1ef0638f360d33ec7ccf5 (patch) | |
tree | aa9005fafd778089ca8070c8ef9f4e0d010b2de9 | |
parent | 3f08dd9bfa0e2a9431ebc0c970759349f4f05239 (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
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); |