Bug 798000 - Part 1 - Read EF_OPL, EF_PNN files and update network name. r=vicamo

This commit is contained in:
Patrick Wang 2012-12-11 17:11:34 +08:00
parent aa11c96fe6
commit a3cc5f89c2
2 changed files with 303 additions and 3 deletions

View File

@ -422,6 +422,7 @@ this.ICC_EF_CBMIR = 0x6f50;
this.ICC_EF_AD = 0x6fad;
this.ICC_EF_PHASE = 0x6fae;
this.ICC_EF_PNN = 0x6fc5;
this.ICC_EF_OPL = 0x6fc6;
this.ICC_EF_MBDN = 0x6fc7;
this.ICC_EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN]
this.ICC_EF_MBI = 0x6fc9;
@ -581,6 +582,11 @@ this.COMPREHENSIONTLV_TAG_BROADCAST_NETWORK_INFO = 0x7a;
this.SPDI_TAG_SPDI = 0xa3;
this.SPDI_TAG_PLMN_LIST = 0x80;
// MM INFORMATION message content IEIs
// See 3GPP TS 24.008 table 9.2.18
this.PNN_IEI_FULL_NETWORK_NAME = 0x43;
this.PNN_IEI_SHORT_NETWORK_NAME = 0x45;
// Device identifiers, see TS 11.14, clause 12.7
this.STK_DEVICE_ID_KEYPAD = 0x01;
this.STK_DEVICE_ID_DISPLAY = 0x02;
@ -988,6 +994,8 @@ this.GECKO_ICC_SERVICES = {
DATA_DOWNLOAD_SMS_PP: 26,
CBMIR: 30,
BDN: 31,
PNN: 51,
OPL: 52,
SPDI: 56
},
usim: {
@ -998,6 +1006,8 @@ this.GECKO_ICC_SERVICES = {
CBMIR: 16,
SPN: 19,
DATA_DOWNLOAD_SMS_PP: 28,
PNN: 45,
OPL: 46,
SPDI: 51
}
};

View File

@ -1671,6 +1671,219 @@ let RIL = {
(serviceTable[index] & bitmask)) != 0;
},
/**
* Choose network names using EF_OPL and EF_PNN
* See 3GPP TS 31.102 sec. 4.2.58 and sec. 4.2.59 for USIM,
* 3GPP TS 51.011 sec. 10.3.41 and sec. 10.3.42 for SIM.
*/
updateNetworkName: function updateNetworkName() {
let iccInfoPriv = this.iccInfoPrivate;
let iccInfo = this.iccInfo;
// We won't update network name if voice registration isn't ready
// or PNN file haven't been retrieved.
if (!iccInfoPriv.PNN ||
!this.voiceRegistrationState.cell ||
this.voiceRegistrationState.cell.gsmLocationAreaCode == -1) {
return null;
}
let pnnEntry;
let lac = this.voiceRegistrationState.cell.gsmLocationAreaCode;
let mcc = this.operator.mcc;
let mnc = this.operator.mnc;
// According to 3GPP TS 31.102 Sec. 4.2.59 and 3GPP TS 51.011 Sec. 10.3.42,
// the ME shall use this EF_OPL in association with the EF_PNN in place
// of any network name stored within the ME's internal list and any network
// name received when registered to the PLMN.
if (iccInfoPriv.OPL) {
for (let i in iccInfoPriv.OPL) {
let opl = iccInfoPriv.OPL[i];
// Try to match the MCC/MNC.
if (mcc != opl.mcc || mnc != opl.mnc) {
continue;
}
// Try to match the location area code. If current local area code is
// covered by lac range that specified in the OPL entry, use the PNN
// that specified in the OPL entry.
if ((opl.lacTacStart == 0x0 && opl.lacTacEnd == 0xFFFE) ||
(opl.lacTacStart <= lac && opl.lacTacEnd >= lac)) {
if (opl.pnnRecordId == 0) {
// See 3GPP TS 31.102 Sec. 4.2.59 and 3GPP TS 51.011 Sec. 10.3.42,
// A value of '00' indicates that the name is to be taken from other
// sources.
return null;
}
pnnEntry = iccInfoPriv.PNN[opl.pnnRecordId - 1]
break;
}
}
}
// According to 3GPP TS 31.102 Sec. 4.2.58 and 3GPP TS 51.011 Sec. 10.3.41,
// the first record in this EF is used for the default network name when
// registered to the HPLMN.
// If we haven't get pnnEntry assigned, we should try to assign default
// value to it.
if (!pnnEntry && mcc == iccInfo.mcc && mnc == iccInfo.mnc) {
pnnEntry = iccInfoPriv.PNN[0]
}
if (DEBUG) {
if (pnnEntry) {
debug("updateNetworkName: Network names will be overriden: longName = " +
pnnEntry.fullName + ", shortName = " + pnnEntry.shortName);
} else {
debug("updateNetworkName: Network names will not be overriden");
}
}
if (pnnEntry) {
return [pnnEntry.fullName, pnnEntry.shortName];
}
return null;
},
/**
* Read OPL (Operator PLMN List) from USIM.
*
* See 3GPP TS 31.102 Sec. 4.2.59 for USIM
* 3GPP TS 51.011 Sec. 10.3.42 for SIM.
*/
getOPL: function getOPL() {
let opl = [];
function callback(options) {
let len = Buf.readUint32();
// The first 7 bytes are LAI (for UMTS) and the format of LAI is defined
// in 3GPP TS 23.003, Sec 4.1
// +-------------+---------+
// | Octet 1 - 3 | MCC/MNC |
// +-------------+---------+
// | Octet 4 - 7 | LAC |
// +-------------+---------+
let mccMnc = [GsmPDUHelper.readHexOctet(),
GsmPDUHelper.readHexOctet(),
GsmPDUHelper.readHexOctet()];
if (mccMnc[0] != 0xFF || mccMnc[1] != 0xFF || mccMnc[2] != 0xFF) {
let oplElement = {};
let semiOctets = [];
for (let i = 0; i < mccMnc.length; i++) {
semiOctets.push((mccMnc[i] & 0xf0) >> 4);
semiOctets.push(mccMnc[i] & 0x0f);
}
let reformat = [semiOctets[1], semiOctets[0], semiOctets[3],
semiOctets[5], semiOctets[4], semiOctets[2]];
let buf = "";
for (let i = 0; i < reformat.length; i++) {
if (reformat[i] != 0xF) {
buf += GsmPDUHelper.semiOctetToBcdChar(reformat[i]);
}
if (i === 2) {
// 0-2: MCC
oplElement.mcc = parseInt(buf);
buf = "";
} else if (i === 5) {
// 3-5: MNC
oplElement.mnc = parseInt(buf);
}
}
// LAC/TAC
oplElement.lacTacStart =
(GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet();
oplElement.lacTacEnd =
(GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet();
// PLMN Network Name Record Identifier
oplElement.pnnRecordId = GsmPDUHelper.readHexOctet();
if (DEBUG) {
debug("OPL: [" + (opl.length + 1) + "]: " + JSON.stringify(oplElement));
}
opl.push(oplElement);
}
Buf.readStringDelimiter(len);
if (options.p1 < options.totalRecords) {
options.p1++;
this.iccIO(options);
} else {
this.iccInfoPrivate.OPL = opl;
}
}
this.iccIO({
command: ICC_COMMAND_GET_RESPONSE,
fileId: ICC_EF_OPL,
pathId: this._getPathIdForICCRecord(ICC_EF_OPL),
p1: 0, // For GET_RESPONSE, p1 = 0
p2: 0, // For GET_RESPONSE, p2 = 0
p3: GET_RESPONSE_EF_SIZE_BYTES,
data: null,
pin2: null,
type: EF_TYPE_LINEAR_FIXED,
callback: callback,
});
},
/**
* Read PNN (PLMN Network Name) from USIM.
*
* See 3GPP TS 31.102 Sec. 4.2.58 for USIM
* 3GPP TS 51.011 Sec. 10.3.41 for SIM.
*/
getPNN: function getPNN() {
let pnn = [];
function callback(options) {
let pnnElement = this.iccInfoPrivate.PNN = {};
let len = Buf.readUint32();
let readLen = 0;
while (len > readLen) {
let tlvTag = GsmPDUHelper.readHexOctet();
readLen = readLen + 2; // 1 Hex octet
if (tlvTag == 0xFF) {
// Unused byte
continue;
}
let tlvLen = GsmPDUHelper.readHexOctet();
let name;
switch (tlvTag) {
case PNN_IEI_FULL_NETWORK_NAME:
pnnElement.fullName = GsmPDUHelper.readNetworkName(tlvLen);
break;
case PNN_IEI_SHORT_NETWORK_NAME:
pnnElement.shortName = GsmPDUHelper.readNetworkName(tlvLen);
break;
default:
Buf.seekIncoming(PDU_HEX_OCTET_SIZE * tlvLen);
}
readLen += (tlvLen * 2 + 2);
}
if (DEBUG) {
debug("PNN: [" + (pnn.length + 1) + "]: " + JSON.stringify(pnnElement));
}
Buf.readStringDelimiter(len);
pnn.push(pnnElement);
if (options.p1 < options.totalRecords) {
options.p1++;
this.iccIO(options);
} else {
this.iccInfoPrivate.PNN = pnn;
}
}
this.iccIO({
command: ICC_COMMAND_GET_RESPONSE,
fileId: ICC_EF_PNN,
pathId: this._getPathIdForICCRecord(ICC_EF_PNN),
p1: 0, // For GET_RESPONSE, p1 = 0
p2: 0, // For GET_RESPONSE, p2 = 0
p3: GET_RESPONSE_EF_SIZE_BYTES,
data: null,
pin2: null,
type: EF_TYPE_LINEAR_FIXED,
callback: callback,
});
},
/**
* Read the (U)SIM Service Table from the ICC.
*/
@ -1705,6 +1918,20 @@ let RIL = {
if (DEBUG) debug("SPDI: SPDI service is not available");
}
if (this.isICCServiceAvailable("PNN")) {
if (DEBUG) debug("PNN: PNN is available");
this.getPNN();
} else {
if (DEBUG) debug("PNN: PNN is not available");
}
if (this.isICCServiceAvailable("OPL")) {
if (DEBUG) debug("OPL: OPL is available");
this.getOPL();
} else {
if (DEBUG) debug("OPL: OPL is not available");
}
if (this.isICCServiceAvailable("CBMI")) {
this.getCBMI();
} else {
@ -3643,6 +3870,8 @@ let RIL = {
case ICC_EF_SPDI:
case ICC_EF_CBMI:
case ICC_EF_CBMIR:
case ICC_EF_OPL:
case ICC_EF_PNN:
return EF_PATH_MF_SIM + EF_PATH_ADF_USIM;
default:
@ -3968,8 +4197,15 @@ let RIL = {
this.operator.shortName !== shortName ||
thisTuple !== networkTuple) {
this.operator.longName = longName;
this.operator.shortName = shortName;
let networkName = this.updateNetworkName();
if (networkName) {
this.operator.longName = networkName[0];
this.operator.shortName = networkName[1];
} else {
this.operator.longName = longName;
this.operator.shortName = shortName;
}
this.operator.mcc = 0;
this.operator.mnc = 0;
@ -7848,6 +8084,60 @@ let GsmPDUHelper = {
return msg;
},
/**
* Read network name.
*
* @param len Length of the information element.
* @return
* {
* networkName: network name.
* shouldIncludeCi: Should Country's initials included in text string.
* }
* @see TS 24.008 clause 10.5.3.5a.
*/
readNetworkName: function readNetworkName(len) {
// According to TS 24.008 Sec. 10.5.3.5a, the first octet is:
// bit 8: must be 1.
// bit 5-7: Text encoding.
// 000 - GSM default alphabet.
// 001 - UCS2 (16 bit).
// else - reserved.
// bit 4: MS should add the letters for Country's Initials and a space
// to the text string if this bit is true.
// bit 1-3: number of spare bits in last octet.
let codingInfo = GsmPDUHelper.readHexOctet();
if (!(codingInfo & 0x80)) {
return null;
}
let textEncoding = (codingInfo & 0x70) >> 4,
shouldIncludeCountryInitials = !!(codingInfo & 0x08),
spareBits = codingInfo & 0x07;
let resultString;
switch (textEncoding) {
case 0:
// GSM Default alphabet.
resultString = GsmPDUHelper.readSeptetsToString(
((len - 1) * 8 - spareBits) / 7, 0,
PDU_NL_IDENTIFIER_DEFAULT,
PDU_NL_IDENTIFIER_DEFAULT);
break;
case 1:
// UCS2 encoded.
resultString = this.readUCS2String(len - 1);
break;
default:
// Not an available text coding.
return null;
}
// TODO - Bug 820286: According to shouldIncludeCountryInitials, add
// country initials to the resulting string.
return resultString;
}
};
let StkCommandParamsFactory = {