154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu/* 254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Copyright (C) 2016 The Android Open Source Project 354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Licensed under the Apache License, Version 2.0 (the "License"); 554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * you may not use this file except in compliance with the License. 654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * You may obtain a copy of the License at 754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * http://www.apache.org/licenses/LICENSE-2.0 954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 1054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Unless required by applicable law or agreed to in writing, software 1154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * distributed under the License is distributed on an "AS IS" BASIS, 1254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * See the License for the specific language governing permissions and 1454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * limitations under the License. 1554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 1654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 178ca4ac971a9b862fbd69c57af3a3c0029a6b9f4dPeter Qiupackage com.android.server.wifi.hotspot2.anqp; 1871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 1954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport android.util.Log; 2054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 2154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport com.android.internal.annotations.VisibleForTesting; 2254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 237ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvistimport java.net.ProtocolException; 2454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport java.nio.BufferUnderflowException; 2571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.nio.ByteBuffer; 2671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.ArrayList; 2754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport java.util.Collections; 2871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.List; 2971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 3054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu/** 3154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * The IEI (Information Element Identity) contained in the Generic Container for the 3254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 3GPP Cellular Network ANQP element. 3354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 3454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Refer to Annex A of 3GPP TS 24.234 version 11.3.0 for information on the data format: 3554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * (http://www.etsi.org/deliver/etsi_ts/124200_124299/124234/11.03.00_60/ts_124234v110300p.pdf) 3654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 3754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiupublic class CellularNetwork { 3854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu private static final String TAG = "CellularNetwork"; 3971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 4054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu /** 4154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * IEI type for PLMN (Public Land Mobile Network) list. 4254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 4354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu @VisibleForTesting 4454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public static final int IEI_TYPE_PLMN_LIST = 0; 4571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 4654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu @VisibleForTesting 4754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public static final int IEI_CONTENT_LENGTH_MASK = 0x7F; 4871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 4954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu /** 5054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Number of bytes for each PLMN (Public Land Mobile Network). 5154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 5254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu @VisibleForTesting 5354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public static final int PLMN_DATA_BYTES = 3; 5471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 5554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu /** 5654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * The value for comparing the third digit of MNC data with to determine if the MNC is 5754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * two or three digits. 5854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 5954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu private static final int MNC_2DIGIT_VALUE = 0xF; 6054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 6154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu /** 6254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * List of PLMN (Public Land Mobile Network) information. 6354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 6454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu private final List<String> mPlmnList; 6554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 6654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu @VisibleForTesting 6754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public CellularNetwork(List<String> plmnList) { 6854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu mPlmnList = plmnList; 6954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu } 7054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 7154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu /** 7254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Parse a CellularNetwork from the given buffer. 7354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 7454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * @param payload The byte buffer to read from 7554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * @return {@link CellularNetwork} 7654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * @throws ProtocolException 7754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * @throws BufferUnderflowException 7854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 7954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public static CellularNetwork parse(ByteBuffer payload) throws ProtocolException { 8054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu int ieiType = payload.get() & 0xFF; 8154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu int ieiSize = payload.get() & IEI_CONTENT_LENGTH_MASK; 8271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 8354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // Skip this IEI if it is an unsupported type. 8454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu if (ieiType != IEI_TYPE_PLMN_LIST) { 8554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu Log.e(TAG, "Ignore unsupported IEI Type: " + ieiType); 8654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // Advance the buffer position to the next IEI. 8754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu payload.position(payload.position() + ieiSize); 8854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return null; 8954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu } 9071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 9154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // Get PLMN count. 9254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu int plmnCount = payload.get() & 0xFF; 9371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 9454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // Verify IEI size with PLMN count. The IEI size contained the PLMN count field plus 9554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // the bytes for the PLMNs. 9654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu if (ieiSize != (plmnCount * PLMN_DATA_BYTES + 1)) { 9754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu throw new ProtocolException("IEI size and PLMN count mismatched: IEI Size=" + ieiSize 9854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu + " PLMN Count=" + plmnCount); 9954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu } 10071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 10154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // Process each PLMN. 10254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu List<String> plmnList = new ArrayList<>(); 10354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu while (plmnCount > 0) { 10454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu plmnList.add(parsePlmn(payload)); 1057ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist plmnCount--; 10671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 10754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return new CellularNetwork(plmnList); 10871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 10971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 11054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public List<String> getPlmns() { 11154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return Collections.unmodifiableList(mPlmnList); 11254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu } 11371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 11454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu @Override 11554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public boolean equals(Object thatObject) { 11654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu if (this == thatObject) { 11754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return true; 11871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 11954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu if (!(thatObject instanceof CellularNetwork)) { 12054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return false; 12154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu } 12254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu CellularNetwork that = (CellularNetwork) thatObject; 12354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return mPlmnList.equals(that.mPlmnList); 12471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 12571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 12607f11f6f2ee7ec17cb08180035dfb5002aaaf5dfJan Nordqvist @Override 12754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu public int hashCode() { 12854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return mPlmnList.hashCode(); 12971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 13071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 13171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist @Override 13271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public String toString() { 13354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return "CellularNetwork{mPlmnList=" + mPlmnList + "}"; 13454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu } 13554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 13654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu /** 13754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Parse the PLMN information from the given buffer. A string representing a hex value 13854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * of |MCC|MNC| will be returned. 13954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 14054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * PLMN Coding Format: 14154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * b7 b0 14254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * | MCC Digit 2 | MCC Digit 1 | 14354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * | MNC Digit 3 | MCC Digit 3 | 14454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * | MNC Digit 2 | MNC Digit 1 | 14554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 14654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * @param payload The buffer to read from. 14754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * @return {@Link String} 14854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * @throws BufferUnderflowException 14954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */ 15054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu private static String parsePlmn(ByteBuffer payload) { 15154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu byte[] plmn = new byte[PLMN_DATA_BYTES]; 15254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu payload.get(plmn); 15354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 15454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // Formatted as | MCC Digit 1 | MCC Digit 2 | MCC Digit 3 | 15554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu int mcc = ((plmn[0] << 8) & 0xF00) | (plmn[0] & 0x0F0) | (plmn[1] & 0x00F); 15654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 15754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // Formated as |MNC Digit 1 | MNC Digit 2 | 15854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu int mnc = ((plmn[2] << 4) & 0xF0) | ((plmn[2] >> 4) & 0x0F); 15954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu 16054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // The digit 3 of MNC decides if the MNC is 2 or 3 digits number. When it is equal to 16154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu // 0xF, MNC is a 2 digit value. Otherwise, it is a 3 digit number. 16254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu int mncDigit3 = (plmn[1] >> 4) & 0x0F; 16354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu return (mncDigit3 != MNC_2DIGIT_VALUE) 16454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu ? String.format("%03x%03x", mcc, (mnc << 4) | mncDigit3) 16554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu : String.format("%03x%02x", mcc, mnc); 16671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 16771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist} 168