1. BSSAP复杂信元分析 cell identifier (0x5)
此信元是变长的,此信元的作用是标记小区。标记小区的识别码很多如下定义: 其中最常用的是CGI和LAC_CI组合的方式。 其中CGI的格式为:MCC-MNC-LAC-CI。 MCC(Mobile Country Code):三个十进制数组成,取值范围为十进制的000 ~ 999。 MNC(Mobile Network Code):二个十进制数,取值范围为十进制的00~99。 LAC(Location Area Code):范围为1~65535。 CI(Cell Identity):范围为0~65535。
imsi (0x8)
imsi使用BCD编码的方式,解析imsi的时候需要注意。BCD的编码方式可以压缩一半的字节数。
2. BSSMAP消息格式
BSSMAP消息的格式有三种TLV、TV、 T,比较复杂,尤其是有些可选的IE其格式要预先设定好,在解析到相应的IE的时候预先读取其格式,再做解析。 此次代码编写只实现了部分信令流程的解析,所以需要关注的IE不多,在实际编码过程中遇到的IE都要能够识别。如下是定义的部分:
/* 这个数组用来标记信元是什么格式的, 如果是tv和t格式则第二参数需要注明长度 */ /* 当格式是tlv的时候,长度可以设置为0,报文里面会自带长度 */ static uint8_t bssmap_ie_formart[255][2] = {
/* formart, data's len */ [element_id_cic] = {bssap_ie_format_tv, 2}, [element_id_cellIdentifier] = {bssap_ie_format_tlv, 0}, [element_id_priority] = {bssap_ie_format_tlv, 0},
[element_id_layer3HeadInformation] = {bssap_ie_format_tlv, 0}, [element_id_imsi] = {bssap_ie_format_tlv, 0}, [element_id_tmsi] = {bssap_ie_format_tlv, 0}, [element_id_channelType] = {bssap_ie_format_tlv, 0},
[element_id_classmarkInformation2] = {bssap_ie_format_tlv, 0}, [element_id_interferenceBandToBeUsed] = {bssap_ie_format_tv, 1}, [element_id_layer3Info] = {bssap_ie_format_tlv, 0}, [element_id_downlinkDtxFlag] = {bssap_ie_format_tv, 1}, [element_id_cellIdentifierList] = {bssap_ie_format_tlv, 0}, [element_id_chosenChannel] = {bssap_ie_format_tv, 1},
[element_id_channelNeeded] = {bssap_ie_format_tv, 1}, [element_id_subscriptionInformation] = {bssap_ie_format_tv, 1}, [element_id_talkerFlag] = {bssap_ie_format_t, 0},
[element_id_groupCallReference] = {bssap_ie_format_tlv, 0}, };
3. DTAP的消息格式
DTAP消息的格式也有TLV、TV、T这三种。绝大部分都是TLV的,预计工作量比BSSMAP小,需要注意的是DTAP的信元element id和BSSMAP中的element id是两套编码,需要分别定义两组枚举常量。DTAP部分格式定义如下:
/* 所关注的dtap信元的格式,大部分是tlv的,有少数是TV和T的格式。 */ static uint8_t dtap_ie_formate[255][2] = {
/* {formate, len} formate为tlv格式的时候,len填0,其他情况按照实际情况填 */ [dtap_e_id_bearerCapability] = {bssap_ie_format_tlv, 0}, [dtap_e_id_alert] = {bssap_ie_format_tlv, 0},
[dtap_e_id_facility_recall_alignment] = {bssap_ie_format_tlv, 0}, [dtap_e_id_facility] = {bssap_ie_format_tlv, 0}, [dtap_e_id_ccbs] = {bssap_ie_format_tlv, 0},
[dtap_e_id_progressIndicator] = {bssap_ie_format_tlv, 0}, [dtap_e_id_signal] = {bssap_ie_format_tv, 1},
[dtap_e_id_callingPartBCDNumber] = {bssap_ie_format_tlv, 0}, [dtap_e_id_callingPartSubaddress] = {bssap_ie_format_tlv, 0}, [dtap_e_id_calledPartBCDNumber] = {bssap_ie_format_tlv, 0}, [dtap_e_id_calledPartSubaddress] = {bssap_ie_format_tlv, 0}, [dtap_e_id_lowLayerCompatibility] = {bssap_ie_format_tlv, 0}, [dtap_e_id_highLayerCompatibility] = {bssap_ie_format_tlv, 0}, [dtap_e_id_user_user] = {bssap_ie_format_tlv, 0}, [dtap_e_id_ss_version] = {bssap_ie_format_tlv, 0}, [dtap_e_id_clir_suppression] = {bssap_ie_format_tlv, 0}, [dtap_e_id_clir_invocation] = {bssap_ie_format_tlv, 0}, [dtap_e_id_callControlCapabilities] = {bssap_ie_format_tlv, 0}, };
4. 主要接口设计 semp_dtap_parse
函数原型为:
mp_error_t semp_dtap_parse(uint8_t *data, uint16_t data_length, parse_A_t *a_info);
/**************************************************************************** 函数名名称 : semp_dtap_parse
函数功能 : 将接收到的dtap数据流解析到结构体a_info中 输入参数 : 原始dtap字节流指针data, dtap的长度 输出参数 : 保存解析出来的数据的指针的a_info 返回值 : 失败或者成功 备注 : 单元测试记录:
****************************************************************************/
semp_dtap_element_parse
函数原型为:
mp_error_t semp_dtap_parse(uint8_t *data, uint16_t data_length, parse_A_t *a_info);
/**************************************************************************** 函数名名称 : semp_dtap_parse
函数功能 : 将接收到的dtap数据流解析到结构体a_info中 输入参数 : 原始dtap字节流指针data, dtap的长度 输出参数 : 保存解析出来的数据的指针的a_info 返回值 : 失败或者成功 备注 : 单元测试记录:
****************************************************************************/
semp_bssmap_parse
函数原型:
mp_error_t semp_bssmap_parse(uint8_t *data, uint16_t data_length, parse_A_t *a_info); /**************************************************************************** 函数名名称 : semp_bssmap_parse
函数功能 : 解析bssmap中关键的信令过程 输入参数 : bssmap原始字节流,数据流的长度 输出参数 : A接口的信元信息 返回值 : 失败或者成功 备注 : 单元测试记录:
****************************************************************************/
semp_bssap_element_parse
函数原型:
mp_error_t semp_bssap_element_parse( uint8_t *data,
uint16_t data_length,
bssap_element_t *element, uint8_t *element_nbr );
/**************************************************************************** 函数名名称 : semp_bssap_element_parse
函数功能 : 解析bssap消息中固定格式的信元
输入参数 : bssmap原始消息流data,消息的长度data_length
输出参数 : bssmap各个信元<指针形式返回>,bssmap原始消息中信元的个数 返回值 : 失败或成功 备注 : 单元测试记录:
****************************************************************************/
forlist_to_fetch_element
函数原型:
mp_error_t forlist_to_fetch_element( const bssap_element_t *pelement, uint8_t element_nbr, uint8_t which,
bssap_element_t *out);
/**************************************************************************** 函数名名称 : forlist_to_fetch_element
函数功能 : 遍历bssap信元指针所指向的内存,提取出我们关心的。 输入参数 : bssap信元的指针,信元总数,提取哪个信元 输出参数 : 保存所提取信元的指针 返回值 : 失败或者成功 备注 : 单元测试记录:
****************************************************************************/
5. 主要数据结构 parse_A_t
/****************************************************************************** * 用于存放A接口报文解析结果
******************************************************************************/ typedef struct {
uint8_t direction;
ip_comm_t an_ip; //接入网IP
ip_comm_t cn_ip; //核心网IP, MSC的IP parse_sccp_t sccp_info; parse_bssap_t bssap_info; }parse_A_t;
parse_dtap_t
/****************************************************************************** * 用于存放dtap解析出来的数据
******************************************************************************/ typedef struct {
uint8_t message_type; uint16_t valid_ie_mask; uint8_t identity_type; p_tmsi_t p_tmsi; imsi_t imsi; imei_t imei; }parse_dtap_t;
parse_bssmap_t
/****************************************************************************** * 用于存放bssmap解析出来的数据
******************************************************************************/ typedef struct {
uint8_t message_type; /*指示是什么消息类型*/
uint16_t valid_ie_mask; /*指示bssmap消息里面的哪些IE是有效的*/
uint8_t identity_type; /*指示该消息中的有效身份标识(IMSI、TMSI、IMEI)*/ p_tmsi_t p_tmsi; imsi_t imsi;
rai_t rai; /*位置*/ imei_t imei; }parse_bssmap_t;
parse_bssap_t
/****************************************************************************** * 用于存放bssap报文解析出来的数据
******************************************************************************/
typedef struct {
uint16_t type;/*指示是bssmap还是dtap*/
uint16_t isPacketValid; /*对关联模块是否是有效的, YES有效 NO无效*/ union{ parse_bssmap_t bssmap; /*存放bssmap解析结果*/ parse_dtap_t dtap; /*存放dtap解析结果*/ }un;
}parse_bssap_t;
6. 模拟数据测试
从北京发过来的数据包中提取了一些典型的数据流(代码见decode_bssap_c/src/),如下: /* 以下数据都是从北京发回来的报文中抓取的片段,sccp层的数据不包括 */ // assignment request数据
uint8_t bssap_assignment_request[] = {
0x1,0xb, 0x7, 0x1, 0xa, 0xa1, 0x91, 0x81, 0xa5, 0x05, 0x07, 0x02, 0x06, 0x00, 0x06, 0x01, 0x32, 0x01, 0x02, 0x14, 0x19, 0x01 };
// cm service request数据
uint8_t bssap_coml3info_cmservicerequest[] = {
0x57, 0x5, 0x8, 0x0, 0x64, 0xf0, 0x0, 0x59, 0x81, 0xd6, 0x93, 0x17, 0x0d, 0x5, 0x24, 0x31, 0x3, 0x33, 0x59 ,0x92 ,0x5 ,0xf4 ,0x39 ,0x20, 0xaf, 0x22 };
// paging数据
uint8_t bssap_paging[] = {
0x52 ,0x8 ,0x8 ,0x49 ,0x6 ,0 ,0x89 ,0x7 ,0x75 ,0x76 ,7 ,9, 4, 0x22, 0x80, 0xa7, 0x8d ,0x1a ,0x6, 4, 0x64, 0xf0, 0, 0x59, 0x81 };
// paging response数据
uint8_t bssap_coml3info_paging_response[] = {
0x57, 5, 5, 1, 0x59, 0x8b, 0x84, 0xb5, 0x17, 0xd, 0x6, 0x27, 2, 3, 0x53, 0x59, 0x80, 5, 0xf4, 0x29, 0xf0, 0x3e, 0x5c };
// called setup数据
uint8_t bssap_called_setup[] = {
3, 5, 4, 1, 0xa0, 0x5c, 8, 0x21, 0x83, 0x50, 0x59, 0x88, 0x88, 0x95, 0x30 };
// moc setup数据
uint8_t bssap_moc_setup[] = {
3, 5, 4, 4, 0x60, 2, 0, 0x81, 0x5e, 7, 0x81, 0x51, 0x59, 0x94, 0x43, 0x56, 0xf8, 0x15, 1, 1 };
在ubuntu环境下编译:gcc *.c -Wall 运行:./a.out,结果如下:
[M_PARSE, LV_DBG]bssmap.c:72 id = 0x8, formate = 1 [M_PARSE, LV_DBG]bssmap.c:72 id = 0x9, formate = 1 [M_PARSE, LV_DBG]bssmap.c:72 id = 0x1a, formate = 1
[M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x8, which = 0x8 [M_PARSE, LV_DBG]bssmap.c:248 imsi len = 8
[M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x8, which = 0x9 [M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x9, which = 0x9 [M_PARSE, LV_DBG]bssmap.c:256 tmsi = 22 80 a7 8d
[M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x8, which = 0x1a [M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x9, which = 0x1a [M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x1a, which = 0x1a [M_PARSE, LV_DBG]bssmap.c:261 cilist len = 6 -----------------------------------
[M_PARSE, LV_DBG]bssmap.c:72 id = 0x5, formate = 1 [M_PARSE, LV_DBG]bssmap.c:72 id = 0x17, formate = 1
[M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x5, which = 0x5 [M_PARSE, LV_DBG]bssmap.c:227 lac = 0xb517, ci = 0xd06 [M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x5, which = 0x17 [M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x17, which = 0x17 [M_PARSE, LV_DBG]bssmap.c:231 get layinfo len = 0xd We get midtype = 4
[M_PARSE, LV_DBG]dtap.c:140 tmsi = 29 f0 3e 5c -----------------------------------
[M_PARSE, LV_DBG]dtap.c:183 id = 0x4, formate = 1 [M_PARSE, LV_DBG]dtap.c:183 id = 0x5c, formate = 1
[M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x4, which = 0x5c [M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x5c, which = 0x5c calling number = 0x50 0x59 0x88 0x88 0x95 0x30 -----------------------------------
[M_PARSE, LV_DBG]dtap.c:183 id = 0x4, formate = 1 [M_PARSE, LV_DBG]dtap.c:183 id = 0x5e, formate = 1 [M_PARSE, LV_DBG]dtap.c:183 id = 0x15, formate = 1
[M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x4, which = 0x5e [M_PARSE, LV_DBG]bssmap.c:131 element_id = 0x5e, which = 0x5e called number = 0x51 0x59 0x94 0x43 0x56 0xf8
-----------------------------------
~~~ TEST OK ~~~!
wangkai@semp130:~/MyPro/decode_bssap/src$ ^
因篇幅问题不能全部显示,请点此查看更多更全内容