Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e335f537 authored by Shantur Rathore's avatar Shantur Rathore Committed by Nolen Johnson
Browse files

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 70a14292)
(cherry picked from commit 64f87575)
parent fa92c370
Loading
Loading
Loading
Loading
+63 −28
Original line number Diff line number Diff line
@@ -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,6 +449,18 @@ public abstract class IccFileHandler extends Handler implements IccConstants {

                data = result.payload;

                if (UiccTlvData.isUiccTlvData(data)) {
                    UiccTlvData tlvData = UiccTlvData.parse(data);

                    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();
@@ -459,6 +471,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
                    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,6 +491,17 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
                data = result.payload;
                path = lc.mPath;

                if (UiccTlvData.isUiccTlvData(data)) {
                    UiccTlvData tlvData = UiccTlvData.parse(data);

                    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();
                    }
@@ -492,6 +516,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
                           + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);

                    lc.mCountRecords = size / lc.mRecordSize;
                }

                 if (lc.mLoadAll) {
                     lc.results = new ArrayList<byte[]>(lc.mCountRecords);
@@ -524,6 +549,15 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
                            + IccUtils.bytesToHexString(data));
                }

                if (UiccTlvData.isUiccTlvData(data)) {
                    UiccTlvData tlvData = UiccTlvData.parse(data);

                    if (tlvData.mFileSize < 0) {
                        throw new IccFileTypeMismatch();
                    }

                    size = tlvData.mFileSize;
                } else {
                    if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
                        throw new IccFileTypeMismatch();
                    }
@@ -534,6 +568,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants {

                    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,
+154 −0
Original line number Diff line number Diff line
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();
        }
    }

}