/* packet-gtp.c * Routines for GTP dissection * Copyright 2001, Michal Melerowicz * * $Id: packet-gtp.c,v 1.6 2001/06/18 02:17:46 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #include #ifdef NEED_SNPRINTF_H # include "snprintf.h" #endif #include "packet.h" #include "packet-ipv6.h" #define UDP_PORT_GTP 3386 #define TCP_PORT_GTP 3386 #define UDP_PORT_GTP3C 2123 /* 3G Control PDU */ #define UDP_PORT_GTP3U 2152 /* 3G T-PDU */ #define TCP_PORT_GTP3C 2123 /* 3G Control PDU */ #define TCP_PORT_GTP3U 2152 /* 3G T-PDU */ #define GTP_HDR_LENGTH 20 #define GTP3_HDR_LENGTH 11 /* Initialize the protocol and registered fields */ static int proto_gtp = -1; static int hf_gtp_flags = -1; static int hf_gtp_flags_ver = -1; static int hf_gtp_flags_pt = -1; static int hf_gtp_flags_spare = -1; static int hf_gtp_flags_snn = -1; static int hf_gtp_message_type = -1; static int hf_gtp_length = -1; static int hf_gtp_seq_number = -1; static int hf_gtp_flow_label = -1; static int hf_gtp_sndcp_number = -1; static int hf_gtp_tid = -1; static int hf_gtp_ext = -1; static int hf_gtp_ext_cause = -1; static int hf_gtp_ext_imsi = -1; static int hf_gtp_ext_rai_mcc = -1; static int hf_gtp_ext_rai_mnc = -1; static int hf_gtp_ext_rai_rac = -1; static int hf_gtp_ext_rai_lac = -1; static int hf_gtp_ext_tlli = -1; static int hf_gtp_ext_ptmsi = -1; static int hf_gtp_ext_qos_delay = -1; static int hf_gtp_ext_qos_mean = -1; static int hf_gtp_ext_qos_peak = -1; static int hf_gtp_ext_qos_precedence = -1; static int hf_gtp_ext_qos_reliability = -1; static int hf_gtp_ext_reorder = -1; /*static int hf_gtp_ext_auth_rand = -1; static int hf_gtp_ext_auth_sres = -1; static int hf_gtp_ext_auth_kc = -1;*/ static int hf_gtp_ext_map = -1; static int hf_gtp_ext_ptmsi_sig = -1; static int hf_gtp_ext_ms = -1; static int hf_gtp_ext_recover = -1; static int hf_gtp_ext_sel_mode = -1; static int hf_gtp_ext_flow_label = -1; static int hf_gtp_ext_flow_sig = -1; static int hf_gtp_ext_flow_ii_nsapi = -1; static int hf_gtp_ext_flow_ii = -1; static int hf_gtp_ext_tr_comm = -1; static int hf_gtp_ext_chrg_id = -1; static int hf_gtp_ext_user_addr = -1; static int hf_gtp_ext_user_addr_pdp_type = -1; static int hf_gtp_ext_user_addr_pdp_org = -1; static int hf_gtp_ext_apn = -1; static int hf_gtp_ext_proto_conf = -1; static int hf_gtp_ext_gsn_addr = -1; static int hf_gtp_ext_msisdn = -1; static int hf_gtp_ext_chrg_addr = -1; static int hf_gtp_ext_node_addr = -1; static int hf_gtp_ext_ext_id = -1; static int hf_gtp_ext_ext_val = -1; static int hf_gtp_ext_unknown = -1; /*static int gf_gtp_chrg_cap_gea = -1; static int gf_gtp_chrg_cap_sm_gsm = -1; static int gf_gtp_chrg_cap_sm_gprs = -1; static int gf_gtp_chrg_cap_ucs2 = -1; static int gf_gtp_chrg_cap_ss = -1; static int gf_gtp_chrg_cap_solsa = -1; */ /* Initialize the subtree pointers */ static gint ett_gtp = -1; static gint ett_gtp_flags = -1; static gint ett_gtp_ext = -1; static gint ett_gtp_qos = -1; #define GTP_VER_MASK 0xE0 static const value_string ver_types[] = { { 0, "GTP version 1" }, { 1, "GTP 3G" }, { 2, "None" }, { 3, "None" }, { 4, "None" }, { 5, "None" }, { 6, "None" }, { 7, "None" }, { 0, NULL } }; #define GTP_PT_MASK 0x10 #define GTP_SPARE_MASK 0x0E #define GTP_SNN_MASK 0x01 /* definitions of GTP messages */ #define GTP_MSG_UNKNOWN 0x00 #define GTP_MSG_ECHO_REQ 0x01 #define GTP_MSG_ECHO_RESP 0x02 #define GTP_MSG_VER_NOT_SUPP 0x03 #define GTP_MSG_NODE_ALIVE_REQ 0x04 #define GTP_MSG_NODE_ALIVE_RESP 0x05 #define GTP_MSG_REDIR_REQ 0x06 #define GTP_MSG_REDIR_RESP 0x07 #define GTP_MSG_CREATE_PDP_REQ 0x10 #define GTP_MSG_CREATE_PDP_RESP 0x11 #define GTP_MSG_UPDATE_PDP_REQ 0x12 #define GTP_MSG_UPDATE_PDP_RESP 0x13 #define GTP_MSG_DELETE_PDP_REQ 0x14 #define GTP_MSG_DELETE_PDP_RESP 0x15 #define GTP_MSG_CREATE_AA_PDP_REQ 0x16 #define GTP_MSG_CREATE_AA_PDP_RESP 0x17 #define GTP_MSG_DELETE_AA_PDP_REQ 0x18 #define GTP_MSG_DELETE_AA_PDP_RESP 0x19 #define GTP_MSG_ERR_IND 0x1A #define GTP_MSG_PDU_NOTIFY_REQ 0x1B #define GTP_MSG_PDU_NOTIFY_RESP 0x1C #define GTP_MSG_PDU_NOTIFY_REJ_REQ 0x1D #define GTP_MSG_PDU_NOTIFY_REJ_RESP 0x1E #define GTP_MSG_SUPP_EXT_HDR_NOT 0x1F #define GTP_MSG_SEND_ROUT_INFO_REQ 0x20 #define GTP_MSG_SEND_ROUT_INFO_RESP 0x21 #define GTP_MSG_FAIL_REP_REQ 0x22 #define GTP_MSG_FAIL_REP_RESP 0x23 #define GTP_MSG_MS_PRESENT_REQ 0x24 #define GTP_MSG_MS_PRESENT_RESP 0x25 #define GTP_MSG_IDENT_REQ 0x30 #define GTP_MSG_IDENT_RESP 0x31 #define GTP_MSG_SGSN_CNTX_REQ 0x32 #define GTP_MSG_SGSN_CNTX_RESP 0x33 #define GTP_MSG_SGSN_CNTX_ACK 0x34 #define GTP_MSG_FORW_RELOC_REQ 0x35 #define GTP_MSG_FORW_RELOC_RESP 0x36 #define GTP_MSG_FORW_RELOC_COMP 0x37 #define GTP_MSG_RELOC_CANCEL_REQ 0x38 #define GTP_MSG_RELOC_CANCEL_RESP 0x39 #define GTP_MSG_FORW_SRNS_CNTX 0x3A #define GTP_MSG_FORW_RELOC_ACK 0x3B #define GTP_MSG_FORW_SRNS_CNTX_ACK 0x3C #define GTP_MSG_DATA_TRANSF_REQ 0xF0 #define GTP_MSG_DATA_TRANSF_RESP 0xF1 #define GTP_MSG_TPDU 0xFF static const value_string message_type[] = { { GTP_MSG_UNKNOWN, "For future use" }, { GTP_MSG_ECHO_REQ, "Echo request" }, { GTP_MSG_ECHO_RESP, "Echo response" }, { GTP_MSG_VER_NOT_SUPP, "Version not supported" }, { GTP_MSG_NODE_ALIVE_REQ, "Node alive request" }, { GTP_MSG_NODE_ALIVE_RESP, "Node alive response" }, { GTP_MSG_REDIR_REQ, "Redirection request" }, { GTP_MSG_REDIR_RESP, "Redirection response" }, { GTP_MSG_CREATE_PDP_REQ, "Create PDP context request" }, { GTP_MSG_CREATE_PDP_RESP, "Create PDP context response" }, { GTP_MSG_UPDATE_PDP_REQ, "Update PDP context request" }, { GTP_MSG_UPDATE_PDP_RESP, "Update PDP context response" }, { GTP_MSG_DELETE_PDP_REQ, "Delete PDP context request" }, { GTP_MSG_DELETE_PDP_RESP, "Delete PDP context respone" }, { GTP_MSG_CREATE_AA_PDP_REQ, "Create AA PDP Context Request" }, { GTP_MSG_CREATE_AA_PDP_RESP, "Create AA PDP Context Response" }, { GTP_MSG_DELETE_AA_PDP_REQ, "Delete AA PDP Context Request" }, { GTP_MSG_DELETE_AA_PDP_RESP, "Delete AA PDP Context Response" }, { GTP_MSG_ERR_IND, "Error indication" }, { GTP_MSG_PDU_NOTIFY_REQ, "PDU notification request" }, { GTP_MSG_PDU_NOTIFY_RESP, "PDU notification response" }, { GTP_MSG_PDU_NOTIFY_REJ_REQ, "PDU notification reject request" }, { GTP_MSG_PDU_NOTIFY_REJ_RESP, "PDU notification reject response" }, { GTP_MSG_SUPP_EXT_HDR_NOT, "Supported extension header notification" }, { GTP_MSG_SEND_ROUT_INFO_REQ, "Send routing information for GPRS request" }, { GTP_MSG_SEND_ROUT_INFO_RESP, "Send routing information for GPRS response" }, { GTP_MSG_FAIL_REP_REQ, "Failure report request" }, { GTP_MSG_FAIL_REP_RESP, "Failure report response" }, { GTP_MSG_MS_PRESENT_REQ, "Note MS GPRS present request" }, { GTP_MSG_MS_PRESENT_RESP, "Note MS GPRS present response" }, { GTP_MSG_IDENT_REQ, "Identification request" }, { GTP_MSG_IDENT_RESP, "Identification response" }, { GTP_MSG_SGSN_CNTX_REQ, "SGSN context request" }, { GTP_MSG_SGSN_CNTX_RESP, "SGSN context response" }, { GTP_MSG_SGSN_CNTX_ACK, "SGSN context acknowledgement" }, { GTP_MSG_FORW_RELOC_REQ, "Forward relocation request" }, { GTP_MSG_FORW_RELOC_RESP, "Forward relocation response" }, { GTP_MSG_FORW_RELOC_COMP, "Forward relocation complete" }, { GTP_MSG_RELOC_CANCEL_REQ, "Relocation cancel request" }, { GTP_MSG_RELOC_CANCEL_RESP, "Relocation cancel response" }, { GTP_MSG_FORW_SRNS_CNTX, "Forward SRNS context" }, { GTP_MSG_FORW_RELOC_ACK, "Forward relocation complete acknowledge" }, { GTP_MSG_FORW_SRNS_CNTX_ACK, "Forward SRNS context acknowledge" }, { GTP_MSG_DATA_TRANSF_REQ, "Data record transfer request" }, { GTP_MSG_DATA_TRANSF_RESP, "Data record transfer response" }, { GTP_MSG_TPDU, "T-PDU" }, { 0, NULL } }; /* definitions of fields in extension header */ #define GTP_EXT_CAUSE 0x01 #define GTP_EXT_IMSI 0x02 #define GTP_EXT_RAI 0x03 #define GTP_EXT_TLLI 0x04 #define GTP_EXT_PTMSI 0x05 #define GTP_EXT_QOS 0x06 #define GTP_EXT_REORDER 0x08 #define GTP_EXT_AUTH 0x09 #define GTP_EXT_MAP 0x0B #define GTP_EXT_PTMSI_SIG 0x0C #define GTP_EXT_MS 0x0D #define GTP_EXT_RECOVER 0x0E #define GTP_EXT_SEL_MODE 0x0F #define GTP_EXT_FLOW_LABEL 0x10 /* for 3G Tunnel Endpoint Id Data I */ #define GTP_EXT_FLOW_SIG 0x11 /* for 3G Tunnel Endpoint Id Control Plane */ #define GTP_EXT_FLOW_II 0x12 /* for 3G Tunnel Endpoint Id Data II */ #define GTP_EXT_TEARDOWN 0x13 /* 3G */ #define GTP_EXT_NSAPI 0x14 /* 3G */ #define GTP_EXT_RANAP_CAUSE 0x15 /* 3G */ #define GTP_EXT_RAB_CNTX 0x16 /* 3G */ #define GTP_EXT_RP_SMS 0x17 /* 3G */ #define GTP_EXT_RP 0x18 /* 3G */ #define GTP_EXT_PKT_FLOW_ID 0x19 /* 3G */ #define GTP_EXT_CHRG_CHAR 0x1A /* 3G */ #define GTP_EXT_TRACE_REF 0x1B /* 3G */ #define GTP_EXT_TRACE_TYPE 0x1C /* 3G */ #define GTP_EXT_MS_REASON 0x1D /* 3G */ #define GTP_EXT_TR_COMM 0x7E /* charging */ #define GTP_EXT_CHRG_ID 0x7F #define GTP_EXT_USER_ADDR 0x80 #define GTP_EXT_MM_CNTX 0x81 #define GTP_EXT_PDP_CNTX 0x82 #define GTP_EXT_APN 0x83 #define GTP_EXT_PROTO_CONF 0x84 #define GTP_EXT_GSN_ADDR 0x85 #define GTP_EXT_MSISDN 0x86 #define GTP_EXT_QOS_PROF 0x87 /* 3G */ #define GTP_EXT_AUTH_QUI 0x88 /* 3G */ #define GTP_EXT_TRAF_FLOW 0x89 /* 3G */ #define GTP_EXT_TARGET_ID 0x8A /* 3G */ #define GTP_EXT_UTRAN_CONT 0x8B /* 3G */ #define GTP_EXT_RAB_SETUP 0x8C /* 3G */ #define GTP_EXT_HDR_LIST 0x8D /* 3G */ #define GTP_EXT_TRIGGER_ID 0x8E /* 3G */ #define GTP_EXT_OMC_IDEN 0x8F /* 3G */ #define GTP_EXT_REL_PACK 0xF9 /* charging */ #define GTP_EXT_CANC_PACK 0xFA /* charging */ #define GTP_EXT_CHRG_ADDR 0xFB #define GTP_EXT_DATA_REC 0xFC /* charging */ #define GTP_EXT_REQ_RESP 0xFD /* charging */ #define GTP_EXT_NODE_ADDR 0xFE /* charging */ #define GTP_EXT_PRIV_EXT 0xFF static const value_string gtp_ext_val[] = { { GTP_EXT_CAUSE, "Cause of operation" }, { GTP_EXT_IMSI, "IMSI" }, { GTP_EXT_RAI, "Routeing Area Identity" }, { GTP_EXT_TLLI, "Temporary Logical Link Identity" }, { GTP_EXT_PTMSI, "Packet TMSI" }, { GTP_EXT_QOS, "Quality of Service" }, { GTP_EXT_REORDER, "Reorder required" }, { GTP_EXT_AUTH, "Authentication triplets" }, { GTP_EXT_MAP, "MAP cause" }, { GTP_EXT_PTMSI_SIG, "P-TMSI signature" }, { GTP_EXT_MS, "MS validated" }, { GTP_EXT_RECOVER, "Recovery" }, { GTP_EXT_SEL_MODE, "Selection mode" }, { GTP_EXT_FLOW_LABEL, "Flow label data I" }, { GTP_EXT_FLOW_SIG, "Flow label signalling" }, { GTP_EXT_FLOW_II, "Flow label data II" }, { GTP_EXT_TR_COMM, "Packet transfer command" }, { GTP_EXT_CHRG_ID, "Charging ID" }, { GTP_EXT_USER_ADDR, "End user address" }, { GTP_EXT_MM_CNTX, "MM context" }, { GTP_EXT_PDP_CNTX, "PDP context" }, { GTP_EXT_APN, "Access point name" }, { GTP_EXT_PROTO_CONF, "Protocol configuration options" }, { GTP_EXT_GSN_ADDR, "GSN address" }, { GTP_EXT_MSISDN, "MS international PSTN/ISDN number" }, { GTP_EXT_CHRG_ADDR, "Charging gateway address" }, { GTP_EXT_DATA_REC, "Data record packet" }, { GTP_EXT_NODE_ADDR, "Address of recommended node" }, { GTP_EXT_PRIV_EXT, "Private extension" }, { 0, NULL } }; static const value_string cause_type[] = { { 0, "Request IMSI" }, { 1, "Request IMEI" }, { 2, "Request IMSI and IMEI" }, { 3, "No identity needed" }, { 4, "MS refuses" }, { 5, "MS is not GPRS responding" }, { 59, "System failure" }, /* charging */ { 60, "The transmit buffers are becoming full" }, /* charging */ { 61, "The receive buffers are becoming full" }, /* charging */ { 62, "Another node is about to go down" }, /* charging */ { 63, "This node is about to go down" }, /* charging */ { 128, "Request accepted" }, { 192, "Non-existent" }, { 193, "Invalid message format" }, { 194, "IMSI not known" }, { 195, "MS is GPRS detached" }, { 196, "MS is not GPRS responding" }, { 197, "MS refuses" }, { 198, "Version not supported" }, { 199, "No resource available" }, { 200, "Service not supported" }, { 201, "Mandatory IE incorrect" }, { 202, "Mandatory IE missing" }, { 203, "Optional IE incorrect" }, { 204, "System failure" }, { 205, "Roaming restriction" }, { 206, "P-TMSI signature mismatch" }, { 207, "GPRS connection suspended" }, { 208, "Authentication failure" }, { 209, "User authentication failed" }, { 210, "Context not found" }, { 211, "All PDP dynamic addresses are occupied" }, { 212, "No memory is available" }, { 252, "Request related to possibly duplicated packets already fulfilled" }, /* charging */ { 253, "Request already fulfilled" }, /* charging */ { 254, "Sequence numbers of released/cancelled packets IE incorrect" }, /* charging */ { 255, "Request not fulfilled" }, /* charging */ { 0, NULL } }; static const value_string map_cause_type[] = { { 1, "Unknown subscriber" }, { 17, "User busy" }, { 18, "Absent subscriber" }, { 21, "Call barred/Forwarding violation" }, { 22, "Number changed" }, { 55, "CUG Reject" }, { 57, "Teleservice/Bearer Service not provisioned" }, { 69, "Facility not supported" }, { 111, "Data missing/Unexpected data value/System failure" }, { 0, NULL } }; static const value_string pdp_type[] = { { 0x00, "X.25" }, { 0x01, "PPP" }, { 0x02, "OSP:IHOSS" }, { 0x21, "IPv4" }, { 0x57, "IPv6" }, { 0, NULL } }; static const value_string qos_delay_type[] = { { 0x00, "Subsribed delay class (in MS to network direction)" }, { 0x01, "Delay class 1" }, { 0x02, "Delay class 2" }, { 0x03, "Delay class 3" }, { 0x04, "Delay class 4 (best effort)" }, { 0x07, "Reserved" }, { 0, NULL } }; static const value_string qos_reliability_type[] = { { 0x00, "Subscribed reliability class (in MS to network direction)" }, { 0x01, "Ack GTP/LLC/RLC, Protected data" }, { 0x02, "Unack GTP, Ack LLC/RLC, Protected data" }, { 0x03, "Unack GTP/LLC, Ack RLC, Protected data" }, { 0x04, "Unack GTP/LLC/RLC, Protected data" }, { 0x05, "Unack GTP/LLC/RLC, Unprotected data" }, { 0x07, "Reserved" }, { 0, NULL } }; static const value_string qos_peak_type[] = { { 0x00, "Subscribed peak throughput (in MS to network direction)" }, { 0x01, "Up to 1 000 oct/s" }, { 0x02, "Up to 2 000 oct/s" }, { 0x03, "Up to 4 000 oct/s" }, { 0x04, "Up to 8 000 oct/s" }, { 0x05, "Up to 16 000 oct/s" }, { 0x06, "Up to 32 000 oct/s" }, { 0x07, "Up to 64 000 oct/s" }, { 0x08, "Up to 128 000 oct/s" }, { 0x09, "Up to 256 000 oct/s" }, { 0x0F, "Reserved" }, { 0, NULL } }; static const value_string qos_precedence_type[] = { { 0x00, "Subscribed precedence (in MS to network direction)" }, { 0x01, "High priority" }, { 0x02, "Normal priority" }, { 0x03, "Low priority" }, { 0x07, "Reserved" }, { 0, NULL } }; static const value_string qos_mean_type[] = { { 0x00, "Subscribed mean throughput (in MS to network direction)" }, { 0x01, "100 oct/h" }, { 0x02, "200 oct/h" }, { 0x03, "500 oct/h" }, { 0x04, "1 000 oct/h" }, { 0x05, "2 000 oct/h" }, { 0x06, "5 000 oct/h" }, { 0x07, "10 000 oct/h" }, { 0x08, "20 000 oct/h" }, { 0x09, "50 000 oct/h" }, { 0x0A, "100 000 oct/h" }, { 0x0B, "200 000 oct/h" }, { 0x0C, "500 000 oct/h" }, { 0x0D, "1 000 000 oct/h" }, { 0x0E, "2 000 000 oct/h" }, { 0x0F, "5 000 000 oct/h" }, { 0x10, "10 000 000 oct/h" }, { 0x11, "20 000 000 oct/h" }, { 0x12, "50 000 000 oct/h" }, { 0x1E, "Reserved" }, { 0x1F, "Best effort" }, { 0, NULL }, }; static const value_string sel_mode_type[] = { { 0, "MS or network provided APN, subscriber verified" }, { 1, "MS provided APN, subscription not verified" }, { 2, "Network provided APN, subscription not verified" }, { 3, "For future use (Network provided APN, subscription not verified" }, { 0, NULL } }; static const value_string tr_comm_type[] = { { 1, "Send data record packet" }, { 2, "Send possibly duplicated data record packet" }, { 3, "Cancel data record packet" }, { 4, "Release data record packet"}, { 0, NULL } }; static const value_string mm_proto_disc[] = { { 0x00, "Group call control" }, { 0x01, "Broadcast call control" }, { 0x02, "PDSS1" }, { 0x03, "Call control; call related SS messages" }, { 0x04, "PDSS2" }, { 0x05, "Mobility Management messages for non-GPRS services" }, { 0x06, "Radio Resource management messages" }, { 0x08, "Mobility Management messages for GPRS services" }, { 0x09, "SMS" }, { 0x0A, "Session Management messages" }, { 0x0B, "Non-call related SS messages" }, { 0, NULL } }; static const value_string mm_rr_mess[] = { { 0x3C, "RR initialization request" }, { 0x3B, "Additional assignment" }, { 0x3F, "Immediate assignment" }, { 0x39, "Immediate assignment extended" }, { 0x3A, "Immediate assignment reject" }, { 0x35, "Ciphering mode command" }, { 0x32, "Ciphering mode complete" }, { 0x30, "Configuration change command" }, { 0x31, "Configuration change ack" }, { 0x33, "Configuration change reject" }, { 0x2E, "Assignment command" }, { 0x29, "Assignment complete" }, { 0x2F, "Assigment failure" }, { 0x2B, "Handover command" }, { 0x2C, "Handover complete" }, { 0x28, "Handover failure" }, { 0x2D, "Physical information" }, { 0x08, "RR-cell change order" }, { 0x23, "PDCH assignment command" }, { 0x0D, "Channel release" }, { 0x0A, "Partial release" }, { 0x0F, "PArtial release complete" }, { 0x21, "Paging request type 1" }, { 0x22, "Paging request type 2" }, { 0x24, "Paging request type 3" }, { 0x27, "Paging response" }, { 0x20, "Notification/NCH" }, { 0x25, "Notification/FACCH" }, { 0x26, "Reserved" }, { 0x0B, "Reserved" }, { 0x18, "System information type 8" }, { 0x19, "System information type 1" }, { 0x1A, "System information type 2" }, { 0x1B, "System information type 3" }, { 0x1C, "System information type 4" }, { 0x1D, "System information type 5" }, { 0x1E, "System information type 6" }, { 0x1F, "System information type 7" }, { 0x02, "System information type 2bis" }, { 0x03, "System information type 2ter" }, { 0x05, "System information type 5bis" }, { 0x06, "System information type 5ter" }, { 0x04, "System information 9" }, { 0x00, "System information 13" }, { 0x01, "System information 14" }, { 0x3D, "System information type 16" }, { 0x3E, "System information type 17" }, { 0x10, "Channel mode modify" }, { 0x12, "RR status" }, { 0x17, "Channel mode modify ack" }, { 0x14, "Frequency redefinition " }, { 0x15, "Measurement report" }, { 0x16, "Classmark change" }, { 0x13, "Classmark enquiry" }, { 0x36, "Extended measurement report" }, { 0x37, "Extended measurement order" }, { 0x34, "GPRS suspension request" }, { 0x09, "VGCS uplink grant" }, { 0x0E, "Uplink release" }, { 0x0C, "Uplink free" }, { 0x2A, "Uplink busy" }, { 0x11, "Talker indication" }, { 0, NULL } }; static const value_string mm_mm_mess[] = { { 0x01, "IMSI DETACH INDICATION" }, { 0x02, "LOCATION UPDATING ACCEPT" }, { 0x04, "LOCATION UPDATING REJECT" }, { 0x08, "LOCATION UPDATING REQUEST" }, { 0x11, "AUTHENTICATION REJECT" }, { 0x12, "AUTHENTICATION REQUEST" }, { 0x14, "AUTHENTICATION RESPONSE" }, { 0x18, "IDENTITY REQUEST" }, { 0x19, "IDENTITY RESPONSE" }, { 0x1A, "TMSI REALLOCATION COMMAND" }, { 0x1B, "TMSI REALLOCATION COMPLETE" }, { 0x21, "CM SERVICE ACCEPT" }, { 0x22, "CM SERVICE REJECT" }, { 0x23, "CM SERVICE ABORT" }, { 0x24, "CM SERVICE REQUEST" }, { 0x25, "CM SERVICE PROMPT" }, { 0x26, "NOTIFICATION RESPONSE" }, { 0x28, "CM RE-ESTABLISHMENT REQUEST" }, { 0x29, "ABORT" }, { 0x30, "MM NULL" }, { 0x31, "MM STATUS" }, { 0x32, "MM INFORMATION" }, { 0, NULL } }; static const value_string mm_cc_mess[] = { { 0x00, "escape to nationally specific" }, /*{ 0 x 0 0, "- - - Call establishment messages:" },*/ { 0x01, "ALERTING" }, { 0x08, "CALL CONFIRMED" }, { 0x02, "CALL PROCEEDING" }, { 0x07, "CONNECT" }, { 0x0F, "CONNECT ACKNOWLEDGE" }, { 0x0E, "EMERGENCY SETUP" }, { 0x03, "PROGRESS" }, { 0x04, "CC-ESTABLISHMENT" }, { 0x06, "CC-ESTABLISHMENT CONFIRMED" }, { 0x0B, "RECALL" }, { 0x09, "START CC" }, { 0x05, "SETUP" }, /*{ 0 x 0 1, "- - - Call information phase messages:" },*/ { 0x17, "MODIFY" }, { 0x1F, "MODIFY COMPLETE" }, { 0x13, "MODIFY REJECT" }, { 0x10, "USER INFORMATION" }, { 0x18, "HOLD" }, { 0x19, "HOLD ACKNOWLEDGE" }, { 0x1A, "HOLD REJECT" }, { 0x1C, "RETRIEVE" }, { 0x1D, "RETRIEVE ACKNOWLEDGE" }, { 0x1E, "RETRIEVE REJECT" }, /*{ 0 x 1 0, "- - - Call clearing messages:" },*/ { 0x25, "DISCONNECT" }, { 0x2D, "RELEASE" }, { 0x2A, "RELEASE COMPLETE" }, /*{ 0 x 1 1, "- - - Miscellaneous messages:" },*/ { 0x39, "CONGESTION CONTROL" }, { 0x3E, "NOTIFY" }, { 0x3D, "STATUS" }, { 0x34, "STATUS ENQUIRY" }, { 0x35, "START DTMF" }, { 0x31, "STOP DTMF" }, { 0x32, "STOP DTMF ACKNOWLEDGE" }, { 0x36, "START DTMF ACKNOWLEDGE" }, { 0x37, "START DTMF REJECT" }, { 0x3A, "FACILITY" }, { 0, NULL } }; static const value_string mm_gprs_mess[] = { { 0x01, "Attach request" }, { 0x02, "Attach accept" }, { 0x03, "Attach complete" }, { 0x04, "Attach reject" }, { 0x05, "Detach request" }, { 0x06, "Detach accept" }, { 0x08, "Routing area update request" }, { 0x09, "Routing area update accept" }, { 0x0A, "Routing area update complete" }, { 0x0B, "Routing area update reject" }, { 0x10, "P-TMSI reallocation command" }, { 0x11, "P-TMSI reallocation complete" }, { 0x12, "Authentication and ciphering req" }, { 0x13, "Authentication and ciphering resp" }, { 0x14, "Authentication and ciphering rej" }, { 0x15, "Identity request" }, { 0x16, "Identity response" }, { 0x20, "GMM status" }, { 0x21, "GMM information" }, { 0, NULL } }; static dissector_handle_t ip_handle; static dissector_handle_t ppp_handle; static int decode_gtp_cause(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_imsi(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_rai(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_tlli(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_ptmsi(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_qos(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_reorder(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_auth(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_map(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_ptmsi_sig(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_ms(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_recover(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_sel_mode(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_flow_label(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_flow_sig(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_flow_ii(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_tr_comm(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_chrg_id(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_user_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_mm_cntx(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_pdp_cntx(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_apn(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_gsn_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_proto_conf(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static void free_tvb_data(void *tvb_data); static int decode_gtp_msisdn(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_chrg_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_data_rec(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_node_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_priv_ext(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); static int decode_gtp_unknown(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); typedef struct _gtp_opt { int optcode; /* char *name; */ int (*decode)(tvbuff_t *, int, packet_info *, proto_tree *); } gtp_opt_t; static const gtp_opt_t gtpopt[] = { { GTP_EXT_CAUSE, decode_gtp_cause }, { GTP_EXT_IMSI, decode_gtp_imsi }, { GTP_EXT_RAI, decode_gtp_rai }, { GTP_EXT_TLLI, decode_gtp_tlli }, { GTP_EXT_PTMSI, decode_gtp_ptmsi }, { GTP_EXT_QOS, decode_gtp_qos }, { GTP_EXT_REORDER, decode_gtp_reorder }, { GTP_EXT_AUTH, decode_gtp_auth }, { GTP_EXT_MAP, decode_gtp_map }, { GTP_EXT_PTMSI_SIG,decode_gtp_ptmsi_sig }, { GTP_EXT_MS, decode_gtp_ms }, { GTP_EXT_RECOVER, decode_gtp_recover }, { GTP_EXT_SEL_MODE, decode_gtp_sel_mode }, { GTP_EXT_FLOW_LABEL,decode_gtp_flow_label }, { GTP_EXT_FLOW_SIG, decode_gtp_flow_sig }, { GTP_EXT_FLOW_II, decode_gtp_flow_ii }, { GTP_EXT_TR_COMM, decode_gtp_tr_comm }, { GTP_EXT_CHRG_ID, decode_gtp_chrg_id }, { GTP_EXT_USER_ADDR,decode_gtp_user_addr }, { GTP_EXT_MM_CNTX, decode_gtp_mm_cntx }, { GTP_EXT_PDP_CNTX, decode_gtp_pdp_cntx }, { GTP_EXT_APN, decode_gtp_apn }, { GTP_EXT_PROTO_CONF,decode_gtp_proto_conf }, { GTP_EXT_GSN_ADDR, decode_gtp_gsn_addr }, { GTP_EXT_MSISDN, decode_gtp_msisdn }, { GTP_EXT_CHRG_ADDR,decode_gtp_chrg_addr }, { GTP_EXT_DATA_REC, decode_gtp_data_rec }, { GTP_EXT_NODE_ADDR,decode_gtp_node_addr }, { GTP_EXT_PRIV_EXT, decode_gtp_priv_ext }, { 0, decode_gtp_unknown} }; typedef struct _pdp { guint8 nsapi; guint8 sapi; guint8 qos_sub[3]; guint8 qos_req[3]; guint8 qos_neg[3]; guint16 sn_down; guint16 sn_up; guint8 pdu_send_no; guint8 pdu_rec_no; guint16 up_flow; guint8 pdp_org; guint8 pdp_type; guint8 pdp_addr_len; } pdp_t; struct _gtp_hdr { guint8 flags; guint8 message; guint16 length; guint16 seq_no; guint16 flow_label; guint8 npdu_no; guint8 spare[3]; guint8 tid[8]; } gtp; struct _gtp3_hdr { guint8 flags; guint8 message; guint16 length; guint32 teid; guint16 seq_no; guint8 npdu_no; } gtp3_hdr; struct _gtp { guint8 flags; guint8 message; guint16 length; union { struct { guint16 seq_no; guint16 flow_label; guint8 npdu_no; guint8 spare[3]; } v1; struct { guint32 teid; guint16 seq_no; guint8 npdu_no; guint8 next; } v2; } v; } gtp_g; struct gcdr_ { /* GCDR 118B */ guint8 imsi[8]; guint32 ggsnaddr; guint32 chrgid; guint32 sgsnaddr; gchar apn[63]; guint8 pdporg; guint8 pdptype; guint32 pdpaddr; guint8 addrflag; guint8 qos[3]; guint32 uplink; guint32 downlink; guint32 timestamp; guint32 opening; guint32 duration; guint8 closecause; guint32 seqno; } gcdr; typedef struct change_ { guint8 change; guint32 time1; guint32 time2; guint32 uplink; guint32 downlink; guint8 qos_req[3]; guint8 qos_neg[3]; } change_t; struct _scdr { /* SCDR 277B */ guint16 len; guint8 netini; guint8 anon; guint8 imsilen; guint8 imsi[8]; guint8 imei[8]; guint8 msisdnlen; guint8 msisdn[10]; guint32 sgsnaddr; guint8 msclass_notused[12]; guint8 msclass_caplen; guint8 msclass_cap; guint16 msclass_capomit; guint16 lac; guint8 rac; guint16 ci; guint32 chrgid; guint32 ggsnaddr; gchar apn[64]; guint8 pdporg; guint8 pdptype; guint32 pdpaddr; guint8 listind; change_t change[5]; guint32 timestamp; guint32 opening; guint32 duration; guint8 sgsnchange; guint8 closecause; guint8 diag1; guint8 diag2; guint8 diag3; guint8 diag4; guint32 diag5; guint32 seqno; } scdr; typedef struct mmchange_ { guint16 lac; guint8 rac; guint16 cid; guint8 omit[8]; } mmchange_t; struct _mcdr { /* MCDR 147B */ guint16 len; guint8 imsilen; guint8 imsi[8]; guint8 imei[8]; guint8 msisdnlen; guint8 msisdn[10]; guint32 sgsnaddr; guint8 msclass_notused[12]; guint8 msclass_caplen; guint8 msclass_cap; guint16 msclass_capomit; guint16 lac; guint8 rac; guint16 cid; guint8 change_count; mmchange_t change[5]; guint32 timestamp; guint32 opening; /* guint8 opening[8]; */ guint32 duration; guint8 sgsnchange; guint8 closecause; guint8 diag1; guint8 diag2; guint8 diag3; guint8 diag4; guint32 diag5; guint32 seqno; } mcdr; struct _socdr { /* SOCDR 80B */ guint16 len; guint8 imsilen; guint8 imsi[8]; guint8 imei[8]; guint8 msisdnlen; guint8 msisdn[10]; guint32 sgsnaddr; guint8 msclass_not_used[12]; guint8 msclass_caplen; guint8 msclass_cap[3]; guint8 serv_centr[9]; guint8 rec_ent[9]; guint16 lac; guint8 rac; guint16 ci; guint8 timestamp[8]; guint8 messref; guint16 smsres; } socdr; struct _stcdr { /* STCDR 79B */ guint16 len; guint8 imsilen; guint8 imsi[8]; guint8 imei[8]; guint8 msisdnlen; guint8 msisdn[10]; guint32 sgsnaddr; guint8 msclass_not_used[12]; guint8 msclass_caplen; guint8 msclass_cap[3]; guint8 serv_centr[9]; guint8 rec_ent[9]; guint16 lac; guint8 rac; guint16 ci; guint8 timestamp[8]; guint16 smsres; } stcdr; guint8 gtp_version = 0; char *yesno[] = { "False", "True" }; static void col_append_str_gtp(frame_data *fd, gint el) { int i; int max_len; gchar _tmp[COL_MAX_LEN]; max_len = COL_MAX_LEN; for (i = 0; i < fd->cinfo->num_cols; i++) { if (fd->cinfo->fmt_matx[i][el]) { if (fd->cinfo->col_data[i] != fd->cinfo->col_buf[i]) { strncpy(fd->cinfo->col_buf[i], fd->cinfo->col_data[i], max_len); fd->cinfo->col_buf[i][max_len - 1] = '\0'; } _tmp[0] = '\0'; strcat(_tmp, "GTP <"); strcat(_tmp, fd->cinfo->col_buf[i]); strcat(_tmp, ">"); fd->cinfo->col_buf[i][0] = '\0'; strcat(fd->cinfo->col_buf[i], _tmp); fd->cinfo->col_data[i] = fd->cinfo->col_buf[i]; } } } static gchar * id_to_str(const guint8 *ad) { static gchar *str[17]; gchar *p; guint8 octet, i; static const gchar hex_digits[16] = "0123456789abcdef"; p = (gchar *)&str[17]; *--p = '\0'; i = 7; for (;;) { octet = ad[i]; *--p = hex_digits[(octet >> 4) & 0xF]; *--p = hex_digits[octet&0xF]; if (i == 0) break; i--; } return p; } static gchar * msisdn_to_str(const guint8 *ad, int len) { static gchar *str[17]; gchar *p; guint8 octet, i; static const gchar hex_digits[16] = "0123456789 "; p = (gchar *)&str[0]; *p = '+'; i = 1; for (;;) { octet = ad[i]; *++p = hex_digits[octet&0xF]; *++p = hex_digits[(octet >> 4) &0xF]; if (i == len-1) break; i++; } *++p = '\0'; return (gchar *)&str[0]; } /* static gchar * time_int_to_str(guint32 time) { guint hours, mins, secs, month, days; guint mths_n[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; guint mths_s[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static gchar *cur, *p, str[3][2+1+2+1+2+1+4+1+2+1+2+2]; if (cur == &str[0][0]) { cur = &str[1][0]; } else if (cur == &str[1][0]) { cur = &str[2][0]; } else { cur = &str[0][0]; } if (time == 0) { sprintf (cur, "00:00:00 1970-01-01"); return cur; } secs = time % 60; time /= 60; mins = time % 60; time /= 60; hours = time % 24; time /= 24; days = time % 365; time /= 365; days -= time / 4 + 1; if (!(time / 4)) { for (month=0; month<12; month++) if (days > mths_n[month]) days -= mths_n[month]; else break; } else { for (month=0; month<12; month++) if (days > mths_s[month]) days -= mths_s[month]; else break; } month++; time += 1970; p = cur; sprintf (p, "%02d:%02d:%02d %u-%02d-%02d", hours, mins, secs, time, month, days); return cur; }*/ /* Decoders of fields in extension headers, each function returns no of bytes from field */ /* ETSI 9.60 * 3G TS 29.060 v. 3.5.0, 7.7.1*/ static int decode_gtp_cause(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 cause; cause = tvb_get_guint8(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_cause, tvb, offset, 2, cause, "%s: %u", val_to_str(GTP_EXT_CAUSE, gtp_ext_val, "Unknown message"), cause); return 2; } static int decode_gtp_imsi(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 tid_val[8]; gchar *tid_str; tvb_memcpy(tvb, tid_val, offset+1, 8); tid_val[1] = tid_val[1] & 0x0F; tid_str = id_to_str(tid_val); proto_tree_add_string_format(tree, hf_gtp_ext_imsi, tvb, offset, 9, tid_str, "%s: %s", val_to_str(GTP_EXT_IMSI, gtp_ext_val, "Unknown message"), tid_str); return 9; } static int decode_gtp_rai(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { proto_tree *ext_tree; proto_item *te; te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_RAI, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); proto_tree_add_uint(ext_tree, hf_gtp_ext_rai_mcc, tvb, offset+1, 2, tvb_get_ntohs(tvb, offset+1) & 0xFF0F); proto_tree_add_uint(ext_tree, hf_gtp_ext_rai_mnc, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+3)); proto_tree_add_uint(ext_tree, hf_gtp_ext_rai_lac, tvb, offset+4, 2, tvb_get_ntohs(tvb, offset+4)); proto_tree_add_uint(ext_tree, hf_gtp_ext_rai_rac, tvb, offset+6, 1, tvb_get_guint8(tvb, offset+6)); return 7; } static int decode_gtp_tlli(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint32 tlli; tlli = tvb_get_ntohl(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_tlli, tvb, offset, 5, tlli, "%s: %x", val_to_str(GTP_EXT_TLLI, gtp_ext_val, "Unknown message"), tlli); return 5; } static int decode_gtp_ptmsi(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint32 ptmsi; ptmsi = tvb_get_ntohl(tvb, offset); proto_tree_add_uint_format(tree, hf_gtp_ext_ptmsi, tvb, offset, 5, ptmsi, "%s: %x", val_to_str(GTP_EXT_PTMSI, gtp_ext_val, "Unknown message"), ptmsi); return 5; } /* check if length is included: ETSI 4.08 vs 9.60 */ static int decode_gtp_qos(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 delay, reliability, peak, precedence, mean; proto_tree *ext_tree; proto_item *te; delay = (tvb_get_guint8(tvb, offset+1) >> 3) & 0x07; reliability = tvb_get_guint8(tvb, offset+1) & 0x07; peak = (tvb_get_guint8(tvb, offset+2) >> 4) & 0xF; precedence = tvb_get_guint8(tvb, offset+2) & 0x07; mean = tvb_get_guint8(tvb, offset+3) & 0x1F; te = proto_tree_add_text(tree, tvb, offset, 4, "QoS: delay: %u, reliability: %u, peak: %u, precedence: %u, mean: %u", delay, reliability, peak, precedence, mean); ext_tree = proto_item_add_subtree(te, ett_gtp_qos); proto_tree_add_text(ext_tree, tvb, offset+1, 1, val_to_str(delay, qos_delay_type, "Unknown")); proto_tree_add_text(ext_tree, tvb, offset+1, 1, val_to_str(reliability, qos_reliability_type, "Unknown")); proto_tree_add_text(ext_tree, tvb, offset+2, 1, val_to_str(peak, qos_peak_type, "Unknown")); proto_tree_add_text(ext_tree, tvb, offset+2, 1, val_to_str(precedence, qos_precedence_type, "Unknown")); proto_tree_add_text(ext_tree, tvb, offset+3, 1, val_to_str(mean, qos_mean_type, "Unknown")); proto_tree_add_uint_hidden(ext_tree, hf_gtp_ext_qos_delay, tvb, offset+1, 1, delay); proto_tree_add_uint_hidden(ext_tree, hf_gtp_ext_qos_reliability, tvb, offset+1, 1, reliability); proto_tree_add_uint_hidden(ext_tree, hf_gtp_ext_qos_peak, tvb, offset+2, 1, peak); proto_tree_add_uint_hidden(ext_tree, hf_gtp_ext_qos_precedence, tvb, offset+2, 1, precedence); proto_tree_add_uint_hidden(ext_tree, hf_gtp_ext_qos_mean, tvb, offset+3, 1, mean); return 4; } static int decode_gtp_reorder(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 reorder; reorder = tvb_get_guint8(tvb, offset+1) & 0x01; proto_tree_add_boolean_format(tree, hf_gtp_ext_reorder, tvb, offset, 2, reorder, "%s: %s", val_to_str(GTP_EXT_REORDER, gtp_ext_val, "Unknown message"), yesno[reorder]); return 2; } /* ETSI 4.08 v. 7.1.2, 10.5.3.1+ * 3G TS 29.060 v. 3.5.0, 7.7.7 * TODO - rand/sres/kc based search? */ static int decode_gtp_auth(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { proto_tree *ext_tree; proto_item *te; guint32 rand1, rand2, rand3, rand4, sres, kc1, kc2; rand1 = tvb_get_ntohl(tvb, offset+1); rand2 = tvb_get_ntohl(tvb, offset+5); rand3 = tvb_get_ntohl(tvb, offset+9); rand4 = tvb_get_ntohl(tvb, offset+13); sres = tvb_get_ntohl(tvb, offset+17); kc1 = tvb_get_ntohl(tvb, offset+21); kc2 = tvb_get_ntohl(tvb, offset+25); te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_AUTH, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(tree, ett_gtp_ext); proto_tree_add_text(ext_tree, tvb, offset+1, 16, "RAND: %x%x%x%x", rand1, rand2, rand3, rand4); proto_tree_add_text(ext_tree, tvb, offset+17, 4, "SRES: %x", sres); proto_tree_add_text(ext_tree, tvb, offset+21, 8, "Kc: %x%x", kc1, kc2); return 1+16+4+8; } static int decode_gtp_map(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 map; map = tvb_get_guint8(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_map, tvb, offset, 2, map, "%s: %u", val_to_str(GTP_EXT_MAP, gtp_ext_val, "Unknown message"), map); return 2; } static int decode_gtp_ptmsi_sig(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint32 ptmsi_sig; ptmsi_sig = tvb_get_ntoh24(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_ptmsi_sig, tvb, offset, 4, ptmsi_sig, "%s: %x", val_to_str(GTP_EXT_PTMSI_SIG, gtp_ext_val, "Unknown message"), ptmsi_sig); return 4; } static int decode_gtp_ms(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 ms; ms = tvb_get_guint8(tvb, offset+1) & 0x01; proto_tree_add_boolean_format(tree, hf_gtp_ext_ms, tvb, offset, 2, ms, "%s: %s", val_to_str(GTP_EXT_MS, gtp_ext_val, "Unknown message"), yesno[ms]); return 2; } static int decode_gtp_recover(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 recover; recover = tvb_get_guint8(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_recover, tvb, offset, 2, recover, "%s: %u", val_to_str(GTP_EXT_RECOVER, gtp_ext_val, "Unknown message"), recover); return 2; } static int decode_gtp_sel_mode(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 sel_mode; sel_mode = tvb_get_guint8(tvb, offset+1) & 0x03; proto_tree_add_uint_format(tree, hf_gtp_ext_sel_mode, tvb, offset, 2, sel_mode, "%s: %s", val_to_str(GTP_EXT_SEL_MODE, gtp_ext_val, "Unknown message"), val_to_str(sel_mode, sel_mode_type, "Unknown selection mode")); return 2; } static int decode_gtp_flow_label(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 flow_label; guint32 te_id_data; switch (gtp_version) { case 0: flow_label = tvb_get_ntohs(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_flow_label, tvb, offset, 3, flow_label, "%s: %u", val_to_str(GTP_EXT_FLOW_LABEL, gtp_ext_val, "Unknown message"), flow_label); return 3; case 1: te_id_data = tvb_get_ntohl(tvb, offset+1); /* proto_tree_add_uint_format(tree, hf_gtp_te_id_data, tvb, offset, 5, te_id_data, "%s: %u", val_to_str(GTP_EXT_FLOW_LABEL, gtp_ext_val, "Unknown message"), te_id_data); */ return 5; default: proto_tree_add_text(tree, tvb, offset, 1, "Flow label/Tunnel end point: GTP version not supported"); return 3; } } static int decode_gtp_flow_sig(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 flow_sig; guint32 te_id_sig; switch (gtp_version) { case 0: flow_sig = tvb_get_ntohs(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_flow_sig, tvb, offset, 3, flow_sig, "%s: %u", val_to_str(GTP_EXT_FLOW_SIG, gtp_ext_val, "Unknown message"), flow_sig); return 3; case 1: te_id_sig = tvb_get_ntohl(tvb, offset+1); /* proto_tree_add_uint(tvb, hf_3g_gtp_ext_te_id_sig, tvb, offset, 5, te_id_sig, "%s: %u", val_to_str(GTP_EXT_TE_ID_SIG, gtp_ext_val, "Unknown message"), te_id_sig); */ return 5; default: proto_tree_add_text(tree, tvb, offset, 0, "Flow sig/Tunnel end: GTP version not supported"); return 3; } } static int decode_gtp_flow_ii(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 flow_ii; guint32 te_id_ii; proto_tree *ext_tree; proto_item *te; te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_FLOW_II, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); proto_tree_add_uint(ext_tree, hf_gtp_ext_flow_ii_nsapi, tvb, offset+1, 1, tvb_get_guint8(tvb, offset+1) & 0x0F); switch (gtp_version) { case 0: flow_ii = tvb_get_ntohs(tvb, offset+2); proto_tree_add_uint(ext_tree, hf_gtp_ext_flow_ii, tvb, offset+2, 2, flow_ii); return 4; case 1: te_id_ii = tvb_get_ntohl(tvb, offset+2); /* proto_tree_add_uint(tree, hf_3g_gtp_ext_te_id_ii, tvb, offset+2, 4, te_id_ii); */ return 6; default: proto_tree_add_text(ext_tree, tvb, offset, 1, "Flow data II/Tunnel end data II: GTP Version not supported"); return 4; } } static int decode_gtp_tr_comm(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 command; command = tvb_get_guint8(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_tr_comm, tvb, offset, 2, command, "%s: %x", val_to_str(GTP_EXT_TR_COMM, gtp_ext_val, "Unknown message"), command); return 2; } static int decode_gtp_chrg_id(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint32 chrg_id; chrg_id = tvb_get_ntohl(tvb, offset+1); proto_tree_add_uint_format(tree, hf_gtp_ext_chrg_id, tvb, offset, 5, chrg_id, "%s: %x", val_to_str(GTP_EXT_CHRG_ID, gtp_ext_val, "Unknown message"), chrg_id); return 5; } static int decode_gtp_user_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length; guint8 pdp_type, pdp_org; guint32 addr_ipv4; struct e_in6_addr addr_ipv6; proto_tree *ext_tree; proto_item *te; length = tvb_get_ntohs(tvb, offset+1); pdp_org = tvb_get_guint8(tvb, offset+3) & 0x0F; pdp_type = tvb_get_guint8(tvb, offset+4); te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_USER_ADDR, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); proto_tree_add_uint(ext_tree, hf_gtp_ext_user_addr_pdp_org, tvb, offset+3, 1, pdp_org); proto_tree_add_uint(ext_tree, hf_gtp_ext_user_addr_pdp_type, tvb, offset+4, 1, pdp_type); if (length > 2) { switch (pdp_type) { case 0x00: break; case 0x01: break; case 0x02: break; case 0x21: addr_ipv4 = tvb_get_letohl(tvb, offset+5); proto_tree_add_ipv4(ext_tree, hf_gtp_ext_user_addr, tvb, offset+5, 4, addr_ipv4); break; case 0x57: tvb_memcpy(tvb, (guint8 *)&addr_ipv6, offset+5, sizeof addr_ipv6); proto_tree_add_ipv6(ext_tree, hf_gtp_ext_user_addr, tvb, offset+5, 16, (guint8 *)&addr_ipv6); break; default: ; /* nothing */ } } return 3+length; } static int decode_gtp_mm_cntx(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length, drx, net_cap, con_len; guint8 cksn, count, triplets[8], cipher, i, trans_id, proto_disc, message; gchar kc[9]; proto_tree *ext_tree; proto_item *te; te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_MM_CNTX, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); length = tvb_get_ntohs(tvb, offset+1); if (length < 1) return 3; cksn = tvb_get_guint8(tvb, offset+3) & 0x07; count = (tvb_get_guint8(tvb, offset+4) >> 3) & 0x07; cipher = tvb_get_guint8(tvb, offset+4) & 0x07; tvb_memcpy(tvb, kc, offset+5, 8); kc[8] = '\0'; for(i=0; i < count; i++) triplets[i] = tvb_get_guint8(tvb, offset+13+i); drx = tvb_get_ntohs(tvb, offset+13+count); net_cap = tvb_get_ntohs(tvb, offset+15+count); con_len = tvb_get_ntohs(tvb, offset+17+count); if (con_len > 0) { trans_id = (tvb_get_guint8(tvb, offset+18+count) >> 4) & 0x0F; proto_disc = tvb_get_guint8(tvb, offset+18+count) & 0x0F; message = tvb_get_guint8(tvb, offset+19+count); } proto_tree_add_text(ext_tree, tvb, offset+3, 1, "MM PDP CNTX - Ciphering Key Sequence Number: %u", cksn); proto_tree_add_text(ext_tree, tvb, offset+4, 1, "MM PDP CNTX - No of triplets: %u", count); proto_tree_add_text(ext_tree, tvb, offset+4, 1, "MM PDP CNTX - Ciphering: %u", cipher); proto_tree_add_text(ext_tree, tvb, offset+5, 8, "MM PDP CNTX - Kc: %s", kc); proto_tree_add_text(ext_tree, tvb, offset+13, 2, "MM PDP CNTX - DRX: %u", drx); proto_tree_add_text(ext_tree, tvb, offset+15, 2, "MM PDP CNTX - MS network capability: %u", net_cap); proto_tree_add_text(ext_tree, tvb, offset+17, 2, "MM PDP CNTX - Container length: %u", con_len); return 3+length; } static void decode_qos(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 qos[3], gchar* qos_str) { guint8 delay, reliability, peak, precedence, mean; delay = (qos[0] >> 3) & 0x07; reliability = qos[0] & 0x07; peak = (qos[1] >> 4) & 0xF; precedence = qos[1] & 0x07; mean = qos[2] & 0x1F; proto_tree_add_text(tree, tvb, offset, 3, "%s: delay: %u, reliability: %u, peak: %u, precedence: %u, mean: %u", qos_str, delay, reliability, peak, precedence, mean); } /* insert info about PDP type, decode X.25 addr - unify qos/apn/addr functions */ static int decode_gtp_pdp_cntx(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint8 ggsn_addr_len, apn_len, name_len, tmp, trans_id, vaa, order; guint16 length; guint32 addr_ipv4; guint8 apn[100]; pdp_t pdp; struct e_in6_addr addr_ipv6; proto_tree *ext_tree; proto_item *te; te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_PDP_CNTX, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); length = tvb_get_ntohs(tvb, offset+1); if (length < sizeof(pdp_t)) return 3+length; tvb_memcpy(tvb, (guint8 *)&pdp, offset+3, sizeof(pdp_t)); vaa = (pdp.nsapi >> 6) & 0x01; order = (pdp.nsapi >> 4) & 0x01; pdp.nsapi = pdp.nsapi & 0x0F; pdp.sapi = pdp.sapi & 0x0F; proto_tree_add_text(ext_tree, tvb, offset+3, 1, "VPLMN address allowed: %s", yesno[vaa]); proto_tree_add_text(ext_tree, tvb, offset+3, 1, "Reordering required: %s", yesno[order]); proto_tree_add_text(ext_tree, tvb, offset+3, 1, "NSAPI: %u", pdp.nsapi); proto_tree_add_text(ext_tree, tvb, offset+4, 1, "SAPI: %u", pdp.sapi); decode_qos(tvb, offset+5, ext_tree, pdp.qos_sub, "QoS subscribed"); decode_qos(tvb, offset+8, ext_tree, pdp.qos_req, "QoS requested"); decode_qos(tvb, offset+11, ext_tree, pdp.qos_neg, "QoS negotiated"); proto_tree_add_text(ext_tree, tvb, offset+14, 2, "Sequence number down: %u", pdp.sn_down); proto_tree_add_text(ext_tree, tvb, offset+16, 2, "Sequence number up: %u", pdp.sn_up); proto_tree_add_text(ext_tree, tvb, offset+18, 1, "Send N-PDU number: %u", pdp.pdu_send_no); proto_tree_add_text(ext_tree, tvb, offset+19, 1, "Receive N-PDU number: %u", pdp.pdu_rec_no); proto_tree_add_text(ext_tree, tvb, offset+20, 2, "Uplink flow label signalling: %u", pdp.up_flow); if (pdp.pdp_addr_len > 0) { switch (pdp.pdp_type) { case 0x00: break; case 0x01: break; case 0x02: break; case 0x21: addr_ipv4 = tvb_get_letohl(tvb, offset+25); proto_tree_add_ipv4(ext_tree, hf_gtp_ext_user_addr, tvb, offset+25, 4, addr_ipv4); break; case 0x57: tvb_memcpy(tvb, (guint8 *)&addr_ipv6, offset+25, sizeof addr_ipv6); proto_tree_add_ipv6(ext_tree, hf_gtp_ext_user_addr, tvb, offset+25, 16, (guint8 *)&addr_ipv6); break; default: ; /* nothing */ } } ggsn_addr_len = tvb_get_guint8(tvb, offset+25+pdp.pdp_addr_len); addr_ipv4 = tvb_get_letohl(tvb, offset+26+pdp.pdp_addr_len); proto_tree_add_ipv4(ext_tree, hf_gtp_ext_gsn_addr, tvb, offset+26+pdp.pdp_addr_len, 4, addr_ipv4); apn_len = tvb_get_guint8(tvb, offset+26+pdp.pdp_addr_len+ggsn_addr_len); tvb_memcpy(tvb, apn, offset+27+pdp.pdp_addr_len+ggsn_addr_len, apn_len); name_len = 0; for (;;) { if (name_len >= apn_len) break; tmp = name_len; name_len = name_len + apn[name_len] + 1; apn[tmp] = '.'; } apn[apn_len] = '\0'; proto_tree_add_string(ext_tree, hf_gtp_ext_apn, tvb, offset+27+pdp.pdp_addr_len+ggsn_addr_len, apn_len, apn); trans_id = tvb_get_guint8(tvb, offset+27+pdp.pdp_addr_len+ggsn_addr_len+apn_len); proto_tree_add_text(ext_tree, tvb, offset+27+pdp.pdp_addr_len+ggsn_addr_len+apn_len, 1, "Transaction identifier: %u", trans_id); return 3+length; } static int decode_gtp_apn(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length, name_len, tmp; guint8 apn[100]; length = tvb_get_ntohs(tvb, offset+1); if (length > 2) { name_len = tvb_get_guint8(tvb, offset+3); tvb_memcpy(tvb, apn, offset+4, length-1); for (;;) { if (name_len >= length-1) break; tmp = name_len; name_len = name_len + apn[tmp] + 1; apn[tmp] = '.'; } } apn[length-1] = '\0'; proto_tree_add_string_format(tree, hf_gtp_ext_apn, tvb, offset, length+3, apn, "%s: %s", val_to_str(GTP_EXT_APN, gtp_ext_val, "Unknown message"), apn); return 3+length; } /* ETSI 4.08 v. 7.1.2, 10.5.6.3 (p.580) * TODO - check if length is 8 or 16 bits * - proto_conf in 3G */ static int decode_gtp_proto_conf(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length, proto_id, raw_offset, proto_offset; guint8 conf, proto_len; tvbuff_t *next_tvb, *temp; guint8 *target; proto_tree *ext_tree; proto_item *te; packet_info save_pi; te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_PROTO_CONF, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); length = tvb_get_ntohs(tvb, offset+1); if (length < 4) return 3+length; conf = tvb_get_guint8(tvb, offset+3) & 0x07; proto_offset = 1; /* 1st byte is conf */ for (;;) { if (proto_offset >= length) break; proto_id = tvb_get_ntohs(tvb, offset+4); proto_len = tvb_get_guint8(tvb, offset+6); proto_offset += proto_len+3; if (proto_len > 0) { /* this part changes layout of GTP payload: * it removes "length field" from between protocol header and protocol payload */ raw_offset = tvb_raw_offset(tvb); target = g_malloc(tvb_length(tvb)+raw_offset); tvb_memcpy(tvb, target+offset+4+raw_offset, offset+6, 1); tvb_memcpy(tvb, target+offset+5+raw_offset, offset+4, 2); tvb_memcpy(tvb, target+offset+7+raw_offset, offset+7, proto_len); temp = tvb_new_real_data(target, tvb_length(tvb)+raw_offset, tvb_length(tvb)+raw_offset, "PPP payload"); tvb_set_free_cb(temp, free_tvb_data); tvb_set_child_real_data_tvbuff(tvb, temp); next_tvb = tvb_new_subset(temp, offset+5+raw_offset, proto_len+2, proto_len+2); /* Save the current value of "pi", and adjust certain fields to reflect the new top-level tvbuff. */ save_pi = pi; pi.compat_top_tvb = temp; pi.len = tvb_reported_length(temp); pi.captured_len = tvb_length(temp); call_dissector(ppp_handle, next_tvb, pinfo, ext_tree); pi = save_pi; } } return 3+length; } static void free_tvb_data(void *tvb_data) { g_free(tvb_data); } static int decode_gtp_gsn_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length, addr_len; guint32 gsn_addr; length = tvb_get_ntohs(tvb, offset+1); if (length < 1) return 3+length; gsn_addr = tvb_get_letohl(tvb, length > 4 ? offset+4 : offset+3); if (length > 4) addr_len = tvb_get_guint8(tvb, offset+3); else addr_len = 4; proto_tree_add_ipv4_format(tree, hf_gtp_ext_gsn_addr, tvb, offset, 3+length, gsn_addr, "%s: %s", val_to_str(GTP_EXT_GSN_ADDR, gtp_ext_val, "Unknown message"), ip_to_str(tvb_get_ptr(tvb, length > 4 ? offset+4 : offset+3, 4))); return 3+length; } static int decode_gtp_msisdn(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { const guint8 *msisdn_val; gchar *msisdn_str; guint16 length; length = tvb_get_ntohs(tvb, offset+1); if (length < 1) return 3+length; msisdn_val = tvb_get_ptr(tvb, offset+3, length); msisdn_str = msisdn_to_str(msisdn_val, length); proto_tree_add_string_format(tree, hf_gtp_ext_msisdn, tvb, offset, 3+length, msisdn_str, "%s: %s", val_to_str(GTP_EXT_MSISDN, gtp_ext_val, "Unknown message"), msisdn_str); return 3+length; } static int decode_gtp_chrg_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length, addr_len; guint32 chrg_addr; length = tvb_get_ntohs(tvb, offset+1); if (length < 1) return 3+length; chrg_addr = tvb_get_letohl(tvb, length > 4 ? offset+4 : offset+3); if (length > 4) addr_len = tvb_get_guint8(tvb, offset+3); else addr_len = 4; proto_tree_add_ipv4_format(tree, hf_gtp_ext_chrg_addr, tvb, offset, 3+length, chrg_addr, "%s: %s", val_to_str(GTP_EXT_CHRG_ADDR, gtp_ext_val, "Unknown message"), ip_to_str(tvb_get_ptr(tvb, length > 4 ? offset+4 : offset+3, 4))); return 3+length; } /* CDRs dissector */ static int decode_gtp_data_rec(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length, format_ver, data_len, i; guint8 no, format, rectype; proto_tree *ext_tree; proto_item *te; te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_DATA_REC, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); length = tvb_get_ntohs(tvb, offset + 1); no = tvb_get_guint8(tvb, offset + 3); format = tvb_get_guint8(tvb, offset + 4); format_ver = tvb_get_ntohs(tvb, offset + 5); proto_tree_add_text(ext_tree, tvb, offset+1, 2, "Length: %u", length); proto_tree_add_text(ext_tree, tvb, offset+3, 1, "Number of data records: %u", no); proto_tree_add_text(ext_tree, tvb, offset+4, 1, "Data record format: %u", format); proto_tree_add_text(ext_tree, tvb, offset+5, 2, "Data record format version: %u", format_ver); data_len = 0; offset = offset + 7; for (i = 0; i < no; i++) { data_len = tvb_get_ntohs(tvb, offset); rectype = tvb_get_guint8(tvb, offset+2); switch (rectype) { case 0x13: /* GCDR */ proto_tree_add_text(ext_tree, tvb, offset, data_len + 2, "GCDR"); break; case 0x12: /* SCDR */ proto_tree_add_text(ext_tree, tvb, offset, data_len + 2, "SCDR"); break; case 0x14: /* MCDR */ proto_tree_add_text(ext_tree, tvb, offset, data_len + 2, "MCDR"); break; case 0x15: /* SOCDR */ proto_tree_add_text(ext_tree, tvb, offset, data_len + 2, "SOCDR"); break; case 0x16: /* STCDR */ proto_tree_add_text(ext_tree, tvb, offset, data_len + 2, "STCDR"); } offset = offset + 2 + data_len; } return 3+length; } static int decode_gtp_node_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length; guint32 node_addr; length = tvb_get_ntohs(tvb, offset+1); if (length < 1) return 3+length; node_addr = tvb_get_letohl(tvb, offset+3); proto_tree_add_ipv4_format(tree, hf_gtp_ext_node_addr, tvb, offset, 3+length, node_addr, "%s: %s", val_to_str(GTP_EXT_NODE_ADDR, gtp_ext_val, "Unknown message"), ip_to_str(tvb_get_ptr(tvb, offset+3, 4))); return 3+length; } static int decode_gtp_priv_ext(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { guint16 length, ext_id; gchar ext_val[64]; proto_tree *ext_tree; proto_item *te; te = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(GTP_EXT_PRIV_EXT, gtp_ext_val, "Unknown message")); ext_tree = proto_item_add_subtree(te, ett_gtp_ext); length = tvb_get_ntohs(tvb, offset+1); if (length < 1) return 3+length; ext_id = tvb_get_ntohs(tvb, offset+3); tvb_memcpy(tvb, ext_val, offset+5, length > 65 ? 63 : length-2); ext_val[length > 65 ? 64 : length-1] = '\0'; proto_tree_add_uint(ext_tree, hf_gtp_ext_ext_id, tvb, offset+3, 2, ext_id); proto_tree_add_string(ext_tree, hf_gtp_ext_ext_val, tvb, offset+5, length-2, ext_val); return 3+length; } static int decode_gtp_unknown(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { return tvb_length_remaining(tvb, offset); } static void dissect_gtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti, *tf; proto_tree *gtp_tree, *flags_tree; guint8 ext_hdr_val; tvbuff_t *next_tvb; const guint8 *tid_val; gchar *tid_str; int offset, length, i; if (check_col(pinfo->fd, COL_PROTOCOL)) col_set_str(pinfo->fd, COL_PROTOCOL, "GTP"); if (check_col(pinfo->fd, COL_INFO)) col_clear(pinfo->fd, COL_INFO); tvb_memcpy(tvb, (guint8 *)>p, 0, 12); tid_val = tvb_get_ptr(tvb, 12, 8); tid_str = id_to_str(tid_val); gtp_version = (gtp.flags >> 5) & 0x07; if (!((gtp.flags >> 4) & 1)) { if (check_col(pinfo->fd, COL_PROTOCOL)) col_set_str(pinfo->fd, COL_PROTOCOL, "GTP-CDR"); if (check_col(pinfo->fd, COL_INFO)) col_add_fstr(pinfo->fd, COL_INFO, "%s - tid: %s", val_to_str(gtp.message, message_type, "Unknown"), tid_str); } else { switch ((gtp.flags >> 5) & 0x07) { case 0: if (check_col(pinfo->fd, COL_PROTOCOL)) col_set_str(pinfo->fd, COL_PROTOCOL, "GTP"); if (check_col(pinfo->fd, COL_INFO)) col_add_fstr(pinfo->fd, COL_INFO, "%s - tid: %s", val_to_str(gtp.message, message_type, "Unknown"), tid_str); break; case 1: if (check_col(pinfo->fd, COL_PROTOCOL)) col_set_str(pinfo->fd, COL_PROTOCOL, "GTP3"); if (check_col(pinfo->fd, COL_INFO)) col_add_fstr(pinfo->fd, COL_INFO, "(version not supported yet) %s", val_to_str(gtp.message, message_type, "Unknown")); break; } } if (tree) { /* dissect GTP header */ ti = proto_tree_add_item(tree, proto_gtp, tvb, 0, tvb_length(tvb), FALSE); gtp_tree = proto_item_add_subtree(ti, ett_gtp); tf = proto_tree_add_uint(gtp_tree, hf_gtp_flags, tvb, 0, 1, gtp.flags); flags_tree = proto_item_add_subtree(tf, ett_gtp_flags); proto_tree_add_uint(flags_tree, hf_gtp_flags_ver, tvb, 0, 1, gtp.flags); proto_tree_add_uint(flags_tree, hf_gtp_flags_pt, tvb, 0, 1, gtp.flags); proto_tree_add_uint(flags_tree, hf_gtp_flags_spare, tvb, 0, 1, gtp.flags); proto_tree_add_uint(flags_tree, hf_gtp_flags_snn, tvb, 0, 1, gtp.flags); gtp.length = ntohs(gtp.length); gtp.seq_no = ntohs(gtp.seq_no); proto_tree_add_uint(gtp_tree, hf_gtp_message_type, tvb, 1, 1, gtp.message); proto_tree_add_uint(gtp_tree, hf_gtp_length, tvb, 2, 2, gtp.length); proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, 4, 2, gtp.seq_no); proto_tree_add_uint(gtp_tree, hf_gtp_flow_label, tvb, 6, 2, gtp.flow_label); proto_tree_add_uint(gtp_tree, hf_gtp_sndcp_number, tvb, 8, 1, gtp.npdu_no); proto_tree_add_string(gtp_tree, hf_gtp_tid, tvb, 12, 8, tid_str); if (gtp.message != GTP_MSG_TPDU) { offset = GTP_HDR_LENGTH; length = tvb_length(tvb); for (;;) { if (offset >= length) break; ext_hdr_val = tvb_get_guint8(tvb, offset); i = -1; while (gtpopt[++i].optcode) if (gtpopt[i].optcode == ext_hdr_val) break; offset = offset + (*gtpopt[i].decode)(tvb, offset, pinfo, gtp_tree); } } } if (gtp.message == GTP_MSG_TPDU) { next_tvb = tvb_new_subset(tvb, 20, -1, -1); call_dissector(ip_handle, next_tvb, pinfo, tree); if (check_col(pinfo->fd, COL_PROTOCOL)) col_append_str_gtp(pinfo->fd, COL_PROTOCOL); } } /* static void dissect_gtp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti, *tf; proto_tree *gtp_tree, *flags_tree; guint8 int_val8, message_type_val, ext_hdr_val, i, gtp_version; guint16 int_val16; tvbuff_t *next_tvb; int offset, length; int (*decode)(tvbuff_t *, int, packet_info *, proto_tree *); if (check_col(pinfo->fd, COL_PROTOCOL)) col_set_str(pinfo->fd, COL_PROTOCOL, "GTP3"); if (check_col(pinfo->fd, COL_INFO)) col_clear(pinfo->fd, COL_INFO); tvb_memcpy(tvb, gtp3_hdr, 0, sizeof(gtp3_hdr)); if (check_col(pinfo->fd, COL_INFO)) col_add_str(pinfo->fd, COL_INFO, val_to_str(gtp3_hdr.message, message_type, "Unknown")); if (tree) { ti = proto_tree_add_item(tree, proto_gtp, tvb, 0, tvb_length(tvb), FALSE); gtp_tree = proto_item_add_subtree(ti, ett_gtp); int_val8 = tvb_get_guint8(tvb, 0); tf = proto_tree_add_uint(gtp_tree, hf_gtp_flags, tvb, 0, 1, int_val8); flags_tree = proto_item_add_subtree(tf, ett_gtp_flags); proto_tree_add_uint(flags_tree, hf_gtp_flags_ver, tvb, 0, 1, int_val8); proto_tree_add_uint(flags_tree, hf_gtp_flags_pt, tvb, 0, 1, int_val8); proto_tree_add_uint(flags_tree, hf_gtp_flags_spare, tvb, 0, 1, int_val8); proto_tree_add_uint(flags_tree, hf_gtp_flags_snn, tvb, 0, 1, int_val8); proto_tree_add_uint(gtp_tree, hf_gtp_message_type, tvb, 1, 1, message_type_val); int_val16 = tvb_get_ntohs(tvb, 2); proto_tree_add_uint(gtp_tree, hf_gtp_length, tvb, 2, 2, int_val16); int_val16 = tvb_get_ntohs(tvb, 4); proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, 4, 2, int_val16); int_val16 = tvb_get_ntohs(tvb, 6); proto_tree_add_uint(gtp_tree, hf_gtp_flow_label, tvb, 6, 2, int_val16); int_val8 = tvb_get_guint8(tvb, 8); proto_tree_add_uint(gtp_tree, hf_gtp_sndcp_number, tvb, 8, 1, int_val8); proto_tree_add_string(gtp_tree, hf_gtp_tid, tvb, 12, 8, tid_str); if (message_type_val != GTP_MSG_TPDU) { offset = GTP_HDR_LENGTH; length = tvb_length(tvb); if (length > GTP_HDR_LENGTH) { int_val16 = 0; for (;;) { offset = offset + int_val16; if (offset >= length) break; ext_hdr_val = tvb_get_guint8(tvb, offset); for (i = 0; i < 26; i++) if (gtpopt[i].optcode == ext_hdr_val) break; if (i < 26) { decode = gtpopt[i].decode; int_val16 = (*decode)(tvb, offset, pinfo, gtp_tree); } else int_val16 = decode_gtp_unknown(tvb, offset, pinfo, gtp_tree); } } } } int_val8 = tvb_get_guint8(tvb, 1); if (int_val8 == 0xff) { next_tvb = tvb_new_subset(tvb, 20, -1, -1); call_dissector(ip_handle, next_tvb, pinfo, tree); if (check_col(pinfo->fd, COL_PROTOCOL)) col_append_str_gtp(pinfo->fd, COL_PROTOCOL); } } */ void proto_register_gtp(void) { static hf_register_info hf[] = { { &hf_gtp_flags, { "Flags", "gtp.flags", FT_UINT8, BASE_HEX, NULL, 0, "Ver/PT/Res/E/S/PN", HFILL }}, { &hf_gtp_flags_ver, { "Version", "gtp.flags.version", FT_UINT8, BASE_DEC, VALS(ver_types), GTP_VER_MASK, "GTP version", HFILL }}, { &hf_gtp_flags_pt, { "Payload Type", "gtp.flags.payload_type", FT_UINT8, BASE_DEC, NULL, GTP_PT_MASK, "Payload types", HFILL }}, { &hf_gtp_flags_spare, { "Reserved", "gtp.flags.spare", FT_UINT8, BASE_DEC, NULL, GTP_SPARE_MASK, "Reserved", HFILL }}, { &hf_gtp_flags_snn, { "Is seq number", "gtp.flags.snn", FT_UINT8, BASE_DEC, NULL, GTP_SNN_MASK, "Is sequence number present", HFILL }}, { &hf_gtp_message_type, { "Message type", "gtp.message_type", FT_UINT8, BASE_HEX, VALS(message_type), 0x0, "GTP message type", HFILL }}, { &hf_gtp_length, { "Length", "gtp.length", FT_UINT16, BASE_DEC, NULL, 0, "Length", HFILL }}, { &hf_gtp_seq_number, { "Sequence number", "gtp.seq_number", FT_UINT16, BASE_HEX, NULL, 0, "Sequence number", HFILL }}, { &hf_gtp_flow_label, { "Flow label", "gtp.flow_label", FT_UINT16, BASE_HEX, NULL, 0, "Flow label", HFILL }}, { &hf_gtp_sndcp_number, { "SNDCP N-PDU LLC Number", "gtp.sndcp_number", FT_UINT8, BASE_HEX, NULL, 0, "SNDCP N-PDU LLC Number", HFILL }}, { &hf_gtp_tid, { "Tunnel ID", "gtp.tid", FT_STRING, BASE_DEC, NULL, 0, "Tunnel ID", HFILL }}, { &hf_gtp_ext, { "Extension header", "gtp.ext", FT_UINT8, BASE_HEX, NULL, 0, "Extension header", HFILL }}, { &hf_gtp_ext_cause, { "Cause", "gtp.ext.cause", FT_UINT8, BASE_DEC, VALS(cause_type), 0, "Cause of operation", HFILL }}, { &hf_gtp_ext_imsi, { "IMSI", "gtp.ext.imsi", FT_STRING, BASE_DEC, NULL, 0, "IMSI number", HFILL }}, { &hf_gtp_ext_rai_mcc, { "MCC", "gtp.ext.mcc", FT_UINT16, BASE_DEC, NULL, 0, "Mobile Country Code", HFILL }}, { &hf_gtp_ext_rai_mnc, { "MNC", "gtp.ext.mnc", FT_UINT8, BASE_DEC, NULL, 0, "Mobile National Code", HFILL }}, { &hf_gtp_ext_rai_rac, { "RAC", "gtp.ext.rac", FT_UINT8, BASE_DEC, NULL, 0, "Routing Area", HFILL }}, { &hf_gtp_ext_rai_lac, { "LAC", "gtp.ext.lac", FT_UINT16, BASE_DEC, NULL, 0, "Location Area", HFILL }}, { &hf_gtp_ext_tlli, { "TLLI", "gtp.ext.tlli", FT_UINT32, BASE_HEX, NULL, 0, "Temporary Logical Link Identity", HFILL }}, { &hf_gtp_ext_ptmsi, { "P-TMSI", "gtp.ext.ptmsi", FT_UINT32, BASE_HEX, NULL, 0, "Packet TMSI", HFILL }}, { &hf_gtp_ext_qos_delay, { "QoS delay", "gtp.ext.qos_delay", FT_UINT8, BASE_DEC, VALS(qos_delay_type), 0, "QoS delay class", HFILL }}, { &hf_gtp_ext_qos_reliability, { "QoS reliability","gtp.ext.qos_reliabilty", FT_UINT8, BASE_DEC, VALS(qos_reliability_type), 0, "QoS reliability class", HFILL }}, { &hf_gtp_ext_qos_peak, { "QoS peak", "gtp.ext.qos_peak", FT_UINT8, BASE_DEC, VALS(qos_peak_type), 0, "QoS peak throughput", HFILL }}, { &hf_gtp_ext_qos_precedence, { "QoS precedence", "gtp.ext.qos_precedence", FT_UINT8, BASE_DEC, VALS(qos_precedence_type), 0, "QoS precedence class", HFILL }}, { &hf_gtp_ext_qos_mean, { "QoS mean", "gtp.ext.qos_mean", FT_UINT8, BASE_DEC, VALS(qos_mean_type), 0, "QoS mean throughput", HFILL }}, { &hf_gtp_ext_reorder, { "Reordering required", "gtp.ext.reorder", FT_BOOLEAN, BASE_NONE, NULL, 0, "Reordering required", HFILL }}, /* { &hf_gtp_ext_auth_rand, { "Authentication RAND", "gtp.ext.auth_rand", FT_STRING, BASE_DEC, NULL, 0, "Authentication RAND", HFILL }}, { &hf_gtp_ext_auth_sres, { "Authentication SRES", "gtp.ext.auth_sres", FT_STRING, BASE_DEC, NULL, 0, "Authentication SRES", HFILL }}, { &hf_gtp_ext_auth_kc, { "Authentication Kc", "gtp.ext.auth_kc", FT_STRING, BASE_DEC, NULL, 0, "Authentication Kc", HFILL }}, */ { &hf_gtp_ext_map, { "Ext type", "gtp.ext.map", FT_UINT8, BASE_DEC, VALS(map_cause_type), 0, "MAP cause", HFILL }}, { &hf_gtp_ext_ptmsi_sig, { "P-TMSI signature", "gtp.ext.ptmsi_sig", FT_UINT24, BASE_HEX, NULL, 0, "P-TMSI signature", HFILL }}, { &hf_gtp_ext_ms, { "MS validated", "gtp.ext.ms", FT_BOOLEAN, BASE_NONE, NULL, 0, "MS validated", HFILL }}, { &hf_gtp_ext_recover, { "Restart counter", "gtp.ext.recover", FT_UINT8, BASE_DEC, NULL, 0, "Restart counter", HFILL }}, { &hf_gtp_ext_sel_mode, { "Selection mode", "gtp.ext.sel_mode", FT_UINT8, BASE_DEC, VALS(sel_mode_type), 0, "Selection mode", HFILL }}, { &hf_gtp_ext_flow_label, { "Flow label", "gtp.ext.flow_label", FT_UINT16, BASE_DEC, NULL, 0, "Flow label", HFILL }}, { &hf_gtp_ext_flow_sig, { "Flow label signature", "gtp.ext.flow_sig", FT_UINT16, BASE_DEC, NULL, 0, "Flow label signature", HFILL }}, { &hf_gtp_ext_flow_ii_nsapi,{ "NSAPI", "gtp.ext.flow_ii_nsapi", FT_UINT8, BASE_HEX, NULL, 0, "NSAPI", HFILL }}, { &hf_gtp_ext_flow_ii, { "Downlink flow label data", "gtp.ext.flow_ii", FT_UINT16, BASE_DEC, NULL, 0, "Downlink flow label data", HFILL }}, { &hf_gtp_ext_tr_comm, { "Transfer command", "gtp.ext.tr_comm", FT_UINT8, BASE_DEC, VALS(tr_comm_type), 0, "Packet transfer command", HFILL }}, { &hf_gtp_ext_chrg_id, { "Charging ID", "gtp.ext.chrg_id", FT_UINT32, BASE_HEX, NULL, 0, "Charging ID", HFILL }}, { &hf_gtp_ext_user_addr, { "End user address", "gtp.ext.user_addr", FT_IPv4, BASE_DEC, NULL, 0, "End user address", HFILL }}, { &hf_gtp_ext_user_addr_pdp_type, { "PDP type", "gtp.ext.user_addr_pdp_type", FT_UINT8, BASE_HEX, VALS(pdp_type), 0, "PDP type", HFILL }}, { &hf_gtp_ext_user_addr_pdp_org, { "PDP type organization", "gtp.ext.user_addr_pdp_org", FT_UINT8, BASE_DEC, NULL, 0, "PDP type organization", HFILL }}, { &hf_gtp_ext_apn, { "APN", "gtp.ext.apn", FT_STRING, BASE_DEC, NULL, 0, "Access Point Name", HFILL }}, { &hf_gtp_ext_proto_conf, { "Protocol configuration", "gtp.ext.proto_conf", FT_STRING, BASE_DEC, NULL, 0, "Protocol configuration", HFILL }}, { &hf_gtp_ext_gsn_addr, { "GSN address", "gtp.ext.gsn_addr", FT_IPv4, BASE_DEC, NULL, 0, "GSN address", HFILL }}, { &hf_gtp_ext_msisdn, { "MSISDN", "gtp.ext.msisdn", FT_STRING, BASE_DEC, NULL, 0, "MSISDN", HFILL }}, { &hf_gtp_ext_chrg_addr, { "CG address", "gtp.ext.chrg_addr", FT_IPv4, BASE_DEC, NULL, 0, "Charging gateway address", HFILL }}, { &hf_gtp_ext_node_addr, { "Node address", "gtp.ext.node_addr", FT_IPv4, BASE_DEC, NULL, 0, "Recommended node address", HFILL }}, { &hf_gtp_ext_ext_id, { "Ext id", "gtp.ext.ext_id", FT_UINT16, BASE_DEC, NULL, 0, "Extension id", HFILL }}, { &hf_gtp_ext_ext_val, { "Ext val", "gtp.ext.ext_val", FT_STRING, BASE_DEC, NULL, 0, "Extension value", HFILL }}, { &hf_gtp_ext_unknown, { "Unknown data (length)", "gtp.ext.unknown", FT_UINT16, BASE_DEC, NULL, 0, "Unknown data", HFILL }}, }; static gint *ett[] = { &ett_gtp, &ett_gtp_flags, &ett_gtp_ext, &ett_gtp_qos, }; proto_gtp = proto_register_protocol("GPRS Tunneling Protocol", "GTP", "gtp"); proto_register_field_array(proto_gtp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } void proto_reg_handoff_gtp(void) { dissector_add("udp.port", UDP_PORT_GTP, dissect_gtp, proto_gtp); dissector_add("tcp.port", TCP_PORT_GTP, dissect_gtp, proto_gtp); /* dissector_add("udp.port", UDP_PORT_GTP3C, dissect_gtp3, proto_gtp3); dissector_add("udp.port", UDP_PORT_GTP3U, dissect_gtp3, proto_gtp3); dissector_add("tcp.port", TCP_PORT_GTP3C, dissect_gtp3, proto_gtp3); dissector_add("tcp.port", TCP_PORT_GTP3U, dissect_gtp3, proto_gtp3); */ ip_handle = find_dissector("ip"); ppp_handle = find_dissector("ppp"); }