зеркало из https://github.com/mozilla/gecko-dev.git
Bug 793111 - Part 2 - getting PLMN list and deciding required carrier name component r=vicamo
This commit is contained in:
Родитель
f18d446d45
Коммит
f9a4e3cb65
|
@ -1497,6 +1497,8 @@ RadioInterfaceLayer.prototype = {
|
|||
oldIcc.mcc != message.mcc ||
|
||||
oldIcc.mnc != message.mnc ||
|
||||
oldIcc.spn != message.spn ||
|
||||
oldIcc.isDisplayNetworkNameRequired != message.isDisplayNetworkNameRequired ||
|
||||
oldIcc.isDisplaySpnRequired != message.isDisplaySpnRequired ||
|
||||
oldIcc.msisdn != message.msisdn;
|
||||
if (!iccInfoChanged) {
|
||||
return;
|
||||
|
|
|
@ -405,6 +405,7 @@ this.ICC_COMMAND_UPDATE_RECORD = 0xdc;
|
|||
this.ICC_EF_ICCID = 0x2fe2;
|
||||
this.ICC_EF_IMG = 0x4f20;
|
||||
this.ICC_EF_PBR = 0x4f30;
|
||||
this.ICC_EF_PLMNsel = 0x6f30; // PLMN for SIM
|
||||
this.ICC_EF_SST = 0x6f38;
|
||||
this.ICC_EF_UST = 0x6f38; // For USIM
|
||||
this.ICC_EF_ADN = 0x6f3a;
|
||||
|
@ -563,6 +564,10 @@ this.COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
|
|||
this.COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE = 0x2b;
|
||||
this.COMPREHENSIONTLV_TAG_URL = 0x31;
|
||||
|
||||
// Tags for Service Provider Display Information TLV
|
||||
this.SPDI_TAG_SPDI = 0xa3;
|
||||
this.SPDI_TAG_PLMN_LIST = 0x80;
|
||||
|
||||
// Device identifiers, see TS 11.14, clause 12.7
|
||||
this.STK_DEVICE_ID_KEYPAD = 0x01;
|
||||
this.STK_DEVICE_ID_DISPLAY = 0x02;
|
||||
|
@ -906,6 +911,8 @@ this.GECKO_ICC_SERVICES = {
|
|||
sim: {
|
||||
ADN: 2,
|
||||
FDN: 3,
|
||||
PLMNSEL: 7,
|
||||
SPN: 17,
|
||||
SDN: 18,
|
||||
DATA_DOWNLOAD_SMS_PP: 26,
|
||||
BDN: 31
|
||||
|
@ -914,7 +921,9 @@ this.GECKO_ICC_SERVICES = {
|
|||
FDN: 2,
|
||||
SDN: 4,
|
||||
BDN: 6,
|
||||
DATA_DOWNLOAD_SMS_PP: 28
|
||||
SPN: 19,
|
||||
DATA_DOWNLOAD_SMS_PP: 28,
|
||||
SPDI: 51
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -703,6 +703,11 @@ let RIL = {
|
|||
this.IMEISV = null;
|
||||
this.SMSC = null;
|
||||
|
||||
/**
|
||||
* ICC information that is not exposed to Gaia.
|
||||
*/
|
||||
this.iccInfoPrivate = {};
|
||||
|
||||
/**
|
||||
* ICC information, such as MSISDN, IMSI, ...etc.
|
||||
*/
|
||||
|
@ -1171,7 +1176,6 @@ let RIL = {
|
|||
this.getIMSI();
|
||||
this.getMSISDN();
|
||||
this.getAD();
|
||||
this.getSPN();
|
||||
this.getSST();
|
||||
this.getMBDN();
|
||||
},
|
||||
|
@ -1184,6 +1188,86 @@ let RIL = {
|
|||
this.sendDOMMessage(this.iccInfo);
|
||||
},
|
||||
|
||||
/**
|
||||
* This will compute the spnDisplay field of the network.
|
||||
* See TS 22.101 Annex A and TS 51.011 10.3.11 for details.
|
||||
*
|
||||
* @return True if some of iccInfo is changed in by this function.
|
||||
*/
|
||||
updateDisplayCondition: function updateDisplayCondition() {
|
||||
// If EFspn isn't existed in SIM or it haven't been read yet, we should
|
||||
// just set isDisplayNetworkNameRequired = true and
|
||||
// isDisplaySpnRequired = false
|
||||
let iccInfo = this.iccInfo;
|
||||
let iccInfoPriv = this.iccInfoPrivate;
|
||||
let iccSpn = iccInfoPriv.SPN;
|
||||
let origIsDisplayNetworkNameRequired = iccInfo.isDisplayNetworkNameRequired;
|
||||
let origIsDisplaySPNRequired = iccInfo.isDisplaySpnRequired;
|
||||
|
||||
if (!iccSpn) {
|
||||
iccInfo.isDisplayNetworkNameRequired = true;
|
||||
iccInfo.isDisplaySpnRequired = false;
|
||||
} else {
|
||||
let operatorMnc = this.operator.mnc;
|
||||
let operatorMcc = this.operator.mcc;
|
||||
|
||||
// First detect if we are on HPLMN or one of the PLMN
|
||||
// specified by the SIM card.
|
||||
let isOnMatchingPlmn = false;
|
||||
|
||||
// If the current network is the one defined as mcc/mnc
|
||||
// in SIM card, it's okay.
|
||||
if (iccInfo.mcc == operatorMcc && iccInfo.mnc == operatorMnc) {
|
||||
isOnMatchingPlmn = true;
|
||||
}
|
||||
|
||||
// Test to see if operator's mcc/mnc match mcc/mnc of PLMN.
|
||||
if (!isOnMatchingPlmn && iccInfoPriv.PLMN) {
|
||||
let iccPlmn = iccInfoPriv.PLMN; // PLMN list
|
||||
for (let plmn in iccPlmn) {
|
||||
let plmnMcc = iccPlmn[plmn].mcc;
|
||||
let plmnMnc = iccPlmn[plmn].mnc;
|
||||
isOnMatchingPlmn = (plmnMcc == operatorMcc) && (plmnMnc == operatorMnc);
|
||||
if (isOnMatchingPlmn) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnMatchingPlmn) {
|
||||
// The first bit of display condition tells us if we should display
|
||||
// registered PLMN.
|
||||
if (DEBUG) debug("updateDisplayCondition: PLMN is HPLMN or PLMN is in PLMN list");
|
||||
if (iccSpn.spnDisplayCondition & 0x01) {
|
||||
iccInfo.isDisplayNetworkNameRequired = true;
|
||||
iccInfo.isDisplaySpnRequired = false;
|
||||
} else {
|
||||
iccInfo.isDisplayNetworkNameRequired = false;
|
||||
iccInfo.isDisplaySpnRequired = false;
|
||||
}
|
||||
} else {
|
||||
// The second bit of display condition tells us if we should display
|
||||
// registered PLMN.
|
||||
if (DEBUG) debug("updateICCDisplayName: PLMN isn't HPLMN and PLMN isn't in PLMN list");
|
||||
if (iccSpn.spnDisplayCondition & 0x02) {
|
||||
iccInfo.isDisplayNetworkNameRequired = false;
|
||||
iccInfo.isDisplaySpnRequired = false;
|
||||
} else {
|
||||
iccInfo.isDisplayNetworkNameRequired = false;
|
||||
iccInfo.isDisplaySpnRequired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
debug("updateDisplayCondition: isDisplayNetworkNameRequired = " + iccInfo.isDisplayNetworkNameRequired);
|
||||
debug("updateDisplayCondition: isDisplaySpnRequired = " + iccInfo.isDisplaySpnRequired);
|
||||
}
|
||||
|
||||
return ((origIsDisplayNetworkNameRequired !== iccInfo.isDisplayNetworkNameRequired) ||
|
||||
(origIsDisplaySPNRequired !== iccInfo.isDisplaySpnRequired));
|
||||
},
|
||||
|
||||
/**
|
||||
* Get EF_phase.
|
||||
* This EF is only available in SIM.
|
||||
|
@ -1345,12 +1429,20 @@ let RIL = {
|
|||
// Minus 1 because first is used to store display condition
|
||||
let len = (length / 2) - 1;
|
||||
let spnDisplayCondition = GsmPDUHelper.readHexOctet();
|
||||
this.iccInfo.spn = GsmPDUHelper.readAlphaIdentifier(len);
|
||||
let spn = GsmPDUHelper.readAlphaIdentifier(len);
|
||||
Buf.readStringDelimiter(length);
|
||||
|
||||
if (DEBUG) {
|
||||
debug("SPN: spn=" + this.iccInfo.spn + ", spnDisplayCondition=" + spnDisplayCondition);
|
||||
debug("SPN: spn = " + spn +
|
||||
", spnDisplayCondition = " + spnDisplayCondition);
|
||||
}
|
||||
|
||||
this.iccInfoPrivate.SPN = {
|
||||
spn : spn,
|
||||
spnDisplayCondition : spnDisplayCondition,
|
||||
};
|
||||
this.iccInfo.spn = spn;
|
||||
this.updateDisplayCondition();
|
||||
this._handleICCInfoChange();
|
||||
}
|
||||
|
||||
|
@ -1368,6 +1460,104 @@ let RIL = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Read the PLMNsel (Public Land Mobile Network) from the ICC.
|
||||
*
|
||||
* See ETSI TS 100.977 section 10.3.4 EF_PLMNsel
|
||||
*/
|
||||
getPLMNSelector: function getPLMNSelector() {
|
||||
function callback() {
|
||||
if (DEBUG) debug("PLMN: [PLMN Selector] Process PLMN Selector");
|
||||
|
||||
let length = Buf.readUint32();
|
||||
this.iccInfoPrivate.PLMN = this.readPLMNEntries(length/6);
|
||||
Buf.readStringDelimiter(length);
|
||||
|
||||
if (DEBUG) debug("PLMN: [PLMN Selector] " + JSON.stringify(this.iccInfoPrivate.PLMN));
|
||||
|
||||
if (this.updateDisplayCondition()) {
|
||||
this._handleICCInfoChange();
|
||||
}
|
||||
}
|
||||
|
||||
// PLMN List is Service 7 in SIM, EF_PLMNsel
|
||||
this.iccIO({
|
||||
command: ICC_COMMAND_GET_RESPONSE,
|
||||
fileId: ICC_EF_PLMNsel,
|
||||
pathId: this._getPathIdForICCRecord(ICC_EF_PLMNsel),
|
||||
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_TRANSPARENT,
|
||||
callback: callback,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Read the SPDI (Service Provider Display Information) from the ICC.
|
||||
*
|
||||
* See TS 131.102 section 4.2.66
|
||||
*/
|
||||
getSPDI: function getSPDI() {
|
||||
function callback() {
|
||||
if (DEBUG) debug("PLMN: [SPDI] Process SPDI callback");
|
||||
let length = Buf.readUint32();
|
||||
let tlvTag;
|
||||
let tlvLen;
|
||||
let readLen = 0;
|
||||
let endLoop = false;
|
||||
this.iccInfoPrivate.PLMN = null;
|
||||
while ((readLen < length) && !endLoop) {
|
||||
tlvTag = GsmPDUHelper.readHexOctet();
|
||||
tlvLen = GsmPDUHelper.readHexOctet();
|
||||
readLen += 2; // For tag and length.
|
||||
switch (tlvTag) {
|
||||
case SPDI_TAG_SPDI:
|
||||
// The value part itself is a TLV.
|
||||
continue;
|
||||
case SPDI_TAG_PLMN_LIST:
|
||||
// This PLMN list is what we want.
|
||||
this.iccInfoPrivate.PLMN = readPLMNEntries(tlvLen/6);
|
||||
readLen += tlvLen;
|
||||
endLoop = true;
|
||||
break;
|
||||
default:
|
||||
// We don't care about its content if its tag is not SPDI nor
|
||||
// PLMN_LIST.
|
||||
GsmPDUHelper.readHexOctetArray(tlvLen);
|
||||
readLen += tlvLen;
|
||||
}
|
||||
}
|
||||
|
||||
// Consume unread octets.
|
||||
if (length - readLen > 0) {
|
||||
GsmPDUHelper.readHexOctetArray(length - readLen);
|
||||
}
|
||||
Buf.readStringDelimiter(length);
|
||||
|
||||
if (DEBUG) debug("PLMN: [SPDI] " + JSON.stringify(this.iccInfoPrivate.PLMN));
|
||||
if (this.updateDisplayCondition()) {
|
||||
this._handleICCInfoChange();
|
||||
}
|
||||
}
|
||||
|
||||
// PLMN List is Servive 51 in USIM, EF_SPDI
|
||||
this.iccIO({
|
||||
command: ICC_COMMAND_GET_RESPONSE,
|
||||
fileId: ICC_EF_SPDI,
|
||||
pathId: this._getPathIdForICCRecord(ICC_EF_SPDI),
|
||||
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_TRANSPARENT,
|
||||
callback: callback,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get whether specificed (U)SIM service is available.
|
||||
*
|
||||
|
@ -1448,6 +1638,24 @@ let RIL = {
|
|||
}
|
||||
debug("SST: " + str);
|
||||
}
|
||||
|
||||
// Fetch SPN and PLMN list, if some of them are available.
|
||||
if (this.isICCServiceAvailable("SPN")) {
|
||||
if (DEBUG) debug("SPN: SPN is available");
|
||||
this.getSPN();
|
||||
} else {
|
||||
if (DEBUG) debug("SPN: SPN service is not available");
|
||||
}
|
||||
|
||||
if (this.isICCServiceAvailable("PLMNSEL")) {
|
||||
if (DEBUG) debug("PLMN: PLMNSEL available.");
|
||||
this.getPLMNSelector();
|
||||
} else if (this.isICCServiceAvailable("SPDI")) {
|
||||
if (DEBUG) debug("PLMN: SPDI available.");
|
||||
this.getSPDI();
|
||||
} else {
|
||||
if (DEBUG) debug("PLMN: Both PLMNSEL/SPDI not available");
|
||||
}
|
||||
}
|
||||
|
||||
// ICC_EF_UST has the same value with ICC_EF_SST.
|
||||
|
@ -1685,6 +1893,73 @@ let RIL = {
|
|||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read the list of PLMN (Public Land Mobile Network) entries
|
||||
* We cannot directly rely on readSwappedNibbleBcdToString(),
|
||||
* since it will no correctly handle some corner-cases that are
|
||||
* not a problem in our case (0xFF 0xFF 0xFF).
|
||||
*
|
||||
* @param length The number of PLMN records.
|
||||
* @return An array of string corresponding to the PLMNs.
|
||||
*/
|
||||
readPLMNEntries: function readPLMNEntries(length) {
|
||||
let plmnList = [];
|
||||
// each PLMN entry has 3 byte
|
||||
debug("readPLMNEntries: PLMN entries length = " + length);
|
||||
let index = 0;
|
||||
while (index < length) {
|
||||
// Unused entries will be 0xFFFFFF, according to EF_SPDI
|
||||
// specs (TS 131 102, section 4.2.66)
|
||||
try {
|
||||
let plmn = [GsmPDUHelper.readHexOctet(),
|
||||
GsmPDUHelper.readHexOctet(),
|
||||
GsmPDUHelper.readHexOctet()];
|
||||
if (DEBUG) debug("readPLMNEntries: Reading PLMN entry: [" + index +
|
||||
"]: '" + plmn + "'");
|
||||
if (plmn[0] != 0xFF &&
|
||||
plmn[1] != 0xFF &&
|
||||
plmn[2] != 0xFF) {
|
||||
let semiOctets = [];
|
||||
for (let i = 0; i < plmn.length; i++) {
|
||||
semiOctets.push((plmn[idx] & 0xF0) >> 4);
|
||||
semiOctets.push(plmn[idx] & 0x0F);
|
||||
}
|
||||
|
||||
// According to TS 24.301, 9.9.3.12, the semi octets is arranged
|
||||
// in format:
|
||||
// Byte 1: MCC[2] | MCC[1]
|
||||
// Byte 2: MNC[3] | MCC[3]
|
||||
// Byte 3: MNC[2] | MNC[1]
|
||||
// Therefore, we need to rearrage them.
|
||||
let reformat = [semiOctets[1], semiOctets[0], semiOctets[3],
|
||||
semiOctets[5], semiOctets[4], semiOctets[2]];
|
||||
let buf = "";
|
||||
let plmnEntry = {};
|
||||
for (let i = 0; i < reformat.length; i++) {
|
||||
if (reformat[i] != 0xF) {
|
||||
buf += GsmPDUHelper.semiOctetToBcdChar(reformat[i]);
|
||||
}
|
||||
if (i === 2) {
|
||||
// 0-2: MCC
|
||||
plmnEntry.mcc = parseInt(buf);
|
||||
buf = "";
|
||||
} else if (i === 5) {
|
||||
// 3-5: MNC
|
||||
plmnEntry.mnc = parseInt(buf);
|
||||
}
|
||||
}
|
||||
if (DEBUG) debug("readPLMNEntries: PLMN = " + plmnEntry.mcc + ", " + plmnEntry.mnc);
|
||||
plmnList.push(plmnEntry);
|
||||
}
|
||||
} catch (e) {
|
||||
if (DEBUG) debug("readPLMNEntries: PLMN entry " + index + " is invalid.");
|
||||
break;
|
||||
}
|
||||
index ++;
|
||||
}
|
||||
return plmnList;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get UICC Phonebook.
|
||||
*
|
||||
|
@ -3082,6 +3357,7 @@ let RIL = {
|
|||
|
||||
case ICC_EF_AD:
|
||||
case ICC_EF_MBDN:
|
||||
case ICC_EF_PLMNsel:
|
||||
case ICC_EF_SPN:
|
||||
case ICC_EF_SST:
|
||||
return EF_PATH_MF_SIM + EF_PATH_DF_GSM;
|
||||
|
@ -3094,6 +3370,7 @@ let RIL = {
|
|||
case ICC_EF_UST:
|
||||
case ICC_EF_MSISDN:
|
||||
case ICC_EF_SPN:
|
||||
case ICC_EF_SPDI:
|
||||
return EF_PATH_MF_SIM + EF_PATH_ADF_USIM;
|
||||
|
||||
default:
|
||||
|
@ -3438,7 +3715,9 @@ let RIL = {
|
|||
debug("Error processing operator tuple: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.updateDisplayCondition()) {
|
||||
this._handleICCInfoChange();
|
||||
}
|
||||
this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator);
|
||||
}
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче