GPRS隧道协议(GTP)是3GPP标准定义的隧道协议,用于在3G /4G/5G网络中承载通用分组无线服务(GPRS)。
GTP用于在服务网关(S-GW)和分组数据网络网关(P-GW)以及S-GW和移动性管理实体(MME)之间为用户设备建立GTP隧道。如图-EPC架构:
GTP包含哪些单独的协议?
GTP包括在UDP / IP上传输的控制平面(GTP-C),用户平面(GTP-U)和计费(从GTP-C派生的GTP)流量。
GTP-C-在核心GPRS网络中的S-GW和P-GW之间执行信令,以激活和停用用户会话,调整服务质量参数或更新从另一个S-GW到达的漫游用户的会话。GTP-C支持以IPv4格式传输控制数据包。它用于各种EPC(演进的分组核心)信令接口,例如S5,S8和S11。还承载各种类型的控制平面信令消息。GTP-C端口号是2123。
GTP-U-在核心GPRS网络内以及在无线访问网络(RAN)和核心网络之间传输用户数据。GTP-U支持IPv4和IPv6用户数据,但传输是IPv4。它跨多个信令接口(例如S1,S5和S8)封装和路由用户平面流量。GTP-U消息是用户平面消息或信令消息。GTP-U端口号是2152。
什么是MME
MME是移动管理实体,是一个用于信令控制的网元,主要做移动的管理,此外还需要做会话相关的控制处理。
MME主要的功能是:
1、NAS信令处理
2、 3GPP内不同节点之间的移动性管理
3、PGW和SGW选择
4、漫游控制
…
什么是PGW
PGW是PDN网关,所谓PDN就是公共数据网,可以理解成核心网后端的网络系统,PDN负责用户数据包与其他网络的处理。
PGW功能描述:
1、基于用户包过滤
2、IP地址分配
3、上下行传输层数据包标记
4、上下行的承载绑定、校验。
…
什么是SGW
SGW是服务网关,它是数据面的网元,所谓数据面可以理解成数据传输的通道,负责本地网络用户数据的处理部分。
SGW功能描述
1、(基站)eNodeB之间的切换的本地
2、数据包路由和转发
3、上下行传输层数据包标记
4、用户和QCI力度的统计,主要用于运营商间计费
5、基于用户、PDN和QCI力度的上下行的计费。
EPC网元之间的接口
上面已经描述了MME、SGW、PGW。接下来介绍EPC协议围绕这三个网元之间的接口讲解。分别是eNodeB和MME之间的(S1-MME),eNodeB和SGW之间的(S1-U),MME和SGW之间的(S11),SGW和PGW之间的协议(S5)
S1-MME接口承载的协议是S1-AP/SCTP/IP,S1-U承载的协议是GTPv1-U,S5接口承载的协议是GTPv2-C。
GTPv2消息格式
各个版本的差异主要是协议功能,即传输的内容的差异,新版本一般来说比旧版本承载更多的信息。
控制平面GTP使用可变长度的标头。 控制平面GTP报头长度应为4个八位位组的倍数。
下面是GTPv2-C标头的格式。
Create Session Request
Create Session Response
对协议分析还原而言,知道如何识别,再知道如何解析协议格式,那么,就可以去实现解析了。
GTP消息类型
作为移动网络的协议,GTP当然是由3GPP组织来定义的,GTP v2参考3GPP TS 29.274,GTP v1参考3GPP TS 29.060。
#define GTPV2_IE_RESERVED 0
#define GTPV2_IE_IMSI 1
#define GTPV2_IE_CAUSE 2
#define GTPV2_REC_REST_CNT 3
/*Start SRVCC Messages*/
#define GTPV2_IE_STN_SR 51
#define GTPV2_IE_SRC_TGT_TRANS_CON 52
#define GTPV2_IE_TGT_SRC_TRANS_CON 53
#define GTPV2_IE_MM_CON_EUTRAN_SRVCC 54
#define GTPV2_IE_MM_CON_UTRAN_SRVCC 55
#define GTPV2_IE_SRVCC_CAUSE 56
#define GTPV2_IE_TGT_RNC_ID 57
#define GTPV2_IE_TGT_GLOGAL_CELL_ID 58
#define GTPV2_IE_TEID_C 59
#define GTPV2_IE_SV_FLAGS 60
#define GTPV2_IE_SAI 61
#define GTPV2_IE_MM_CTX_FOR_CS_TO_PS_SRVCC 62
/* 61 - 70 for future sv interface use*/
/*End SRVCC Messages*/
#define GTPV2_APN 71
#define GTPV2_AMBR 72
#define GTPV2_EBI 73
#define GTPV2_IP_ADDRESS 74
#define GTPV2_MEI 75
#define GTPV2_IE_MSISDN 76
#define GTPV2_INDICATION 77
#define GTPV2_PCO 78
#define GTPV2_PAA 79
#define GTPV2_BEARER_QOS 80
#define GTPV2_IE_FLOW_QOS 81
#define GTPV2_IE_RAT_TYPE 82
#define GTPV2_IE_SERV_NET 83
#define GTPV2_IE_BEARER_TFT 84
#define GTPV2_IE_TAD 85
#define GTPV2_IE_ULI 86
#define GTPV2_IE_F_TEID 87
#define GTPV2_IE_TMSI 88
#define GTPV2_IE_GLOBAL_CNID 89
#define GTPV2_IE_S103PDF 90
#define GTPV2_IE_S1UDF 91
#define GTPV2_IE_DEL_VAL 92
#define GTPV2_IE_BEARER_CTX 93
#define GTPV2_IE_CHAR_ID 94
#define GTPV2_IE_CHAR_CHAR 95
#define GTPV2_IE_TRA_INFO 96
#define GTPV2_BEARER_FLAG 97
/* define GTPV2_IE_PAGING_CAUSE 98 (void) */
#define GTPV2_IE_PDN_TYPE 99
#define GTPV2_IE_PTI 100
#define GTPV2_IE_DRX_PARAM 101
#define GTPV2_IE_UE_NET_CAPABILITY 102
#define GTPV2_IE_MM_CONTEXT_GSM_T 103
#define GTPV2_IE_MM_CONTEXT_UTMS_CQ 104
#define GTPV2_IE_MM_CONTEXT_GSM_CQ 105
#define GTPV2_IE_MM_CONTEXT_UTMS_Q 106
#define GTPV2_IE_MM_CONTEXT_EPS_QQ 107
#define GTPV2_IE_MM_CONTEXT_UTMS_QQ 108
#define GTPV2_IE_PDN_CONNECTION 109
#define GTPV2_IE_PDN_NUMBERS 110
#define GTPV2_IE_P_TMSI 111
#define GTPV2_IE_P_TMSI_SIG 112
#define GTPV2_IE_HOP_COUNTER 113
#define GTPV2_IE_UE_TIME_ZONE 114
#define GTPV2_IE_TRACE_REFERENCE 115
#define GTPV2_IE_COMPLETE_REQUEST_MSG 116
#define GTPV2_IE_GUTI 117
#define GTPV2_IE_F_CONTAINER 118
#define GTPV2_IE_F_CAUSE 119
#define GTPV2_IE_SEL_PLMN_ID 120
#define GTPV2_IE_TARGET_ID 121
/* GTPV2_IE_NSAPI 122 */
#define GTPV2_IE_PKT_FLOW_ID 123
#define GTPV2_IE_RAB_CONTEXT 124
#define GTPV2_IE_S_RNC_PDCP_CTX_INFO 125
#define GTPV2_IE_UDP_S_PORT_NR 126
#define GTPV2_IE_APN_RESTRICTION 127
#define GTPV2_IE_SEL_MODE 128
#define GTPV2_IE_SOURCE_IDENT 129
#define GTPV2_IE_BEARER_CONTROL_MODE 130
#define GTPV2_IE_CNG_REP_ACT 131
#define GTPV2_IE_FQ_CSID 132
#define GTPV2_IE_CHANNEL_NEEDED 133
#define GTPV2_IE_EMLPP_PRI 134
#define GTPV2_IE_NODE_TYPE 135
#define GTPV2_IE_FQDN 136
#define GTPV2_IE_TI 137
#define GTPV2_IE_MBMS_SESSION_DURATION 138
#define GTPV2_IE_MBMS_SERVICE_AREA 139
#define GTPV2_IE_MBMS_SESSION_ID 140
#define GTPV2_IE_MBMS_FLOW_ID 141
#define GTPV2_IE_MBMS_IP_MC_DIST 142
#define GTPV2_IE_MBMS_DIST_ACK 143
#define GTPV2_IE_RFSP_INDEX 144
#define GTPV2_IE_UCI 145
#define GTPV2_IE_CSG_INFO_REP_ACTION 146
#define GTPV2_IE_CSG_ID 147
#define GTPV2_IE_CMI 148
#define GTPV2_IE_SERVICE_INDICATOR 149
#define GTPV2_IE_DETACH_TYPE 150
#define GTPV2_IE_LDN 151
#define GTPV2_IE_NODE_FEATURES 152
#define GTPV2_IE_MBMS_TIME_TO_DATA_XFER 153
#define GTPV2_IE_THROTTLING 154
#define GTPV2_IE_ARP 155
#define GTPV2_IE_EPC_TIMER 156
#define GTPV2_IE_SIG_PRIO_IND 157
#define GTPV2_IE_TMGI 158
#define GTPV2_IE_ADD_MM_CONT_FOR_SRVCC 159
#define GTPV2_IE_ADD_FLAGS_FOR_SRVCC 160
#define GTPV2_IE_MMBR 161
#define GTPV2_IE_MDT_CONFIG 162
#define GTPV2_IE_APCO 163
#define GTPV2_IE_ABS_MBMS_DATA_TF_TIME 164
#define GTPV2_IE_HENB_INFO_REPORT 165
#define GTPV2_IE_IP4CP 166
#define GTPV2_IE_CHANGE_TO_REPORT_FLAGS 167
#define GTPV2_IE_ACTION_INDICATION 168
#define GTPV2_IE_TWAN_IDENTIFIER 169
#define GTPV2_IE_ULI_TIMESTAMP 170
#define GTPV2_IE_MBMS_FLAGS 171
#define GTPV2_IE_RAN_NAS_CAUSE 172
#define GTPV2_IE_CN_OP_SEL_ENT 173
#define GTPV2_IE_TRUST_WLAN_MODE_IND 174
#define GTPV2_IE_NODE_NUMBER 175
#define GTPV2_IE_NODE_IDENTIFIER 176
#define GTPV2_IE_PRES_REP_AREA_ACT 177
#define GTPV2_IE_PRES_REP_AREA_INF 178
#define GTPV2_IE_TWAN_ID_TS 179
#define GTPV2_IE_OVERLOAD_CONTROL_INF 180
#define GTPV2_IE_LOAD_CONTROL_INF 181
#define GTPV2_IE_METRIC 182
#define GTPV2_IE_SEQ_NO 183
#define GTPV2_IE_APN_AND_REL_CAP 184
#define GTPV2_IE_WLAN_OFFLOADABILITY_IND 185
#define GTPV2_IE_PAGING_AND_SERVICE_INF 186
#define GTPV2_IE_INTEGER_NUMBER 187
#define GTPV2_IE_MILLISECOND_TS 188
#define GTPV2_IE_MON_EVENT_INF 189
/*
190 ECGI List
191 Remote UE Context
192 Remote User ID
193 Remote UE IP information
*/
#define GTPV2_IE_CIOT_OPT_SUPPORT_IND 194
#define GTPV2_IE_SCEF_PDN_CONNECTION 195
#define GTPV2_IE_HEADER_COMP_CONF 196
#define GTPV2_IE_EXTENDED_PCO 197
#define GTPV2_IE_SERV_PLMN_RATE_CONTROL 198
#define GTPV2_IE_COUNTER 199
#define GTPV2_IE_MAPPED_UE_USAGE_TYPE 200
#define GTPV2_IE_SECONDARY_RAT_USAGE_DATA_REPORT 201
#define GTPV2_IE_UP_FUNC_SEL_INDI_FLG 202
#define GTPV2_IE_MAX_PKT_LOSS_RTE 203
#define GTPV2_IE_APN_RTE_CNTRL_STATUS 204
#define GTPV2_IE_EXT_TRS_INF 205
#define GTPV2_IE_MON_EVENT_EXT_INF 206
/*
203 to 253 Spare. For future use.
254 Special IE type for IE Type Extension
255 Private Extension
256 to 65535 Spare. For future use.
*/
/* 169 to 254 reserved for future use */
#define GTPV2_IE_PRIVATE_EXT 255
GTP-C协议解析实现
下面主要对GTPv2协议的IMSI、TEID、MSISDN、用户IP进行解析。
struct gtpv2_hdr_t {
u_int8_t flags; /* GTP header flags */
u_int8_t msg_type; /* Message type */
u_int16_t length; /* Length of header */
long teid; /* Tunnel End-point ID */
};
static void dissect_gtpv2_ie_common(u_char *gtpv2_info, int offset,int package_len, u_int8_t message_type)
{
u_int8_t type = 0, instance = 0;
u_int16_t length = 0;
int i = 0, remaining_length = 0, msg_length = 0;
/*
* Octets 8 7 6 5 4 3 2 1
* 1 Type
* 2-3 Length = n
* 4 CR Spare Instance
* 5-(n+4) IE specific data
*/
msg_length = package_len;
while (offset < msg_length)
{
/* Get the type and length */
remaining_length = msg_length - offset;
if (remaining_length < 3) {
printf("Not enough data left for IE and length, %i bytes\n", remaining_length);
return;
}
type = gtpv2_info[offset];
printf("IE Type: %d\n",type);
length = ntohs(*(uint16_t *)(gtpv2_info + offset + 1));
printf("IE Length: %d\n",length);
remaining_length = remaining_length -4;
if (remaining_length < length) {
printf("Less data left than indicated by length %u, remaining length %i \n", length, remaining_length);
/* Octet 1 */
offset += 1;
/*Octet 2 - 3 */
return;
}
/* type */
offset += 1;
/*Length */
offset += 2;
instance = gtpv2_info[offset]&0x0f;
printf("instance: %d\n",instance);
/*instance*/
offset += 1;
/* TODO: call IE dissector here */
if (type == GTPV2_IE_RESERVED) {
/* Treat IE type zero specal as type zero is used to end the loop in the else branch */
}
else
{
/* Loop over the IE dissector list to se if we find an entry;
the last entry will have ie_type=0 breaking the loop */
switch(type)
{
case GTPV2_IE_IMSI:
{
uint8_t *imsi = (uint8_t*)malloc(length+1);
if (imsi == NULL)
{
return ;
}
memcpy(imsi, gtpv2_info + offset,length);
//imsi[length] = '\0';
printf("IMSI: ");
for(i=0; i < length; i++)
printf("%.2x ",imsi[i]);
printf("\n");
}
break;
case GTPV2_IE_MSISDN:
{
uint8_t *msisdn = (uint8_t*)malloc(length+1);
if (msisdn == NULL)
{
return ;
}
memcpy(msisdn, gtpv2_info + offset + 1,length);
//msisdn[length] = '\0';
printf("MSISDN: ");
for(i=0; i < length; i++)
printf("%.2x ",msisdn[i]);
printf("\n");
}
break;
case GTPV2_IE_F_TEID:
{
//user ip
uint32_t user_ipv4;
uint8_t *teid = (uint8_t*)malloc(length+1);
if (teid == NULL)
{
return ;
}
memcpy(&user_ipv4, gtpv2_info + offset + 1 + 4,length);
printf("F-TEID IPv4: %s\n",int_ntoa(user_ipv4));
}
break;
default:
break;
}
}
offset += length;
}
}
static int dissect_gtpv2(u_char *gtpv2_info,int PayloadLen)
{
struct gtpv2_hdr_t gtpv2_hdr;
int offset = 0;
//gtpv2_hdr->teid = -1;
u_int8_t message_type, t_flag, p_flag, mp_flag, cause_aux;
u_int8_t version = 0;
int package_len = PayloadLen;
memset(>pv2_hdr, 0, sizeof(struct gtpv2_hdr_t));
/* Setting the TEID to -1 to say that the TEID is not valid for this packet */
version = gtpv2_info[0] >> 5;
printf("version: %d\n",version);
if (version != 2)
return 0;
p_flag = (gtpv2_info[0] & 0x10) >> 4;
t_flag = (gtpv2_info[0] & 0x08) >> 3;
mp_flag = (gtpv2_info[0] & 0x04) >> 2;
//printf("p_flag: %d\n",p_flag);
//printf("t_flag: %d\n",t_flag);
//printf("mp_flag: %d\n",mp_flag);
offset += 1;
/* Octet 2 */
message_type = gtpv2_info[offset];
gtpv2_hdr.msg_type = message_type;
printf("Message type: %d\n",gtpv2_hdr.msg_type);
offset += 1;
/* Octet 3 - 4 */
gtpv2_hdr.length = ntohs(*(uint16_t*)(gtpv2_info + offset));
printf("Message Length: %d\n",gtpv2_hdr.length);
offset += 2;
if (t_flag)
{
/* Tunnel Endpoint Identifier 4 octets */
gtpv2_hdr.teid = ntohl(*(long*)(gtpv2_info + offset));
printf("Tunnel Endpoint Identifier: %ld\n",gtpv2_hdr.teid);
offset += 4;
}
/* Sequence Number 3 octets */
offset += 3;
/* Spare 1 octet or if the "MP" flag is set to "1",
* then bits 8 to 5 of octet 12 shall indicate the message priority.
*/
if (mp_flag)
{
/* Bits 8 to 5 of octet 12 shall be encoded as the binary value of the Message Priority
* and it may take any value between 0 and 15, where 0 corresponds to the highest priority
* and 15 the lowest priority.
*/
}
else
{
}
offset += 1;
if (p_flag)
{
}
else
{
dissect_gtpv2_ie_common(gtpv2_info,offset, package_len,message_type);
}
}
static void confirm_gtpv2_packet(struct ip *pIp)
{
int iIpTotalLen = ntohs(pIp->ip_len);
int offset = 0;
int nFragSeq = 0;
struct udphdr* pUdpHdr = (struct udphdr*)((char*)pIp + (pIp->ip_hl<<2));
/*判断是否是gtpv2协议,gtpv2端口是514*/
if (pIp->ip_p == IPPROTO_UDP && (ntohs(pUdpHdr->dest) == GTPv2C_PORT) || (ntohs(pUdpHdr->source) == GTPv2C_PORT) )
{
printf("\n");
//printf("info udp\n");
int iPayloadLen = iIpTotalLen - (pIp->ip_hl<<2) - 8;
//printf("UDP Payload Len %d\n", iPayloadLen);
u_char *pGtpV2Hdr = (u_char*)(pUdpHdr+1);
dissect_gtpv2(pGtpV2Hdr,iPayloadLen);
}
}
编译运行:
总结
在LTE中,GTP(GPRS隧道协议)隧道用于通过基于GTP的接口进行通信的两个节点之间,以将流量分离为不同的通信流。
通过TEID(隧道端点标识符),IP地址和UDP端口号在每个节点中标识GTP隧道。
GTP隧道的接收端在本地分配发送方必须使用的TEID值。GTPv2包括一个更新的控制平面,该控制平面使控制消息能够在MME,S-GW,PDN GW等之间传递。最后,对于具体协议的实现,请参考3gpp相关的资料。
参考:
TS 29.281
TS 29.060
欢迎关注微信公众号【程序猿编码】,欢迎添加本人微信号(17865354792),交个朋友,咱们一起学习进步!