问题的提出
有前同事咨询我一个问题:
自己写到卡里的IMSI,读出来的PLMN都是6位的;而从正常的联通卡等都出来的PLMN是5位的;
PLMN = MCC + MNC;
MCC是固定3位的;
MNC有2位的,也有3位的;
MNC是几位的如何确定呢?
这个问题困扰了我这位前同事几年了,我也没遇到过,研究下。
基本概念
IMSI:International Mobile Subscriber Identity,国际移动用户识别码。
IMSI由一串十进制数字组成,最大长度为15位。实际使用的IMSI的长度绝大部分都是15位,短于15位的例子少见,例如,南非MTN有一些仍在网络中使用的较旧的IMSI为14位数字。IMSI由移动国家代码(MCC,Mobile Country Code)、移动网络代码(MNC,Mobile Network Code)和移动订户识别代码(MSIN,Mobile subscription identification number)依次连接而成。MCC长度为3位,MNC长度由MCC的值决定,可以是2位(欧洲标准)或3位数字(北美标准),MSIN的值由运营商自行分配。
IMSI的格式由国际电信联盟(ITU)的E.212标准定义。
以上定义摘自百度百科。
IMSI在SIM卡中的存储格式见3GPP 31.102
4.2.2 EFIMSI (IMSI)
If service n°130 is "available", this file shall not be available.
This EF contains the International Mobile Subscriber Identity (IMSI).
Identifier: '6F07' | Structure: transparent | Optional | ||||
SFI: '07' | ||||||
File size: 9 bytes | Update activity: low | |||||
Access Conditions: READ PIN UPDATE ADM DEACTIVATE ADM ACTIVATE ADM | ||||||
Bytes | Description | M/O | Length | |||
1 | Length of IMSI | M | 1 byte | |||
2 to 9 | IMSI | M | 8 bytes |
相关代码
查看代码,相关的函数有:
mmcp\mmode\cm\src\sys.c
/* ==========================================================================
FUNCTION: SYS_GET_NUM_OF_MNC_DIGITS
DESCRIPTION:
This function returns length of MNC in the IMSI which is store in 4th
byte of EF-AD.
DEPENDENCIES:
None
LIMITATIONS:
None
RETURN VALUE:
TRUE: Successful retrieval of number of mnc digits
FALSE: Null input pointer
SIDE EFFECTS:
None
==========================================================================*/
boolean sys_get_num_of_mnc_digits(
mmgsdi_data_type *imsi_ptr,
mmgsdi_data_type *ad_ptr,
uint8 *num_mnc_digits_ptr
)
{
size_t i = 0;
size_t mcc_value = 0;
uint16 mcc_pcs1900_na_list[] = {302, 310, 311, 312, 313,
314, 315, 316, 334, 348
};
if(imsi_ptr == NULL || imsi_ptr->data_ptr == NULL || num_mnc_digits_ptr == NULL)
{
CM_ERR_2("imsi_ptr 0x%x, imsi_ptr->data_ptr or num_mnc_digits_ptr 0x%x is NULL",
imsi_ptr,
num_mnc_digits_ptr);
return FALSE;
}
/* Old SIM cards had only 2 digits MNC and EF-AD with 3 bytes only.
Default to 2 digits to keep backward compatibility */
*num_mnc_digits_ptr = SYS_MNC_2_DIGITS;
if(ad_ptr == NULL)
{
CM_MSG_HIGH_0("EF-AD ptr is NULL, use default 2 digit MNC");
return TRUE;
}
/* 3GPP 23.122 Annex 'A'
For PCS1900 for North America, regulations mandate that a 3-digit MNC
shall be used; however during a transition period, a 2 digit MNC may
be broadcast by the Network and, in this case, the 3rd digit of the
SIM is stored as 0 (this is the 0 suffix rule).
For these specific country codes, MNC length shall default to 3. */
mcc_value = (size_t)((imsi_ptr->data_ptr[SYS_IMSI_DIGIT_1_OFFSET] >> 4) &
SYS_IMSI_LOW_DIGIT_MASK) * 100;
mcc_value += (size_t)((imsi_ptr->data_ptr[SYS_IMSI_DIGIT_2_OFFSET]) &
SYS_IMSI_LOW_DIGIT_MASK) * 10;
mcc_value += (size_t)((imsi_ptr->data_ptr[SYS_IMSI_DIGIT_2_OFFSET] >> 4) &
SYS_IMSI_LOW_DIGIT_MASK);
for (i = 0; i < sizeof(mcc_pcs1900_na_list) / sizeof(uint16); i++)
{
if (mcc_value == (size_t)mcc_pcs1900_na_list[i])
{
*num_mnc_digits_ptr = SYS_MNC_3_DIGITS;
break;
}
}
if (ad_ptr->data_len > SYS_MNC_LEN_BYTE && ad_ptr->data_ptr != NULL)
{
if ( ((ad_ptr->data_ptr[SYS_MNC_LEN_BYTE] & 0x0F) == SYS_MNC_2_DIGITS ) ||
((ad_ptr->data_ptr[SYS_MNC_LEN_BYTE] & 0x0F) == SYS_MNC_3_DIGITS ) )
{
*num_mnc_digits_ptr = ad_ptr->data_ptr[SYS_MNC_LEN_BYTE] & 0x0F;
}
else
{
CM_ERR_1("EF-AD has invalid MNC length: 0x%x", ad_ptr->data_ptr[SYS_MNC_LEN_BYTE]);
}
}
//CM_MSG_HIGH_1("Number of MNC digits: 0x%x", *num_mnc_digits_ptr );
return TRUE;
}/* sys_get_num_of_mnc_digits */
\mmcp\mmode\cm\src\cmph.c
/*==========================================================================
FUNCTION cmph_read_imsi_hplmn
DESCRIPTION
Function that reads EF-IMSI and return HPLMN(MCC-MNC)
RETURN VALUE
boolean Flag indicating whether EF-IMSI read
from the SIM successfully (TRUE) or unsuccessfully(FALSE).
DEPENDENCIES
None
===========================================================================*/
static boolean cmph_read_imsi_hplmn
(
sys_plmn_id_s_type *imsi_ptr,
mmgsdi_session_type_enum_type session_type
)
{
boolean status = FALSE;
mmgsdi_app_enum_type app_type;
byte imsi[MMGSDI_IMSI_LEN] = {0};
byte admin_data[CMMMGSDI_RPM_AD_SIZE] = {0};
boolean plmn_is_undefined_ptr;
boolean mnc_includes_pcs_digit_ptr;
sys_mcc_type mcc=SYS_WILDCARD_MCC;
sys_mnc_type mnc=SYS_WILDCARD_MNC;
sys_modem_as_id_e_type asubs_id= SYS_MODEM_AS_ID_1;
app_type = cm_mmgsdi_ssn_tbl_get_app_type_for_type(
session_type);
/* Read EF-IMSI */
status = cmmmgsdi_read(session_type,
(app_type == MMGSDI_APP_SIM ? MMGSDI_GSM_IMSI : MMGSDI_USIM_IMSI),
0,
MMGSDI_IMSI_LEN,
(uint8 *)imsi,
sizeof(imsi),
transparent);
/* Read EF-AD to get MNC length */
if(status)
{
status = cmmmgsdi_read(session_type,
(app_type == MMGSDI_APP_SIM ? MMGSDI_GSM_AD : MMGSDI_USIM_AD),
0,
CMMMGSDI_RPM_AD_SIZE,
(uint8 *)admin_data,
sizeof(admin_data),
transparent);
}
/* Extract MCC and MNC */
if(status)
{
/*
** Fill MCC Digit 1 and MCC Digit 2
*/
imsi_ptr->identity[0] = (byte)(( ( imsi[1] & 0xF0 ) / 0x10 ) +
( ( imsi[2] & 0x0F ) * 0x10 ));
/*
** Fill MCC Digit 3 and MNC Digit 3
*/
imsi_ptr->identity[1] = (byte)(( ( imsi[2] & 0xF0 ) / 0x10 ) +
( ( imsi[4] & 0x0F ) * 0x10 ));
/*
** If 2 digits MNC is indicated in EF-AD then set MNC digit 3 to 'F'.
*/
if ((admin_data[3] & 0x0F) == 0x02)
{
CM_MSG_MED_0("2 digit MNC");
imsi_ptr->identity[1] |= 0xF0;
}
/*
** Fill MNC Digit 1 and MNC Digit 2
*/
imsi_ptr->identity[2] = imsi[3];
CM_MSG_HIGH_3_EXT("Read IMSI - HPLMN : 0x%02x, 0x%02x, 0x%02x",
imsi_ptr->identity[0],imsi_ptr->identity[1],imsi_ptr->identity[2],
SESSION_TO_AS_ID(session_type));
/*Store MCC/MNC Values*/
sys_plmn_get_mcc_mnc2(*imsi_ptr,&plmn_is_undefined_ptr,&mnc_includes_pcs_digit_ptr,
&mcc,&mnc);
if(session_type == MMGSDI_GW_PROV_PRI_SESSION)
{
asubs_id = SYS_MODEM_AS_ID_1;
}
else if(session_type == MMGSDI_GW_PROV_SEC_SESSION)
{
asubs_id = SYS_MODEM_AS_ID_2;
}
else if(session_type == MMGSDI_GW_PROV_TER_SESSION)
{
asubs_id = SYS_MODEM_AS_ID_3;
}
if(asubs_id < MAX_SIMS && cmph_ptr()->sub_info[asubs_id] != NULL)
{
cmph_ptr()->sub_info[asubs_id]->gwl_mcc=mcc;
cmph_ptr()->sub_info[asubs_id]->gwl_mnc=mnc;
sd_misc_update_3gpp_imsi(asubs_id,mcc,mnc);
}
}
return status;
} /* cmph_read_imsi_hplmn() */
确定MNC有几位的参数
通过代码可以看出,确定IMSI中MNC有几位的参数存在SIM卡的EFAD中,具体见:
3GPP 31.102
4.2.18 EFAD (Administrative Data)
This EF contains information concerning the mode of operation according to the type of USIM, such as normal (to be used by PLMN subscribers for 3G operations), type approval (to allow specific use of the ME during type approval procedures of e.g. the radio equipment), cell testing (to allow testing of a cell before commercial use of this cell), manufacturer specific (to allow the ME manufacturer to perform specific proprietary autotest in its ME during e.g. maintenance phases).
It also provides an indication about how some ME features shall work during normal operation as well as information about the length of the MNC, which is part of the International Mobile Subscriber Identity (IMSI).
Identifier: '6FAD' | Structure: transparent | Mandatory | ||||
SFI: '03' | ||||||
File size: 4+X bytes | Update activity: low | |||||
Access Conditions: READ ALW UPDATE ADM DEACTIVATE ADM ACTIVATE ADM | ||||||
Bytes | Description | M/O | Length | |||
1 | UE operation mode | M | 1 byte | |||
2 to 3 | Additional information | M | 2 bytes | |||
4 | length of MNC in the IMSI | M | 1 byte | |||
5 to 4+X | RFU | O | X bytes |
问题解决验证
我前同事再写卡IMSI时把卡EFAD的length of MNC in the IMSI参数写正确了,再读IMSI得到的PLMN位数就正确了。