summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/hotspot2/anqp/ANQPFactory.java2
-rw-r--r--service/java/com/android/server/wifi/hotspot2/anqp/CellularNetwork.java177
-rw-r--r--service/java/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElement.java106
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTest.java111
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTestUtil.java94
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElementTest.java140
6 files changed, 567 insertions, 63 deletions
diff --git a/service/java/com/android/server/wifi/hotspot2/anqp/ANQPFactory.java b/service/java/com/android/server/wifi/hotspot2/anqp/ANQPFactory.java
index 8ef75a600..bc724ceaf 100644
--- a/service/java/com/android/server/wifi/hotspot2/anqp/ANQPFactory.java
+++ b/service/java/com/android/server/wifi/hotspot2/anqp/ANQPFactory.java
@@ -96,7 +96,7 @@ public class ANQPFactory {
case ANQPNAIRealm:
return new NAIRealmElement(infoID, payload);
case ANQP3GPPNetwork:
- return new ThreeGPPNetworkElement(infoID, payload);
+ return ThreeGPPNetworkElement.parse(payload);
case ANQPDomName:
return DomainNameElement.parse(payload);
case ANQPVendorSpec:
diff --git a/service/java/com/android/server/wifi/hotspot2/anqp/CellularNetwork.java b/service/java/com/android/server/wifi/hotspot2/anqp/CellularNetwork.java
index f8573e6ac..cc39b3f2b 100644
--- a/service/java/com/android/server/wifi/hotspot2/anqp/CellularNetwork.java
+++ b/service/java/com/android/server/wifi/hotspot2/anqp/CellularNetwork.java
@@ -1,70 +1,167 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.wifi.hotspot2.anqp;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.Collections;
import java.util.List;
-import static com.android.server.wifi.hotspot2.anqp.Constants.BYTE_MASK;
+/**
+ * The IEI (Information Element Identity) contained in the Generic Container for the
+ * 3GPP Cellular Network ANQP element.
+ *
+ * Refer to Annex A of 3GPP TS 24.234 version 11.3.0 for information on the data format:
+ * (http://www.etsi.org/deliver/etsi_ts/124200_124299/124234/11.03.00_60/ts_124234v110300p.pdf)
+ */
+public class CellularNetwork {
+ private static final String TAG = "CellularNetwork";
-public class CellularNetwork implements Iterable<String> {
- private static final int PLMNListType = 0;
+ /**
+ * IEI type for PLMN (Public Land Mobile Network) list.
+ */
+ @VisibleForTesting
+ public static final int IEI_TYPE_PLMN_LIST = 0;
- private final List<String> mMccMnc;
+ @VisibleForTesting
+ public static final int IEI_CONTENT_LENGTH_MASK = 0x7F;
- private CellularNetwork(int plmnCount, ByteBuffer payload) throws ProtocolException {
- mMccMnc = new ArrayList<>(plmnCount);
+ /**
+ * Number of bytes for each PLMN (Public Land Mobile Network).
+ */
+ @VisibleForTesting
+ public static final int PLMN_DATA_BYTES = 3;
- while (plmnCount > 0) {
- if (payload.remaining() < 3) {
- throw new ProtocolException("Truncated PLMN info");
- }
- byte[] plmn = new byte[3];
- payload.get(plmn);
+ /**
+ * The value for comparing the third digit of MNC data with to determine if the MNC is
+ * two or three digits.
+ */
+ private static final int MNC_2DIGIT_VALUE = 0xF;
+
+ /**
+ * List of PLMN (Public Land Mobile Network) information.
+ */
+ private final List<String> mPlmnList;
+
+ @VisibleForTesting
+ public CellularNetwork(List<String> plmnList) {
+ mPlmnList = plmnList;
+ }
+
+ /**
+ * Parse a CellularNetwork from the given buffer.
+ *
+ * @param payload The byte buffer to read from
+ * @return {@link CellularNetwork}
+ * @throws ProtocolException
+ * @throws BufferUnderflowException
+ */
+ public static CellularNetwork parse(ByteBuffer payload) throws ProtocolException {
+ int ieiType = payload.get() & 0xFF;
+ int ieiSize = payload.get() & IEI_CONTENT_LENGTH_MASK;
- int mcc = ((plmn[0] << 8) & 0xf00) |
- (plmn[0] & 0x0f0) |
- (plmn[1] & 0x00f);
+ // Skip this IEI if it is an unsupported type.
+ if (ieiType != IEI_TYPE_PLMN_LIST) {
+ Log.e(TAG, "Ignore unsupported IEI Type: " + ieiType);
+ // Advance the buffer position to the next IEI.
+ payload.position(payload.position() + ieiSize);
+ return null;
+ }
- int mnc = ((plmn[2] << 4) & 0xf0) |
- ((plmn[2] >> 4) & 0x0f);
+ // Get PLMN count.
+ int plmnCount = payload.get() & 0xFF;
- int n2 = (plmn[1] >> 4) & 0x0f;
- String mccMnc = n2 != 0xf ?
- String.format("%03x%03x", mcc, (mnc << 4) | n2) :
- String.format("%03x%02x", mcc, mnc);
+ // Verify IEI size with PLMN count. The IEI size contained the PLMN count field plus
+ // the bytes for the PLMNs.
+ if (ieiSize != (plmnCount * PLMN_DATA_BYTES + 1)) {
+ throw new ProtocolException("IEI size and PLMN count mismatched: IEI Size=" + ieiSize
+ + " PLMN Count=" + plmnCount);
+ }
- mMccMnc.add(mccMnc);
+ // Process each PLMN.
+ List<String> plmnList = new ArrayList<>();
+ while (plmnCount > 0) {
+ plmnList.add(parsePlmn(payload));
plmnCount--;
}
+ return new CellularNetwork(plmnList);
}
- public static CellularNetwork buildCellularNetwork(ByteBuffer payload)
- throws ProtocolException {
- int iei = payload.get() & BYTE_MASK;
- int plmnLen = payload.get() & 0x7f;
+ public List<String> getPlmns() {
+ return Collections.unmodifiableList(mPlmnList);
+ }
- if (iei != PLMNListType) {
- payload.position(payload.position() + plmnLen);
- return null;
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
}
-
- int plmnCount = payload.get() & BYTE_MASK;
- return new CellularNetwork(plmnCount, payload);
+ if (!(thatObject instanceof CellularNetwork)) {
+ return false;
+ }
+ CellularNetwork that = (CellularNetwork) thatObject;
+ return mPlmnList.equals(that.mPlmnList);
}
@Override
- public Iterator<String> iterator() {
- return mMccMnc.iterator();
+ public int hashCode() {
+ return mPlmnList.hashCode();
}
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("PLMN:");
- for (String mccMnc : mMccMnc) {
- sb.append(' ').append(mccMnc);
- }
- return sb.toString();
+ return "CellularNetwork{mPlmnList=" + mPlmnList + "}";
+ }
+
+ /**
+ * Parse the PLMN information from the given buffer. A string representing a hex value
+ * of |MCC|MNC| will be returned.
+ *
+ * PLMN Coding Format:
+ * b7 b0
+ * | MCC Digit 2 | MCC Digit 1 |
+ * | MNC Digit 3 | MCC Digit 3 |
+ * | MNC Digit 2 | MNC Digit 1 |
+ *
+ * @param payload The buffer to read from.
+ * @return {@Link String}
+ * @throws BufferUnderflowException
+ */
+ private static String parsePlmn(ByteBuffer payload) {
+ byte[] plmn = new byte[PLMN_DATA_BYTES];
+ payload.get(plmn);
+
+ // Formatted as | MCC Digit 1 | MCC Digit 2 | MCC Digit 3 |
+ int mcc = ((plmn[0] << 8) & 0xF00) | (plmn[0] & 0x0F0) | (plmn[1] & 0x00F);
+
+ // Formated as |MNC Digit 1 | MNC Digit 2 |
+ int mnc = ((plmn[2] << 4) & 0xF0) | ((plmn[2] >> 4) & 0x0F);
+
+ // The digit 3 of MNC decides if the MNC is 2 or 3 digits number. When it is equal to
+ // 0xF, MNC is a 2 digit value. Otherwise, it is a 3 digit number.
+ int mncDigit3 = (plmn[1] >> 4) & 0x0F;
+ return (mncDigit3 != MNC_2DIGIT_VALUE)
+ ? String.format("%03x%03x", mcc, (mnc << 4) | mncDigit3)
+ : String.format("%03x%02x", mcc, mnc);
}
}
diff --git a/service/java/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElement.java b/service/java/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElement.java
index 8436ae3ee..d9795c63d 100644
--- a/service/java/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElement.java
+++ b/service/java/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElement.java
@@ -1,53 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.wifi.hotspot2.anqp;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import static com.android.server.wifi.hotspot2.anqp.Constants.BYTE_MASK;
-
/**
- * The 3GPP Cellular Network ANQP Element, IEEE802.11-2012 section 8.4.4.11
+ * The 3GPP Cellular Network ANQP Element, IEEE802.11-2012 section 8.4.4.11.
+ * The value is embedded in a Generic container User Data (GUD).
+ * Refer to Annex A of 3GPP TS 24.234 version 11.3.0 for more info:
+ * (http://www.etsi.org/deliver/etsi_ts/124200_124299/124234/11.03.00_60/ts_124234v110300p.pdf).
+ *
+ * Format:
+ * | GUD Version | Length | IEI 1 | ... | IEI N|
+ * 1 1 variable
+ *
*/
public class ThreeGPPNetworkElement extends ANQPElement {
- private final int mUserData;
- private final List<CellularNetwork> mPlmns;
+ /**
+ * The expected protocol version number of the Generic container User Data (GUD).
+ */
+ @VisibleForTesting
+ public static final int GUD_VERSION_1 = 0;
- public ThreeGPPNetworkElement(Constants.ANQPElementType infoID, ByteBuffer payload)
+ private final List<CellularNetwork> mNetworks;
+
+ @VisibleForTesting
+ public ThreeGPPNetworkElement(List<CellularNetwork> networks) {
+ super(Constants.ANQPElementType.ANQP3GPPNetwork);
+ mNetworks = networks;
+ }
+
+ /**
+ * Parse a ThreeGPPNetworkElement from the given buffer.
+ *
+ * @param payload The byte buffer to read from
+ * @return {@link ThreeGPPNetworkElement}
+ * @throws BufferUnderflowException
+ * @throws ProtocolException
+ */
+ public static ThreeGPPNetworkElement parse(ByteBuffer payload)
throws ProtocolException {
- super(infoID);
+ // Verify version.
+ int gudVersion = payload.get() & 0xFF;
+ if (gudVersion != GUD_VERSION_1) {
+ throw new ProtocolException("Unsupported GUD version: " + gudVersion);
+ }
- mPlmns = new ArrayList<CellularNetwork>();
- mUserData = payload.get() & BYTE_MASK;
- int length = payload.get() & BYTE_MASK;
- if (length > payload.remaining()) {
- throw new ProtocolException("Runt payload");
+ // Verify length.
+ int length = payload.get() & 0xFF;
+ if (length != payload.remaining()) {
+ throw new ProtocolException("Mismatch length and buffer size: length=" + length
+ + " bufferSize=" + payload.remaining());
}
+ // Parse each IEI (Information Element Identity) content.
+ List<CellularNetwork> networks = new ArrayList<>();
while (payload.hasRemaining()) {
- CellularNetwork network = CellularNetwork.buildCellularNetwork(payload);
+ CellularNetwork network = CellularNetwork.parse(payload);
if (network != null) {
- mPlmns.add(network);
+ networks.add(network);
}
}
+ return new ThreeGPPNetworkElement(networks);
}
- public int getUserData() {
- return mUserData;
+ public List<CellularNetwork> getNetworks() {
+ return Collections.unmodifiableList(mNetworks);
}
- public List<CellularNetwork> getPlmns() {
- return Collections.unmodifiableList(mPlmns);
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof ThreeGPPNetworkElement)) {
+ return false;
+ }
+ ThreeGPPNetworkElement that = (ThreeGPPNetworkElement) thatObject;
+ return mNetworks.equals(that.mNetworks);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return mNetworks.hashCode();
}
@Override
public String toString() {
- return "ThreeGPPNetwork{" +
- "mUserData=" + mUserData +
- ", mPlmns=" + mPlmns +
- '}';
+ return "ThreeGPPNetwork{mNetworks=" + mNetworks + "}";
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTest.java
new file mode 100644
index 000000000..50ab18935
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2.anqp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.CellularNetwork}.
+ */
+@SmallTest
+public class CellularNetworkTest {
+ private static final byte[] TEST_PLMN_BYTES_1 = new byte[] {0x12, 0x34, 0x56};
+ private static final String TEST_PLMN_STRING_1 = "214653";
+ private static final byte[] TEST_PLMN_BYTES_2 = new byte[] {0x13, (byte) 0xF9, 0x32};
+ private static final String TEST_PLMN_STRING_2 = "31923";
+
+ /**
+ * Verify that BufferUnderflowException will be thrown when parsing an empty buffer.
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseBufferWithEmptyBuffer() throws Exception {
+ CellularNetwork.parse(ByteBuffer.allocate(0));
+ }
+
+ /**
+ * Verify that a null will be returned when parsing a buffer contained an unsupported IEI type.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithInvalidIEIType() throws Exception {
+ byte[][] plmnsData = new byte[][] {TEST_PLMN_BYTES_1, TEST_PLMN_BYTES_2};
+ byte[] testData = CellularNetworkTestUtil.formatPLMNListIEI(1, plmnsData);
+ assertNull(CellularNetwork.parse(ByteBuffer.wrap(testData)));
+ }
+
+ /**
+ * Verify that BufferUnderflowException will be thrown when parsing a truncated buffer
+ * (missing a byte at the end).
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseBufferWithIncompleteData() throws Exception {
+ byte[][] plmnsData = new byte[][] {TEST_PLMN_BYTES_1, TEST_PLMN_BYTES_2};
+ byte[] testData = CellularNetworkTestUtil.formatPLMNListIEI(plmnsData);
+ CellularNetwork.parse(ByteBuffer.wrap(testData, 0, testData.length - 1));
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when IEI size and the PLMN count doesn't
+ * match.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithMismatchIEISizeAndPLMNCount() throws Exception {
+ byte[][] plmnsData = new byte[][] {TEST_PLMN_BYTES_1, TEST_PLMN_BYTES_2};
+ // Get test data with IEI size set to incorrect value.
+ byte[] testData = CellularNetworkTestUtil.formatPLMNListIEI(
+ CellularNetwork.IEI_TYPE_PLMN_LIST, plmnsData, true);
+ CellularNetwork.parse(ByteBuffer.wrap(testData));
+ }
+
+ /**
+ * Verify that the expected ProtocolPortTuple is returned when parsing a buffer contained
+ * the test data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithTestData() throws Exception {
+ byte[][] plmnsData = new byte[][] {TEST_PLMN_BYTES_1, TEST_PLMN_BYTES_2};
+ byte[] testData = CellularNetworkTestUtil.formatPLMNListIEI(plmnsData);
+
+ // Setup the expected CellularNetwork.
+ List<String> plmnList = new ArrayList<>();
+ plmnList.add(TEST_PLMN_STRING_1);
+ plmnList.add(TEST_PLMN_STRING_2);
+ CellularNetwork expected = new CellularNetwork(plmnList);
+
+ assertEquals(expected, CellularNetwork.parse(ByteBuffer.wrap(testData)));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTestUtil.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTestUtil.java
new file mode 100644
index 000000000..dad2919f0
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/CellularNetworkTestUtil.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2.anqp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Utility class for formatting IEI (Information Element Identity) data for testing.
+ */
+public class CellularNetworkTestUtil {
+ /**
+ * Format and return PLMN List IEI with the given PLMN list data.
+ *
+ * @param plmnList The array of PLMN data
+ * @return byte[]
+ * @throws IOException
+ */
+ public static byte[] formatPLMNListIEI(byte[][] plmnList) throws IOException {
+ return formatPLMNListIEI(CellularNetwork.IEI_TYPE_PLMN_LIST, plmnList);
+ }
+
+ /**
+ * Format and return PLMN List IEI with the given IEI type and PLMN list data. This
+ * allows the test to use an invalid IEI type for testing purpose.
+ *
+ * @param ieiType The IEI type
+ * @param plmnList The array of PLMN data
+ * @return byte[]
+ * @throws IOException
+ */
+ public static byte[] formatPLMNListIEI(int ieiType, byte[][] plmnList) throws IOException {
+ return formatPLMNListIEI(ieiType, plmnList, false);
+ }
+
+ /**
+ * Format and return PLMN List IEI with the given IEI type and PLMN list data. This also
+ * allows the test to intentionally setting an incorrect size value.
+ *
+ * @param ieiType The IEI type
+ * @param plmnList The array of PLMN data
+ * @param setWrongSize Flag for setting incorrect IEI size
+ * @return byte[]
+ * @throws IOException
+ */
+ public static byte[] formatPLMNListIEI(int ieiType, byte[][] plmnList, boolean setWrongSize)
+ throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+ // Calculate the total bytes for all the PLMNs.
+ int plmnsSize = getDataSize(plmnList);
+
+ // Use incorrect size intentionally.
+ if (setWrongSize) plmnsSize -= 1;
+
+ stream.write((byte) ieiType);
+ // One extra byte for the PLMN count field.
+ stream.write((byte) ((plmnsSize + 1) & CellularNetwork.IEI_CONTENT_LENGTH_MASK));
+ stream.write((byte) plmnList.length);
+ for (byte[] plmn : plmnList) {
+ stream.write(plmn);
+ }
+
+ return stream.toByteArray();
+ }
+
+ /**
+ * Return the number of bytes in a 2D array.
+ *
+ * @param dataArray The 2D array
+ * @return The number of bytes in the 2D array
+ */
+ public static int getDataSize(byte[][] dataArray) {
+ int size = 0;
+ for (byte[] data : dataArray) {
+ size += data.length;
+ }
+ return size;
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElementTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElementTest.java
new file mode 100644
index 000000000..02d45ef46
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/ThreeGPPNetworkElementTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2.anqp;
+
+import static org.junit.Assert.assertEquals;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.ThreeGPPNetworkElement}.
+ */
+@SmallTest
+public class ThreeGPPNetworkElementTest {
+ private static final byte[][] TEST_NETWORK1_PLMN_BYTES =
+ new byte[][] { new byte[] {0x21, 0x63, 0x54},
+ new byte[] {0x43, (byte) 0x85, 0x76} };
+ private static final List<String> TEST_NETWORK1_PLMN_LIST = new ArrayList<>();
+ static {
+ TEST_NETWORK1_PLMN_LIST.add("123456");
+ TEST_NETWORK1_PLMN_LIST.add("345678");
+ }
+ private static final CellularNetwork TEST_NETWORK1 =
+ new CellularNetwork(TEST_NETWORK1_PLMN_LIST);
+
+ private static final byte[][] TEST_NETWORK2_PLMN_BYTES =
+ new byte[][] { new byte[] {(byte) 0x87, 0x29, 0x10},
+ new byte[] {0x62, (byte) 0xF5, 0x73} };
+ private static final List<String> TEST_NETWORK2_PLMN_LIST = new ArrayList<>();
+ static {
+ TEST_NETWORK2_PLMN_LIST.add("789012");
+ TEST_NETWORK2_PLMN_LIST.add("26537");
+ }
+ private static final CellularNetwork TEST_NETWORK2 =
+ new CellularNetwork(TEST_NETWORK2_PLMN_LIST);
+
+ /**
+ * Helper function for generating test data.
+ *
+ * @param version The GUD version number
+ * @param ieiList The array containing IEI data
+ * @return byte[]
+ * @throws IOException
+ */
+ private static byte[] getTestData(int version, byte[][] ieiList)
+ throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ int totalIeiSize = CellularNetworkTestUtil.getDataSize(ieiList);
+ stream.write((byte) version);
+ stream.write((byte) totalIeiSize);
+ for (byte[] iei : ieiList) {
+ stream.write(iei);
+ }
+ return stream.toByteArray();
+ }
+
+ /**
+ * Verify that BufferUnderflowException will be thrown when parsing an empty buffer.
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseBufferWithEmptyBuffer() throws Exception {
+ ThreeGPPNetworkElement.parse(ByteBuffer.allocate(0));
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when parsing an buffer contained
+ * an unsupported version number.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithUnsupportedVersionNumber() throws Exception {
+ byte[][] testIeiList = new byte[][] {
+ CellularNetworkTestUtil.formatPLMNListIEI(TEST_NETWORK1_PLMN_BYTES) };
+ byte[] testData = getTestData(1, testIeiList);
+ ThreeGPPNetworkElement.parse(ByteBuffer.wrap(testData));
+ }
+
+ /**
+ * Verify that Protocol will be thrown when parsing a truncated buffer (missing a
+ * byte at the end), which will cause a inconsistency between the length value and
+ * the buffer size.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithIncompleteData() throws Exception {
+ byte[][] testIeiList = new byte[][] {
+ CellularNetworkTestUtil.formatPLMNListIEI(TEST_NETWORK1_PLMN_BYTES) };
+ byte[] testData = getTestData(ThreeGPPNetworkElement.GUD_VERSION_1, testIeiList);
+ ThreeGPPNetworkElement.parse(ByteBuffer.wrap(testData, 0, testData.length - 1));
+ }
+
+ /**
+ * Verify that the expected ThreeGPPNetworkElement is returned when parsing a buffer contained
+ * the test data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithTestData() throws Exception {
+ byte[][] testIeiList = new byte[][] {
+ CellularNetworkTestUtil.formatPLMNListIEI(TEST_NETWORK1_PLMN_BYTES),
+ CellularNetworkTestUtil.formatPLMNListIEI(TEST_NETWORK2_PLMN_BYTES) };
+ byte[] testData = getTestData(ThreeGPPNetworkElement.GUD_VERSION_1, testIeiList);
+
+ // Setup the expected ThreeGPPNetworkElement.
+ List<CellularNetwork> networkList = new ArrayList<>();
+ networkList.add(TEST_NETWORK1);
+ networkList.add(TEST_NETWORK2);
+ ThreeGPPNetworkElement expected = new ThreeGPPNetworkElement(networkList);
+
+ assertEquals(expected, ThreeGPPNetworkElement.parse(ByteBuffer.wrap(testData)));
+ }
+}