10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/* 20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2006 The Android Open Source Project 30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License. 60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at 70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * http://www.apache.org/licenses/LICENSE-2.0 90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software 110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS, 120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and 140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License. 150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony.cat; 180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.List; 200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/** 220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Class for representing BER-TLV objects. 230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @see "ETSI TS 102 223 Annex C" for more information. 250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@hide} 270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleclass BerTlv { 290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private int mTag = BER_UNKNOWN_TAG; 300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private List<ComprehensionTlv> mCompTlvs = null; 319edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang private boolean mLengthValid = true; 320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public static final int BER_UNKNOWN_TAG = 0x00; 340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public static final int BER_PROACTIVE_COMMAND_TAG = 0xd0; 350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public static final int BER_MENU_SELECTION_TAG = 0xd3; 360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public static final int BER_EVENT_DOWNLOAD_TAG = 0xd6; 370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 389edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang private BerTlv(int tag, List<ComprehensionTlv> ctlvs, boolean lengthValid) { 390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mTag = tag; 400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCompTlvs = ctlvs; 419edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang mLengthValid = lengthValid; 420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Gets a list of ComprehensionTlv objects contained in this BER-TLV object. 460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return A list of COMPREHENSION-TLV object 480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public List<ComprehensionTlv> getComprehensionTlvs() { 500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return mCompTlvs; 510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Gets a tag id of the BER-TLV object. 550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return A tag integer. 570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public int getTag() { 590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return mTag; 600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 639edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang * Gets if the length of the BER-TLV object is valid 649edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang * 659edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang * @return if length valid 669edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang */ 679edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang public boolean isLengthValid() { 689edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang return mLengthValid; 699edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang } 709edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang 719edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang /** 720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Decodes a BER-TLV object from a byte array. 730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param data A byte array to decode from 750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return A BER-TLV object decoded 760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @throws ResultException 770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public static BerTlv decode(byte[] data) throws ResultException { 790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int curIndex = 0; 800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int endIndex = data.length; 810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int tag, length = 0; 829edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang boolean isLengthValid = true; 830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville try { 850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /* tag */ 860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville tag = data[curIndex++] & 0xff; 870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (tag == BER_PROACTIVE_COMMAND_TAG) { 880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /* length */ 890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int temp = data[curIndex++] & 0xff; 900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (temp < 0x80) { 910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville length = temp; 920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else if (temp == 0x81) { 930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville temp = data[curIndex++] & 0xff; 940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (temp < 0x80) { 950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville throw new ResultException( 960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ResultCode.CMD_DATA_NOT_UNDERSTOOD, 970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville "length < 0x80 length=" + Integer.toHexString(length) + 980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville " curIndex=" + curIndex + " endIndex=" + endIndex); 990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville length = temp; 1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville throw new ResultException( 1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ResultCode.CMD_DATA_NOT_UNDERSTOOD, 1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville "Expected first byte to be length or a length tag and < 0x81" + 1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville " byte= " + Integer.toHexString(temp) + " curIndex=" + curIndex + 1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville " endIndex=" + endIndex); 1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (ComprehensionTlvTag.COMMAND_DETAILS.value() == (tag & ~0x80)) { 1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville tag = BER_UNKNOWN_TAG; 1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville curIndex = 0; 1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (IndexOutOfBoundsException e) { 1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING, 1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville "IndexOutOfBoundsException " + 1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville " curIndex=" + curIndex + " endIndex=" + endIndex); 1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (ResultException e) { 1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD, e.explanation()); 1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /* COMPREHENSION-TLVs */ 1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (endIndex - curIndex < length) { 1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD, 1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville "Command had extra data endIndex=" + endIndex + " curIndex=" + curIndex + 1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville " length=" + length); 1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville List<ComprehensionTlv> ctlvs = ComprehensionTlv.decodeMany(data, 1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville curIndex); 1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1339edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang if (tag == BER_PROACTIVE_COMMAND_TAG) { 1349edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang int totalLength = 0; 1359edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang for (ComprehensionTlv item : ctlvs) { 1369edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang int itemLength = item.getLength(); 1379edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang if (itemLength >= 0x80 && itemLength <= 0xFF) { 1389edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang totalLength += itemLength + 3; //3: 'tag'(1 byte) and 'length'(2 bytes). 1399edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang } else if (itemLength >= 0 && itemLength < 0x80) { 1409edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang totalLength += itemLength + 2; //2: 'tag'(1 byte) and 'length'(1 byte). 1419edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang } else { 1429edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang isLengthValid = false; 1439edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang break; 1449edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang } 1459edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang } 1469edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang 1479edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang // According to 3gpp11.14, chapter 6.10.6 "Length errors", 1489edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang 1499edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang // If the total lengths of the SIMPLE-TLV data objects are not 1509edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang // consistent with the length given in the BER-TLV data object, 1519edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang // then the whole BER-TLV data object shall be rejected. The 1529edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang // result field in the TERMINAL RESPONSE shall have the error 1539edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang // condition "Command data not understood by ME". 1549edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang if (length != totalLength) { 1559edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang isLengthValid = false; 1569edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang } 1579edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang } 1589edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang 1599edadf11a7ac700a529f49e46822e2983ed551e4Sanny Shang return new BerTlv(tag, ctlvs, isLengthValid); 1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville} 162