diff options
author | Shantur Rathore <shantur.rathore@gmail.com> | 2014-12-03 16:20:10 +0000 |
---|---|---|
committer | Nolen Johnson <johnsonnolen@gmail.com> | 2020-02-17 06:31:13 +0200 |
commit | e335f5378ab958fd1a088f4ce52d92d3366a9a49 (patch) | |
tree | bd10e762e8fe01dc248ba972b86555128753b794 | |
parent | fa92c370940268c21f03a198377d6f2354b451e0 (diff) | |
download | android_frameworks_opt_telephony-e335f5378ab958fd1a088f4ce52d92d3366a9a49.tar.gz android_frameworks_opt_telephony-e335f5378ab958fd1a088f4ce52d92d3366a9a49.tar.bz2 android_frameworks_opt_telephony-e335f5378ab958fd1a088f4ce52d92d3366a9a49.zip |
Implement UICC TLV Data decoding.
Some phones / SIMs returns data in TLV format as decribed in ETSI TS 102 221 11.1.1
This enables parsing of TLV data if it finds one. This fixes reading of SIM_IO
data like ICCID, MSISDN, etc on affected SIMs.
In CM-12 this is needed for phone to function properly. In CM-12 Multisim support
requires ICCID. If ICCID is not found then user is unable to make any outgoing
calls. User is shown "Call not sent" error.
Change-Id: I0fe20a9ec4cdd6021e7cb614ae578bc1c2c1d1fd
(cherry picked from commit 70a14292e926db8694c03ac21956eb1c8c0b9cc5)
(cherry picked from commit 64f87575de449734eac641188785142d5c6a11a6)
-rw-r--r-- | src/java/com/android/internal/telephony/uicc/IccFileHandler.java | 91 | ||||
-rw-r--r-- | src/java/com/android/internal/telephony/uicc/UiccTlvData.java | 154 |
2 files changed, 217 insertions, 28 deletions
diff --git a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java index 33dd3819a..82663ee7b 100644 --- a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java @@ -291,7 +291,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants { fileid, 0, onLoaded); mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response); + 0, 0, 0, null, null, mAid, response); } /** @@ -449,16 +449,29 @@ public abstract class IccFileHandler extends Handler implements IccConstants { data = result.payload; - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || - EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } + if (UiccTlvData.isUiccTlvData(data)) { + UiccTlvData tlvData = UiccTlvData.parse(data); - recordSize = new int[3]; - recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - recordSize[2] = recordSize[1] / recordSize[0]; + if (tlvData.isIncomplete()) { + throw new IccFileTypeMismatch(); + } + + recordSize = new int[3]; + recordSize[0] = tlvData.mRecordSize; + recordSize[1] = tlvData.mFileSize; + recordSize[2] = tlvData.mNumRecords; + } else { + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || + EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + recordSize = new int[3]; + recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + recordSize[2] = recordSize[1] / recordSize[0]; + } sendResult(response, recordSize, null); break; @@ -478,20 +491,32 @@ public abstract class IccFileHandler extends Handler implements IccConstants { data = result.payload; path = lc.mPath; - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new IccFileTypeMismatch(); - } + if (UiccTlvData.isUiccTlvData(data)) { + UiccTlvData tlvData = UiccTlvData.parse(data); - if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } + if (tlvData.isIncomplete()) { + throw new IccFileTypeMismatch(); + } + + lc.mRecordSize = tlvData.mRecordSize; + lc.mCountRecords = tlvData.mNumRecords; + size = tlvData.mFileSize; + } else { + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } - lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - lc.mCountRecords = size / lc.mRecordSize; + lc.mCountRecords = size / lc.mRecordSize; + } if (lc.mLoadAll) { lc.results = new ArrayList<byte[]>(lc.mCountRecords); @@ -524,16 +549,26 @@ public abstract class IccFileHandler extends Handler implements IccConstants { + IccUtils.bytesToHexString(data)); } - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new IccFileTypeMismatch(); - } + if (UiccTlvData.isUiccTlvData(data)) { + UiccTlvData tlvData = UiccTlvData.parse(data); - if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } + if (tlvData.mFileSize < 0) { + throw new IccFileTypeMismatch(); + } - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + size = tlvData.mFileSize; + } else { + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + } mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid), 0, 0, size, null, null, mAid, diff --git a/src/java/com/android/internal/telephony/uicc/UiccTlvData.java b/src/java/com/android/internal/telephony/uicc/UiccTlvData.java new file mode 100644 index 000000000..5f35e41d6 --- /dev/null +++ b/src/java/com/android/internal/telephony/uicc/UiccTlvData.java @@ -0,0 +1,154 @@ +package com.android.internal.telephony.uicc; + +/** + * UICC TLV Data Parser according to ETSI TS 102 221 spec. + */ +public class UiccTlvData { + + private static final int TLV_FORMAT_ID = 0x62; + + private static final int TAG_FILE_DESCRIPTOR = 0x82; + private static final int TAG_FILE_IDENTIFIER = 0x83; + private static final int TAG_PROPRIETARY_INFO = 0xA5; + private static final int TAG_LIFECYCLE_STATUS = 0x8A; + private static final int TAG_SECURITY_ATTR_1 = 0x8B; + private static final int TAG_SECURITY_ATTR_2 = 0x8C; + private static final int TAG_SECURITY_ATTR_3 = 0xAB; + private static final int TAG_FILE_SIZE = 0x80; + private static final int TAG_TOTAL_FILE_SIZE = 0x81; + private static final int TAG_SHORT_FILE_IDENTIFIER = 0x88; + + private static final int TYPE_5 = 5; + private static final int TYPE_2 = 2; + + int mRecordSize; + int mFileSize; + int mNumRecords; + boolean mIsDataEnough; + + private int mFileType = -1; + + private UiccTlvData() { + mNumRecords = -1; + mFileSize = -1; + mRecordSize = -1; + } + + public boolean isIncomplete() { + return mNumRecords == -1 || mFileSize == -1 || mRecordSize == -1 || mFileType == -1; + } + + public static boolean isUiccTlvData(byte[] data) { + if(data != null && data.length > 0 && TLV_FORMAT_ID == (data[0] & 0xFF)) { + return true; + } + return false; + } + + public static UiccTlvData parse(byte[] data) throws IccFileTypeMismatch{ + + UiccTlvData parsedData = new UiccTlvData(); + + if (data == null || data.length == 0 || TLV_FORMAT_ID != (data[0] & 0xFF)) { + throw new IccFileTypeMismatch(); + } + + try { + + int currentLocation = 2; //Ignore FCP size + int currentTag; + + while (currentLocation < data.length) { + currentTag = data[currentLocation++] & 0xFF; + + switch (currentTag) { + case TAG_FILE_DESCRIPTOR: + currentLocation = parsedData.parseFileDescriptor(data, currentLocation); + break; + + case TAG_FILE_SIZE: + currentLocation = parsedData.parseFileSize(data, currentLocation); + break; + + case TAG_FILE_IDENTIFIER: + case TAG_PROPRIETARY_INFO: + case TAG_LIFECYCLE_STATUS: + case TAG_SECURITY_ATTR_1: + case TAG_SECURITY_ATTR_2: + case TAG_SECURITY_ATTR_3: + case TAG_TOTAL_FILE_SIZE: + case TAG_SHORT_FILE_IDENTIFIER: + currentLocation = parsedData.parseSomeTag(data, currentLocation); + break; + + default: + //Unknown TAG + throw new IccFileTypeMismatch(); + + } + } + + } catch (ArrayIndexOutOfBoundsException e) { + + //We might be looking at incomplete data but we might have what we need. + //Ignore this and let caller handle it by checking isIncomplete + } + + return parsedData; + } + + private int parseFileSize(byte[] data, int currentLocation) { + int length = data[currentLocation++] & 0xFF; + + int fileSize = 0; + for (int i = 0; i < length; i++) { + fileSize += ((data[currentLocation + i] & 0xFF) << ( 8 * (length - i - 1))); + } + + mFileSize = fileSize; + + if (mFileType == TYPE_2) { + mRecordSize = fileSize; + } + + return currentLocation + length; + } + + private int parseSomeTag(byte[] data, int currentLocation) { + //Just skip unwanted tags; + int length = data[currentLocation++] & 0xFF; + return currentLocation + length; + } + + private int parseFileDescriptor(byte[] data, int currentLocation) throws IccFileTypeMismatch { + int length = data[currentLocation++] & 0xFF; + if (length == 5) { + + mRecordSize = ((data[currentLocation + 2] & 0xFF) << 8) + + (data[currentLocation + 3] & 0xFF); // Length of 1 record + mNumRecords = data[currentLocation + 4] & 0xFF; // Number of records + + mFileSize = mRecordSize * mNumRecords; + + mFileType = TYPE_5; + + return currentLocation + 5; + } else if (length == 2) { + + int descriptorByte = data[currentLocation + 1] & 0xFF; + + //Ignore descriptorByte for now + + mNumRecords = 1; + + mFileType = TYPE_2; + + return currentLocation + 2; + + } else { + throw new IccFileTypeMismatch(); + } + } + +} + |