summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
Diffstat (limited to 'service')
-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
3 files changed, 222 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 + "}";
}
}