xref: /openbsd-src/usr.sbin/tcpdump/print-gtp.c (revision 9d41c16906b279ed9301276a66fe6b416bc36526)
1*9d41c169Sjca /*	$OpenBSD: print-gtp.c,v 1.13 2020/10/26 23:19:18 jca Exp $ */
21568fe7eSjsing /*
356e8ec8dSjsing  * Copyright (c) 2009, 2010 Joel Sing <jsing@openbsd.org>
41568fe7eSjsing  *
51568fe7eSjsing  * Permission to use, copy, modify, and distribute this software for any
61568fe7eSjsing  * purpose with or without fee is hereby granted, provided that the above
71568fe7eSjsing  * copyright notice and this permission notice appear in all copies.
81568fe7eSjsing  *
91568fe7eSjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101568fe7eSjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111568fe7eSjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121568fe7eSjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131568fe7eSjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141568fe7eSjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151568fe7eSjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161568fe7eSjsing  */
171568fe7eSjsing 
181568fe7eSjsing /*
191568fe7eSjsing  * Decoder for the GPRS Trunking Protocol (GTP).
201568fe7eSjsing  *
211568fe7eSjsing  * This work has been kindly sponsored by SystemNet (www.systemnet.no).
221568fe7eSjsing  *
231568fe7eSjsing  * GTPv0 standards are available from the ETSI website:
241568fe7eSjsing  *
251568fe7eSjsing  *     http://pda.etsi.org/pda/
261568fe7eSjsing  *
271568fe7eSjsing  * GTPv1 standards are available from the 3GPP website:
281568fe7eSjsing  *
291568fe7eSjsing  *     http://www.3gpp.org/specifications
301568fe7eSjsing  *
311568fe7eSjsing  * The following standards have been referenced to create this decoder:
321568fe7eSjsing  *
331568fe7eSjsing  *     ETSI GSM 09.60 - GPRS Tunnelling Protocol (GTPv0)
341568fe7eSjsing  *     ETSI GSM 12.15 - GPRS Charging (GTPv0')
351568fe7eSjsing  *
361568fe7eSjsing  *     3GPP TS 23.003 - Numbering, addressing and identification
3756e8ec8dSjsing  *     3GPP TS 24.008 - Core network protocols
381568fe7eSjsing  *     3GPP TS 29.002 - Mobile Application Part (MAP) specification
391568fe7eSjsing  *     3GPP TS 29.060 - GPRS Tunnelling Protocol (GTPv1-C/GTPv1-U)
401568fe7eSjsing  *     3GPP TS 32.295 - Charging Data Record (CDR) transfer (GTPv1')
411568fe7eSjsing  */
421568fe7eSjsing 
431568fe7eSjsing #include <sys/time.h>
441568fe7eSjsing #include <sys/socket.h>
451568fe7eSjsing #include <sys/types.h>
461568fe7eSjsing 
471568fe7eSjsing #include <netinet/in.h>
481568fe7eSjsing #include <netinet/ip.h>
491568fe7eSjsing #include <netinet/ip_var.h>
501568fe7eSjsing 
511568fe7eSjsing #include <ctype.h>
521568fe7eSjsing #include <stdio.h>
531568fe7eSjsing #include <stdlib.h>
541568fe7eSjsing #include <string.h>
551568fe7eSjsing 
561568fe7eSjsing #include "addrtoname.h"
571568fe7eSjsing #include "interface.h"
581568fe7eSjsing #include "gtp.h"
591568fe7eSjsing 
601afdc05aSdlg #ifndef nitems
611afdc05aSdlg #define nitems(_a)  (sizeof((_a)) / sizeof((_a)[0]))
621afdc05aSdlg #endif
631afdc05aSdlg 
646ad041cbSmmcc void	gtp_print(const u_char *, u_int, u_short, u_short);
656ad041cbSmmcc void	gtp_decode_ie(const u_char *, u_short, int);
666ad041cbSmmcc void	gtp_print_tbcd(const u_char *, u_int);
676ad041cbSmmcc void	gtp_print_user_address(const u_char *, u_int);
686ad041cbSmmcc void	gtp_print_apn(const u_char *, u_int);
691afdc05aSdlg void	gtp_print_str(const char **, u_int, u_int);
701568fe7eSjsing 
711568fe7eSjsing void	gtp_v0_print(const u_char *, u_int, u_short, u_short);
726ad041cbSmmcc void	gtp_v0_print_prime(const u_char *);
736ad041cbSmmcc int	gtp_v0_print_tv(const u_char *, u_int);
746ad041cbSmmcc int	gtp_v0_print_tlv(const u_char *, u_int);
751568fe7eSjsing 
761568fe7eSjsing void	gtp_v1_print(const u_char *, u_int, u_short, u_short);
776ad041cbSmmcc void	gtp_v1_print_ctrl(const u_char *, u_int, struct gtp_v1_hdr *);
786ad041cbSmmcc void	gtp_v1_print_user(const u_char *, u_int, struct gtp_v1_hdr *);
796ad041cbSmmcc void	gtp_v1_print_prime(const u_char *, struct gtp_v1_prime_hdr *);
806ad041cbSmmcc int	gtp_v1_print_tv(const u_char *, u_int);
816ad041cbSmmcc int	gtp_v1_print_tlv(const u_char *, u_int);
821568fe7eSjsing 
831568fe7eSjsing /* GTPv0 message types. */
841568fe7eSjsing static struct tok gtp_v0_msgtype[] = {
851568fe7eSjsing 
861568fe7eSjsing 	{ 1,	"Echo Request" },
871568fe7eSjsing 	{ 2,	"Echo Response" },
881568fe7eSjsing 	{ 3,	"Version Not Supported" },
891568fe7eSjsing 	{ 4,	"Node Alive Request" },
901568fe7eSjsing 	{ 5,	"Node Alive Response" },
911568fe7eSjsing 	{ 6,	"Redirection Request" },
921568fe7eSjsing 	{ 7,	"Redirection Response" },
931568fe7eSjsing 	{ 16,	"Create PDP Context Request" },
941568fe7eSjsing 	{ 17,	"Create PDP Context Response" },
951568fe7eSjsing 	{ 18,	"Update PDP Context Request" },
961568fe7eSjsing 	{ 19,	"Update PDP Context Response" },
971568fe7eSjsing 	{ 20,	"Delete PDP Context Request" },
981568fe7eSjsing 	{ 21,	"Delete PDP Context Response" },
991568fe7eSjsing 	{ 22,	"Create AA PDP Context Request" },
1001568fe7eSjsing 	{ 23,	"Create AA PDP Context Response" },
1011568fe7eSjsing 	{ 24,	"Delete AA PDP Context Request" },
1021568fe7eSjsing 	{ 25,	"Delete AA PDP Context Response" },
1031568fe7eSjsing 	{ 26,	"Error Indication" },
1041568fe7eSjsing 	{ 27,	"PDU Notification Request" },
1051568fe7eSjsing 	{ 28,	"PDU Notification Response" },
1061568fe7eSjsing 	{ 29,	"PDU Notification Reject Request" },
1071568fe7eSjsing 	{ 30,	"PDU Notification Reject Response" },
1081568fe7eSjsing 	{ 32,	"Send Routeing Information Request" },
1091568fe7eSjsing 	{ 33,	"Send Routeing Information Response" },
1101568fe7eSjsing 	{ 34,	"Failure Report Request" },
1111568fe7eSjsing 	{ 35,	"Failure Report Response" },
1121568fe7eSjsing 	{ 36,	"MS GPRS Present Request" },
1131568fe7eSjsing 	{ 37,	"MS GPRS Present Response" },
1141568fe7eSjsing 	{ 48,	"Identification Request" },
1151568fe7eSjsing 	{ 49,	"Identification Response" },
1161568fe7eSjsing 	{ 50,	"SGSN Context Request" },
1171568fe7eSjsing 	{ 51,	"SGSN Context Response" },
1181568fe7eSjsing 	{ 52,	"SGSN Context Acknowledge" },
1191568fe7eSjsing 	{ 240,	"Data Record Transfer Request" },
1201568fe7eSjsing 	{ 241,	"Data Record Transfer Response" },
1211568fe7eSjsing 	{ 255,	"T-PDU" },
1221568fe7eSjsing 
1231568fe7eSjsing 	{ 0,	NULL }
1241568fe7eSjsing };
1251568fe7eSjsing 
1261568fe7eSjsing /* GTPv0 causes. */
1271568fe7eSjsing static struct tok gtp_v0_cause[] = {
1281568fe7eSjsing 
1291568fe7eSjsing 	{ 0,	"Request IMSI" },
1301568fe7eSjsing 	{ 1,	"Request IMEI" },
1311568fe7eSjsing 	{ 2,	"Request IMSI and IMEI" },
1321568fe7eSjsing 	{ 3,	"No identity needed" },
1331568fe7eSjsing 	{ 4,	"MS refuses" },
1341568fe7eSjsing 	{ 5,	"MS is not GPRS responding" },
1351568fe7eSjsing 	{ 128,	"Request accepted" },
1361568fe7eSjsing 	{ 192,	"Non-existent" },
1371568fe7eSjsing 	{ 193,	"Invalid message format" },
1381568fe7eSjsing 	{ 194,	"IMSI not known" },
1391568fe7eSjsing 	{ 195,	"MS is GPRS detached" },
1401568fe7eSjsing 	{ 196,	"MS is not GPRS responding" },
1411568fe7eSjsing 	{ 197,	"MS refuses" },
1421568fe7eSjsing 	{ 198,	"Version not supported" },
1431568fe7eSjsing 	{ 199,	"No resources available" },
1441568fe7eSjsing 	{ 200,	"Service not supported" },
1451568fe7eSjsing 	{ 201,	"Mandatory IE incorrect" },
1461568fe7eSjsing 	{ 202,	"Mandatory IE missing" },
1471568fe7eSjsing 	{ 203,	"Optional IE incorrect" },
1481568fe7eSjsing 	{ 204,	"System failure" },
1491568fe7eSjsing 	{ 205,	"Roaming restriction" },
1501568fe7eSjsing 	{ 206,	"P-TMSI signature mismatch" },
1511568fe7eSjsing 	{ 207,	"GPRS connection suspended" },
1521568fe7eSjsing 	{ 208,	"Authentication failure" },
1531568fe7eSjsing 	{ 209,	"User authentication failed" },
1541568fe7eSjsing 
1551568fe7eSjsing 	{ 0,	NULL }
1561568fe7eSjsing };
1571568fe7eSjsing 
1581568fe7eSjsing /* GTPv1 message types. */
1591568fe7eSjsing static struct tok gtp_v1_msgtype[] = {
1601568fe7eSjsing 
1611568fe7eSjsing 	{ 1,	"Echo Request" },
1621568fe7eSjsing 	{ 2,	"Echo Response" },
1631568fe7eSjsing 	{ 3,	"Version Not Supported" },
1641568fe7eSjsing 	{ 4,	"Node Alive Request" },
1651568fe7eSjsing 	{ 5,	"Node Alive Response" },
1661568fe7eSjsing 	{ 6,	"Redirection Request" },
1671568fe7eSjsing 	{ 7,	"Redirection Response" },
1681568fe7eSjsing 	{ 16,	"Create PDP Context Request" },
1691568fe7eSjsing 	{ 17,	"Create PDP Context Response" },
1701568fe7eSjsing 	{ 18,	"Update PDP Context Request" },
1711568fe7eSjsing 	{ 19,	"Update PDP Context Response" },
1721568fe7eSjsing 	{ 20,	"Delete PDP Context Request" },
1731568fe7eSjsing 	{ 21,	"Delete PDP Context Response" },
1741568fe7eSjsing 	{ 22,	"Initiate PDP Context Activiation Request" },
1751568fe7eSjsing 	{ 23,	"Initiate PDP Context Activiation Response" },
1761568fe7eSjsing 	{ 26,	"Error Indication" },
1771568fe7eSjsing 	{ 27,	"PDU Notification Request" },
1781568fe7eSjsing 	{ 28,	"PDU Notification Response" },
1791568fe7eSjsing 	{ 29,	"PDU Notification Reject Request" },
1801568fe7eSjsing 	{ 30,	"PDU Notification Reject Response" },
1811568fe7eSjsing 	{ 31,	"Supported Extension Headers Notification" },
1821568fe7eSjsing 	{ 32,	"Send Routeing Information for GPRS Request" },
1831568fe7eSjsing 	{ 33,	"Send Routeing Information for GPRS Response" },
1841568fe7eSjsing 	{ 34,	"Failure Report Request" },
1851568fe7eSjsing 	{ 35,	"Failure Report Response" },
1861568fe7eSjsing 	{ 36,	"Note MS GPRS Present Request" },
1871568fe7eSjsing 	{ 37,	"Note MS GPRS Present Response" },
1881568fe7eSjsing 	{ 48,	"Identification Request" },
1891568fe7eSjsing 	{ 49,	"Identification Response" },
1901568fe7eSjsing 	{ 50,	"SGSN Context Request" },
1911568fe7eSjsing 	{ 51,	"SGSN Context Response" },
1921568fe7eSjsing 	{ 52,	"SGSN Context Acknowledge" },
1931568fe7eSjsing 	{ 53,	"Forward Relocation Request" },
1941568fe7eSjsing 	{ 54,	"Forward Relocation Response" },
1951568fe7eSjsing 	{ 55,	"Forward Relocation Complete" },
1961568fe7eSjsing 	{ 56,	"Relocation Cancel Request" },
1971568fe7eSjsing 	{ 57,	"Relocation Cancel Response" },
1981568fe7eSjsing 	{ 58,	"Forward SRNS Context" },
1991568fe7eSjsing 	{ 59,	"Forward Relocation Complete Acknowledge" },
2001568fe7eSjsing 	{ 60,	"Forward SRNS Context Acknowledge" },
2011568fe7eSjsing 	{ 70,	"RAN Information Relay" },
2021568fe7eSjsing 	{ 96,	"MBMS Notification Request" },
2031568fe7eSjsing 	{ 97,	"MBMS Notification Response" },
2041568fe7eSjsing 	{ 98,	"MBMS Notification Reject Request" },
2051568fe7eSjsing 	{ 99,	"MBMS Notification Reject Response" },
2061568fe7eSjsing 	{ 100,	"Create MBMS Context Request" },
2071568fe7eSjsing 	{ 101,	"Create MBMS Context Response" },
2081568fe7eSjsing 	{ 102,	"Update MBMS Context Request" },
2091568fe7eSjsing 	{ 103,	"Update MBMS Context Response" },
2101568fe7eSjsing 	{ 104,	"Delete MBMS Context Request" },
2111568fe7eSjsing 	{ 105,	"Delete MBMS Context Response" },
2121568fe7eSjsing 	{ 112,	"MBMS Registration Request" },
2131568fe7eSjsing 	{ 113,	"MBMS Registration Response" },
2141568fe7eSjsing 	{ 114,	"MBMS De-Registration Request" },
2151568fe7eSjsing 	{ 115,	"MBMS De-Registration Response" },
2161568fe7eSjsing 	{ 116,	"MBMS Session Start Request" },
2171568fe7eSjsing 	{ 117,	"MBMS Session Start Response" },
2181568fe7eSjsing 	{ 118,	"MBMS Session Stop Request" },
2191568fe7eSjsing 	{ 119,	"MBMS Session Stop Response" },
2201568fe7eSjsing 	{ 120,	"MBMS Session Update Request" },
2211568fe7eSjsing 	{ 121,	"MBMS Session Update Response" },
2221568fe7eSjsing 	{ 128,	"MBMS Info Change Notification Request" },
2231568fe7eSjsing 	{ 129,	"MBMS Info Change Notification Response" },
2241568fe7eSjsing 	{ 240,	"Data Record Transfer Request" },
2251568fe7eSjsing 	{ 241,	"Data Record Transfer Response" },
2261568fe7eSjsing 	{ 255,	"G-PDU" },
2271568fe7eSjsing 
2281568fe7eSjsing 	{ 0,	NULL }
2291568fe7eSjsing };
2301568fe7eSjsing 
2311568fe7eSjsing /* GTPv1 Causes. */
2321568fe7eSjsing static struct tok gtp_v1_cause[] = {
2331568fe7eSjsing 
2341568fe7eSjsing 	/* GTPv1-C. */
2351568fe7eSjsing 	{ 0,	"Request IMSI" },
2361568fe7eSjsing 	{ 1,	"Request IMEI" },
2371568fe7eSjsing 	{ 2,	"Request IMSI and IMEI" },
2381568fe7eSjsing 	{ 3,	"No identity needed" },
2391568fe7eSjsing 	{ 4,	"MS refuses" },
2401568fe7eSjsing 	{ 5,	"MS is not GPRS responding" },
2411568fe7eSjsing 	{ 128,	"Request accepted" },
2421568fe7eSjsing 	{ 192,	"Non-existent" },
2431568fe7eSjsing 	{ 193,	"Invalid message format" },
2441568fe7eSjsing 	{ 194,	"IMSI not known" },
2451568fe7eSjsing 	{ 195,	"MS is GPRS detached" },
2461568fe7eSjsing 	{ 196,	"MS is not GPRS responding" },
2471568fe7eSjsing 	{ 197,	"MS refuses" },
2481568fe7eSjsing 	{ 198,	"Version not supported" },
2491568fe7eSjsing 	{ 199,	"No resources available" },
2501568fe7eSjsing 	{ 200,	"Service not supported" },
2511568fe7eSjsing 	{ 201,	"Mandatory IE incorrect" },
2521568fe7eSjsing 	{ 202,	"Mandatory IE missing" },
2531568fe7eSjsing 	{ 203,	"Optional IE incorrect" },
2541568fe7eSjsing 	{ 204,	"System failure" },
2551568fe7eSjsing 	{ 205,	"Roaming restriction" },
2561568fe7eSjsing 	{ 206,	"P-TMSI signature mismatch" },
2571568fe7eSjsing 	{ 207,	"GPRS connection suspended" },
2581568fe7eSjsing 	{ 208,	"Authentication failure" },
2591568fe7eSjsing 	{ 209,	"User authentication failed" },
2601568fe7eSjsing 	{ 210,	"Context not found" },
2611568fe7eSjsing 	{ 211,	"All dynamic PDP addresses are occupied" },
2621568fe7eSjsing 	{ 212,	"No memory is available" },
2631568fe7eSjsing 	{ 213,	"Relocation failure" },
2641568fe7eSjsing 	{ 214,	"Unknown mandatory extension header" },
2651568fe7eSjsing 	{ 215,	"Semantic error in the TFT operation" },
2661568fe7eSjsing 	{ 216,	"Syntactic error in the TFT operation" },
2671568fe7eSjsing 	{ 217,	"Semantic errors in packet filter(s)" },
2681568fe7eSjsing 	{ 218,	"Syntactic errors in packet filter(s)" },
2691568fe7eSjsing 	{ 219,	"Missing or unknown APN" },
2701568fe7eSjsing 	{ 220,	"Unknown PDP address or PDP type" },
2711568fe7eSjsing 	{ 221,	"PDP context without TFT already activated" },
2721568fe7eSjsing 	{ 222,	"APN access denied - no subscription" },
2731568fe7eSjsing 	{ 223,	"APN restriction type incompatibility with currently "
2741568fe7eSjsing 		"active PDP contexts" },
2751568fe7eSjsing 	{ 224,	"MS MBMS capabilities insufficient" },
2761568fe7eSjsing 	{ 225,	"Invalid correlation-ID" },
2771568fe7eSjsing 	{ 226,	"MBMS bearer context superseded" },
2781568fe7eSjsing 
2791568fe7eSjsing 	/* GTP'v1. */
2801568fe7eSjsing 	{ 59,	"System failure" },
2811568fe7eSjsing 	{ 60,	"The transmit buffers are becoming full" },
2821568fe7eSjsing 	{ 61,	"The receive buffers are becoming full" },
2831568fe7eSjsing 	{ 62,	"Another node is about to go down" },
2841568fe7eSjsing 	{ 63,	"This node is about to go down" },
2851568fe7eSjsing 	{ 177,	"CDR decoding error" },
2861568fe7eSjsing 	{ 252,	"Request related to possibly duplicated packets already "
2871568fe7eSjsing 		"fulfilled" },
2881568fe7eSjsing 	{ 253,	"Request already fulfilled" },
2891568fe7eSjsing 	{ 254,	"Sequence numbers of released/cancelled packets IE incorrect" },
2901568fe7eSjsing 	{ 255,	"Request not fulfilled" },
2911568fe7eSjsing 
2921568fe7eSjsing 	{ 0,	NULL }
2931568fe7eSjsing };
2941568fe7eSjsing 
2951568fe7eSjsing static int gtp_proto = -1;
2961568fe7eSjsing 
2971568fe7eSjsing void
gtp_print(const u_char * cp,u_int length,u_short sport,u_short dport)2986ad041cbSmmcc gtp_print(const u_char *cp, u_int length, u_short sport, u_short dport)
2991568fe7eSjsing {
3001568fe7eSjsing 	int version;
3011568fe7eSjsing 
3021568fe7eSjsing 	/* Decode GTP version. */
3031568fe7eSjsing 	TCHECK(cp[0]);
3041568fe7eSjsing 	version = cp[0] >> GTP_VERSION_SHIFT;
3051568fe7eSjsing 
3061568fe7eSjsing 	if (version == GTP_VERSION_0)
3071568fe7eSjsing 		gtp_v0_print(cp, length, sport, dport);
3081568fe7eSjsing 	else if (version == GTP_VERSION_1)
3091568fe7eSjsing 		gtp_v1_print(cp, length, sport, dport);
3101568fe7eSjsing 	else
3111568fe7eSjsing 		printf("GTP (version %i)", version);
3121568fe7eSjsing 
3131568fe7eSjsing 	return;
3141568fe7eSjsing 
3151568fe7eSjsing trunc:
3161568fe7eSjsing 	printf("[|GTP]");
3171568fe7eSjsing }
3181568fe7eSjsing 
3191568fe7eSjsing /*
3201568fe7eSjsing  * Decode and print information elements from message. The actual work is
3211568fe7eSjsing  * handled in the appropriate Tag/Value (TV) or Tag/Length/Value (TLV)
3221568fe7eSjsing  * decoding routine.
3231568fe7eSjsing  */
3241568fe7eSjsing void
gtp_decode_ie(const u_char * cp,u_short version,int len)3256ad041cbSmmcc gtp_decode_ie(const u_char *cp, u_short version, int len)
3261568fe7eSjsing {
3271568fe7eSjsing 	int val, ielen, iecount = 0;
3281568fe7eSjsing 
3291568fe7eSjsing 	if (len <= 0)
3301568fe7eSjsing 		return;
3311568fe7eSjsing 
3321568fe7eSjsing 	printf(" {");
3331568fe7eSjsing 
3341568fe7eSjsing 	while (len > 0) {
3351568fe7eSjsing 
3361568fe7eSjsing 		iecount++;
3371568fe7eSjsing 		if (iecount > 1)
3381568fe7eSjsing 			printf(" ");
3391568fe7eSjsing 
3401568fe7eSjsing 		TCHECK(cp[0]);
3411568fe7eSjsing 		val = (u_int)cp[0];
3421568fe7eSjsing 		cp++;
3431568fe7eSjsing 
3441568fe7eSjsing 		printf("[");
3451568fe7eSjsing 
3461568fe7eSjsing 		switch (version) {
3471568fe7eSjsing 		case GTP_VERSION_0:
3481568fe7eSjsing 			if ((val & GTPV0_IE_TYPE_MASK) == 0)
3491568fe7eSjsing 				ielen = gtp_v0_print_tv(cp, val);
3501568fe7eSjsing 			else
3511568fe7eSjsing 				ielen = gtp_v0_print_tlv(cp, val);
3521568fe7eSjsing 			break;
3531568fe7eSjsing 
3541568fe7eSjsing 		case GTP_VERSION_1:
3551568fe7eSjsing 			if ((val & GTPV1_IE_TYPE_MASK) == 0)
3561568fe7eSjsing 				ielen = gtp_v1_print_tv(cp, val);
3571568fe7eSjsing 			else
3581568fe7eSjsing 				ielen = gtp_v1_print_tlv(cp, val);
3591568fe7eSjsing 			break;
3601568fe7eSjsing 
3611568fe7eSjsing 		default:
3621568fe7eSjsing 			/* Version not supported... */
3631568fe7eSjsing 			ielen = -1;
3641568fe7eSjsing 			break;
3651568fe7eSjsing 		}
3661568fe7eSjsing 
3671568fe7eSjsing 		printf("]");
3681568fe7eSjsing 
3691568fe7eSjsing 		if (ielen < 0)
3701568fe7eSjsing 			goto trunc;
3711568fe7eSjsing 
3721568fe7eSjsing 		len -= ielen;
3731568fe7eSjsing 		cp += ielen - 1;
3741568fe7eSjsing 	}
3751568fe7eSjsing 
3761568fe7eSjsing 	if (iecount > 0)
3771568fe7eSjsing 		printf("}");
3781568fe7eSjsing 
3791568fe7eSjsing 	return;
3801568fe7eSjsing 
3811568fe7eSjsing trunc:
3821568fe7eSjsing 	printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
3831568fe7eSjsing }
3841568fe7eSjsing 
3851568fe7eSjsing /*
3861568fe7eSjsing  * Decode and print telephony binary coded decimal.
3871568fe7eSjsing  */
3881568fe7eSjsing void
gtp_print_tbcd(const u_char * cp,u_int len)3896ad041cbSmmcc gtp_print_tbcd(const u_char *cp, u_int len)
3901568fe7eSjsing {
3911568fe7eSjsing 	u_int8_t *data, bcd;
3921568fe7eSjsing 	int i;
3931568fe7eSjsing 
3941568fe7eSjsing 	data = (u_int8_t *)cp;
3951568fe7eSjsing 	for (i = 0; i < len; i++) {
3961568fe7eSjsing 		bcd = *data & 0xf;
3971568fe7eSjsing 		if (bcd != 0xf)
3981568fe7eSjsing 			printf("%u", bcd);
3991568fe7eSjsing 		bcd = *data >> 4;
4001568fe7eSjsing 		if (bcd != 0xf)
4011568fe7eSjsing 			printf("%u", bcd);
4021568fe7eSjsing 		data++;
4031568fe7eSjsing 	}
4041568fe7eSjsing }
4051568fe7eSjsing 
4061568fe7eSjsing /*
4071568fe7eSjsing  * Decode and print an end user address. Format is detailed in
4081568fe7eSjsing  * GSM 09.60 section 7.9.18 and 3GPP 29.060 section 7.7.27.
4091568fe7eSjsing  */
4101568fe7eSjsing void
gtp_print_user_address(const u_char * cp,u_int len)4116ad041cbSmmcc gtp_print_user_address(const u_char *cp, u_int len)
4121568fe7eSjsing {
4131568fe7eSjsing 	u_int8_t org, type;
4141568fe7eSjsing 
4151568fe7eSjsing 	if (len < 2)
4161568fe7eSjsing 		return;
4171568fe7eSjsing 
4181568fe7eSjsing 	org = (u_int8_t)cp[0] & 0xf;
4191568fe7eSjsing 	type = (u_int8_t)cp[1];
4201568fe7eSjsing 
4211568fe7eSjsing 	cp += 2;
4221568fe7eSjsing 
4231568fe7eSjsing 	if (org == 0x0 && type == 0x1)
4241568fe7eSjsing 		printf(": PPP");
4251568fe7eSjsing 	else if (org == 0x1 && type == 0x21) {
4261568fe7eSjsing 		if (len == 6)
4271568fe7eSjsing 			printf(": %s", ipaddr_string(cp));
4281568fe7eSjsing 		else
4291568fe7eSjsing 			printf(": IPv4");
4301568fe7eSjsing 	} else if (org == 0x1 && type == 0x57) {
4311568fe7eSjsing 		if (len == 18)
4321568fe7eSjsing 			printf(": %s", ip6addr_string(cp));
4331568fe7eSjsing 		else
4341568fe7eSjsing 			printf(": IPv6");
4351568fe7eSjsing 	} else
4361568fe7eSjsing 		printf(" (org 0x%x, type 0x%x)", org, type);
4371568fe7eSjsing }
4381568fe7eSjsing 
43956e8ec8dSjsing /*
44056e8ec8dSjsing  * Decode and print an Access Point Name. Format is detailed in
44156e8ec8dSjsing  * 3GPP 24.008 section 10.5.6.1 and 3GPP 23.003 section 9.1.
44256e8ec8dSjsing  */
44356e8ec8dSjsing void
gtp_print_apn(const u_char * cp,u_int len)4446ad041cbSmmcc gtp_print_apn(const u_char *cp, u_int len)
44556e8ec8dSjsing {
44656e8ec8dSjsing 	u_char label[100];
44756e8ec8dSjsing 	u_int8_t llen;
44856e8ec8dSjsing 
44956e8ec8dSjsing 	if (len < 1 || len > 100)
45056e8ec8dSjsing 		return;
45156e8ec8dSjsing 
45256e8ec8dSjsing 	while (len > 0) {
45356e8ec8dSjsing 
45456e8ec8dSjsing 		llen = (u_int8_t)cp[0];
45556e8ec8dSjsing 		if (llen > 99)
45656e8ec8dSjsing 			return;
45756e8ec8dSjsing 
45856e8ec8dSjsing 		bcopy(cp + 1, label, llen);
45956e8ec8dSjsing 		label[llen] = '\0';
46056e8ec8dSjsing 		printf("%s", label);
46156e8ec8dSjsing 
46256e8ec8dSjsing 		cp += llen + 1;
46356e8ec8dSjsing 		len -= llen + 1;
46456e8ec8dSjsing 
46556e8ec8dSjsing 		if (len > 0)
46656e8ec8dSjsing 			printf(".");
46756e8ec8dSjsing 
46856e8ec8dSjsing 	}
46956e8ec8dSjsing }
47056e8ec8dSjsing 
4711568fe7eSjsing /* Print string from array. */
4721568fe7eSjsing void
gtp_print_str(const char ** strs,u_int bound,u_int index)4731afdc05aSdlg gtp_print_str(const char **strs, u_int bound, u_int index)
4741568fe7eSjsing {
4751afdc05aSdlg 	if (index >= bound)
4761568fe7eSjsing 		printf(": %u", index);
4771568fe7eSjsing 	else if (strs[index] != NULL)
4781568fe7eSjsing 		printf(": %s", strs[index]);
4791568fe7eSjsing }
4801568fe7eSjsing 
4811568fe7eSjsing /*
4821568fe7eSjsing  * Decoding routines for GTP version 0.
4831568fe7eSjsing  */
4841568fe7eSjsing void
gtp_v0_print(const u_char * cp,u_int length,u_short sport,u_short dport)4851568fe7eSjsing gtp_v0_print(const u_char *cp, u_int length, u_short sport, u_short dport)
4861568fe7eSjsing {
4871568fe7eSjsing 	struct gtp_v0_hdr *gh = (struct gtp_v0_hdr *)cp;
4881568fe7eSjsing 	int len, version;
48961aaa407Sjsing 	u_int64_t tid;
4901568fe7eSjsing 
4911568fe7eSjsing 	gtp_proto = GTP_V0_PROTO;
4921568fe7eSjsing 
4931568fe7eSjsing 	/* Check if this is GTP prime. */
4941568fe7eSjsing 	TCHECK(gh->flags);
4951568fe7eSjsing 	if ((gh->flags & GTPV0_HDR_PROTO_TYPE) == 0) {
4961568fe7eSjsing 		gtp_proto = GTP_V0_PRIME_PROTO;
4971568fe7eSjsing 		gtp_v0_print_prime(cp);
4981568fe7eSjsing 		return;
4991568fe7eSjsing 	}
5001568fe7eSjsing 
5011568fe7eSjsing 	/* Print GTP header. */
5021568fe7eSjsing 	TCHECK(*gh);
5031568fe7eSjsing 	cp += sizeof(struct gtp_v0_hdr);
5041568fe7eSjsing 	len = ntohs(gh->length);
50561aaa407Sjsing 	bcopy(&gh->tid, &tid, sizeof(tid));
5061568fe7eSjsing 	printf("GTPv0 (len %u, seqno %u, flow %u, N-PDU %u, tid 0x%llx) ",
5071568fe7eSjsing 	    ntohs(gh->length), ntohs(gh->seqno), ntohs(gh->flow),
50861aaa407Sjsing 	    ntohs(gh->npduno), betoh64(tid));
5091568fe7eSjsing 
5101568fe7eSjsing 	/* Decode GTP message. */
5111568fe7eSjsing 	printf("%s", tok2str(gtp_v0_msgtype, "Message Type %u", gh->msgtype));
5121568fe7eSjsing 
5131568fe7eSjsing 	if (!vflag)
5141568fe7eSjsing 		return;
5151568fe7eSjsing 
5161568fe7eSjsing 	if (gh->msgtype == GTPV0_T_PDU) {
5171568fe7eSjsing 
5181568fe7eSjsing 		TCHECK(cp[0]);
5191568fe7eSjsing 		version = cp[0] >> 4;
5201568fe7eSjsing 
5211568fe7eSjsing 		printf(" { ");
5221568fe7eSjsing 
5231568fe7eSjsing 		if (version == 4)
5241568fe7eSjsing 			ip_print(cp, len);
5251568fe7eSjsing 		else if (version == 6)
5261568fe7eSjsing 			ip6_print(cp, len);
5271568fe7eSjsing 		else
5281568fe7eSjsing 			printf("Unknown IP version %u", version);
5291568fe7eSjsing 
5301568fe7eSjsing 		printf(" }");
5311568fe7eSjsing 	} else
5321568fe7eSjsing 		gtp_decode_ie(cp, GTP_VERSION_0, len);
5331568fe7eSjsing 
5341568fe7eSjsing 	return;
5351568fe7eSjsing 
5361568fe7eSjsing trunc:
5371568fe7eSjsing 	printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
5381568fe7eSjsing }
5391568fe7eSjsing 
5401568fe7eSjsing void
gtp_v0_print_prime(const u_char * cp)5416ad041cbSmmcc gtp_v0_print_prime(const u_char *cp)
5421568fe7eSjsing {
5431568fe7eSjsing 	struct gtp_v0_prime_hdr *gph = (struct gtp_v0_prime_hdr *)cp;
5441568fe7eSjsing 	int len;
5451568fe7eSjsing 
5461568fe7eSjsing 	/* Decode GTP prime header. */
5471568fe7eSjsing 	TCHECK(*gph);
5481568fe7eSjsing 	cp += sizeof(*gph);
5491568fe7eSjsing 
5501568fe7eSjsing 	len = ntohs(gph->length);
5511568fe7eSjsing 	printf("GTPv0' (len %u, seq %u) ", len, ntohs(gph->seqno));
5521568fe7eSjsing 
5531568fe7eSjsing 	/* Decode GTP message. */
5541568fe7eSjsing 	printf("%s", tok2str(gtp_v0_msgtype, "Message Type %u", gph->msgtype));
5551568fe7eSjsing 
5561568fe7eSjsing 	if (vflag)
5571568fe7eSjsing 		gtp_decode_ie(cp, GTP_VERSION_0, len);
5581568fe7eSjsing 
5591568fe7eSjsing 	return;
5601568fe7eSjsing 
5611568fe7eSjsing trunc:
5621568fe7eSjsing 	printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
5631568fe7eSjsing }
5641568fe7eSjsing 
5651568fe7eSjsing int
gtp_v0_print_tv(const u_char * cp,u_int value)5666ad041cbSmmcc gtp_v0_print_tv(const u_char *cp, u_int value)
5671568fe7eSjsing {
5681568fe7eSjsing 	u_int32_t *dpl;
5691568fe7eSjsing 	u_int16_t *dps;
5701568fe7eSjsing 	u_int8_t data;
5711568fe7eSjsing 	int ielen = -1;
5721568fe7eSjsing 
5731568fe7eSjsing 	switch (value) {
5741568fe7eSjsing 	case GTPV0_TV_CAUSE:
5751568fe7eSjsing 
5761568fe7eSjsing 		/* 09.60 7.9.1 - Cause. */
5771568fe7eSjsing 		TCHECK(cp[0]);
5781568fe7eSjsing 		data = (u_int8_t)cp[0];
5791568fe7eSjsing 		ielen = GTPV0_TV_CAUSE_LENGTH;
5801568fe7eSjsing 		printf("Cause: %s", tok2str(gtp_v0_cause, "#%u", data));
5811568fe7eSjsing 		break;
5821568fe7eSjsing 
5831568fe7eSjsing 	case GTPV0_TV_IMSI:
5841568fe7eSjsing 
5851568fe7eSjsing 		/* 09.60 7.9.2 - International Mobile Subscriber Identity. */
5861568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_IMSI_LENGTH - 1);
5871568fe7eSjsing 		printf("IMSI ");
5881568fe7eSjsing 		gtp_print_tbcd(cp, GTPV0_TV_IMSI_LENGTH - 1);
5891568fe7eSjsing 		ielen = GTPV0_TV_IMSI_LENGTH;
5901568fe7eSjsing 		break;
5911568fe7eSjsing 
5921568fe7eSjsing 	case GTPV0_TV_RAI:
5931568fe7eSjsing 
5941568fe7eSjsing 		/* 09.60 7.9.3 - Routing Area Identity (RAI). */
5951568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_RAI_LENGTH - 1);
5961568fe7eSjsing 		printf("RAI: MCC ");
5971568fe7eSjsing 		data = cp[1] | 0xf0;
5981568fe7eSjsing 		gtp_print_tbcd(cp, 1);
5991568fe7eSjsing 		gtp_print_tbcd(&data, 1);
6001568fe7eSjsing 		printf(", MNC ");
6011568fe7eSjsing 		data = (cp[1] >> 4) | 0xf0;
6021568fe7eSjsing 		gtp_print_tbcd(cp + 2, 1);
6031568fe7eSjsing 		gtp_print_tbcd(&data, 1);
6041568fe7eSjsing 		printf(", LAC 0x%x%x", cp[3], cp[4]);
6051568fe7eSjsing 		printf(", RAC 0x%x", cp[5]);
6061568fe7eSjsing 		ielen = GTPV0_TV_RAI_LENGTH;
6071568fe7eSjsing 		break;
6081568fe7eSjsing 
6091568fe7eSjsing 	case GTPV0_TV_TLLI:
6101568fe7eSjsing 
6111568fe7eSjsing 		/* 09.60 7.9.4 - Temporary Logical Link Identity (TLLI). */
6121568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_TLLI_LENGTH - 1);
6131568fe7eSjsing 		dpl = (u_int32_t *)cp;
6141568fe7eSjsing 		printf("TLLI 0x%x", ntohl(*dpl));
6151568fe7eSjsing 		ielen = GTPV0_TV_TLLI_LENGTH;
6161568fe7eSjsing 		break;
6171568fe7eSjsing 
6181568fe7eSjsing 	case GTPV0_TV_PTMSI:
6191568fe7eSjsing 
6201568fe7eSjsing 		/* 09.60 7.9.5 - Packet TMSI (P-TMSI). */
6211568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_PTMSI_LENGTH - 1);
6221568fe7eSjsing 		dpl = (u_int32_t *)cp;
6231568fe7eSjsing 		printf("P-TMSI 0x%x", ntohl(*dpl));
6241568fe7eSjsing 		ielen = GTPV0_TV_PTMSI_LENGTH;
6251568fe7eSjsing 		break;
6261568fe7eSjsing 
6271568fe7eSjsing 	case GTPV0_TV_QOS:
6281568fe7eSjsing 
6291568fe7eSjsing 		/* 09.60 7.9.6 - Quality of Service (QoS) Profile. */
6301568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_QOS_LENGTH - 1);
6311568fe7eSjsing 		printf("QoS Profile");				/* XXX */
6321568fe7eSjsing 		ielen = GTPV0_TV_QOS_LENGTH;
6331568fe7eSjsing 		break;
6341568fe7eSjsing 
6351568fe7eSjsing 	case GTPV0_TV_REORDER:
6361568fe7eSjsing 
6371568fe7eSjsing 		/* 09.60 7.9.7 - Reordering Required. */
6381568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_REORDER_LENGTH - 1);
6391568fe7eSjsing 		printf("Reordering Required: ");
6401568fe7eSjsing 		if (cp[0] & 0x1)
6411568fe7eSjsing 			printf("yes");
6421568fe7eSjsing 		else
6431568fe7eSjsing 			printf("no");
6441568fe7eSjsing 		ielen = GTPV0_TV_REORDER_LENGTH;
6451568fe7eSjsing 		break;
6461568fe7eSjsing 
6471568fe7eSjsing 	case GTPV0_TV_AUTH_TRIPLET:
6481568fe7eSjsing 
6491568fe7eSjsing 		/* 09.60 7.9.8 - Authentication Triplet. */
6501568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_AUTH_TRIPLET_LENGTH - 1);
6511568fe7eSjsing 		printf("Authentication");			/* XXX */
6521568fe7eSjsing 		ielen = GTPV0_TV_AUTH_TRIPLET_LENGTH;
6531568fe7eSjsing 		break;
6541568fe7eSjsing 
6551568fe7eSjsing 	case GTPV0_TV_MAP_CAUSE:
6561568fe7eSjsing 
6571568fe7eSjsing 		/* 09.60 7.9.9 - MAP Cause. */
6581568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_MAP_CAUSE_LENGTH - 1);
6591568fe7eSjsing 		printf("MAP Cause: %u", cp[0]);
6601568fe7eSjsing 		ielen = GTPV0_TV_MAP_CAUSE_LENGTH;
6611568fe7eSjsing 		break;
6621568fe7eSjsing 
6631568fe7eSjsing 	case GTPV0_TV_PTMSI_SIGNATURE:
6641568fe7eSjsing 
6651568fe7eSjsing 		/* 09.60 7.9.10 - P-TMSI Signature. */
6661568fe7eSjsing 		/* Signature defined in GSM 04.08. */
6671568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_PTMSI_SIGNATURE_LENGTH - 1);
6681568fe7eSjsing 		printf("PTMSI Signature: 0x%x%x%x", cp[0], cp[1], cp[2]);
6691568fe7eSjsing 		ielen = GTPV0_TV_PTMSI_SIGNATURE_LENGTH;
6701568fe7eSjsing 		break;
6711568fe7eSjsing 
6721568fe7eSjsing 	case GTPV0_TV_MS_VALIDATED:
6731568fe7eSjsing 
6741568fe7eSjsing 		/* 09.60 7.9.11 - MS Validated. */
6751568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_MS_VALIDATED_LENGTH - 1);
6761568fe7eSjsing 		printf("MS Validated");
6771568fe7eSjsing 		if (cp[0] & 0x1)
6781568fe7eSjsing 			printf("yes");
6791568fe7eSjsing 		else
6801568fe7eSjsing 			printf("no");
6811568fe7eSjsing 		ielen = GTPV0_TV_MS_VALIDATED_LENGTH;
6821568fe7eSjsing 		break;
6831568fe7eSjsing 
6841568fe7eSjsing 	case GTPV0_TV_RECOVERY:
6851568fe7eSjsing 
6861568fe7eSjsing 		/* 09.60 7.9.12 - Recovery. */
6871568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_RECOVERY_LENGTH - 1);
6881568fe7eSjsing 		printf("Recovery: Restart counter %u", cp[0]);
6891568fe7eSjsing 		ielen = GTPV0_TV_RECOVERY_LENGTH;
6901568fe7eSjsing 		break;
6911568fe7eSjsing 
6921568fe7eSjsing 	case GTPV0_TV_SELECTION_MODE:
6931568fe7eSjsing 
6941568fe7eSjsing 		/* 09.60 7.9.13 - Selection Mode. */
6951568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_SELECTION_MODE_LENGTH - 1);
6961568fe7eSjsing 		printf("Selection Mode");			/* XXX */
6971568fe7eSjsing 		ielen = GTPV0_TV_SELECTION_MODE_LENGTH;
6981568fe7eSjsing 		break;
6991568fe7eSjsing 
7001568fe7eSjsing 	case GTPV0_TV_FLOW_LABEL_DATA_I:
7011568fe7eSjsing 
7021568fe7eSjsing 		/* 09.60 7.9.14 - Flow Label Data I. */
7031568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_FLOW_LABEL_DATA_I_LENGTH - 1);
7041568fe7eSjsing 		dps = (u_int16_t *)cp;
7051568fe7eSjsing 		printf("Flow Label Data I: %u", ntohs(*dps));
7061568fe7eSjsing 		ielen = GTPV0_TV_FLOW_LABEL_DATA_I_LENGTH;
7071568fe7eSjsing 		break;
7081568fe7eSjsing 
7091568fe7eSjsing 	case GTPV0_TV_FLOW_LABEL_SIGNALLING:
7101568fe7eSjsing 
7111568fe7eSjsing 		/* 09.60 7.9.15 - Flow Label Signalling. */
7121568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_FLOW_LABEL_SIGNALLING_LENGTH - 1);
7131568fe7eSjsing 		dps = (u_int16_t *)cp;
7141568fe7eSjsing 		printf("Flow Label Signalling: %u", ntohs(*dps));
7151568fe7eSjsing 		ielen = GTPV0_TV_FLOW_LABEL_SIGNALLING_LENGTH;
7161568fe7eSjsing 		break;
7171568fe7eSjsing 
7181568fe7eSjsing 	case GTPV0_TV_FLOW_LABEL_DATA_II:
7191568fe7eSjsing 
7201568fe7eSjsing 		/* 09.60 7.9.16 - Flow Label Data II. */
7211568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_FLOW_LABEL_DATA_II_LENGTH - 1);
7221568fe7eSjsing 		data = cp[0] & 0xf;
7231568fe7eSjsing 		dps = (u_int16_t *)(cp + 1);
7241568fe7eSjsing 		printf("Flow Label Data II: %u, NSAPI %u", ntohs(*dps), data);
7251568fe7eSjsing 		ielen = GTPV0_TV_FLOW_LABEL_DATA_II_LENGTH;
7261568fe7eSjsing 		break;
7271568fe7eSjsing 
7281568fe7eSjsing 	case GTPV0_TV_PACKET_XFER_CMD:
7291568fe7eSjsing 
7301568fe7eSjsing 		/* 12.15 7.3.4.5.3 - Packet Transfer Command. */
7311568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_PACKET_XFER_CMD_LENGTH - 1);
7321568fe7eSjsing 		printf("Packet Transfer Command");
7331afdc05aSdlg 		gtp_print_str(gtp_packet_xfer_cmd, nitems(gtp_packet_xfer_cmd),
7341afdc05aSdlg 		    cp[0]);
7351568fe7eSjsing 		ielen = GTPV0_TV_PACKET_XFER_CMD_LENGTH;
7361568fe7eSjsing 		break;
7371568fe7eSjsing 
7381568fe7eSjsing 	case GTPV0_TV_CHARGING_ID:
7391568fe7eSjsing 
7401568fe7eSjsing 		/* 09.60 7.9.17 - Charging ID. */
7411568fe7eSjsing 		TCHECK2(cp[0], GTPV0_TV_CHARGING_ID_LENGTH - 1);
7421568fe7eSjsing 		dps = (u_int16_t *)cp;
7431568fe7eSjsing 		printf("Charging ID: %u", ntohs(*dps));
7441568fe7eSjsing 		ielen = GTPV0_TV_CHARGING_ID_LENGTH;
7451568fe7eSjsing 		break;
7461568fe7eSjsing 
7471568fe7eSjsing 	default:
7481568fe7eSjsing 		printf("TV %u", value);
7491568fe7eSjsing 	}
7501568fe7eSjsing 
7511568fe7eSjsing trunc:
7521568fe7eSjsing 	return ielen;
7531568fe7eSjsing }
7541568fe7eSjsing 
7551568fe7eSjsing int
gtp_v0_print_tlv(const u_char * cp,u_int value)7566ad041cbSmmcc gtp_v0_print_tlv(const u_char *cp, u_int value)
7571568fe7eSjsing {
7581568fe7eSjsing 	u_int8_t data;
7591568fe7eSjsing 	u_int16_t *lenp, *seqno, len;
7601568fe7eSjsing 	int ielen = -1;
7611568fe7eSjsing 
7621568fe7eSjsing 	/* Get length of IE. */
7631568fe7eSjsing 	TCHECK2(cp[0], 2);
7641568fe7eSjsing 	lenp = (u_int16_t *)cp;
7651568fe7eSjsing 	cp += 2;
7661568fe7eSjsing 	len = ntohs(*lenp);
7671568fe7eSjsing 	TCHECK2(cp[0], len);
7681568fe7eSjsing 	ielen = sizeof(data) + sizeof(len) + len;
7691568fe7eSjsing 
7701568fe7eSjsing 	switch (value) {
7711568fe7eSjsing 
7721568fe7eSjsing 	case GTPV0_TLV_END_USER_ADDRESS:
7731568fe7eSjsing 
7741568fe7eSjsing 		/* 09.60 7.9.18 - End User Address. */
7751568fe7eSjsing 		printf("End User Address");
7761568fe7eSjsing 		gtp_print_user_address(cp, len);
7771568fe7eSjsing 		break;
7781568fe7eSjsing 
7791568fe7eSjsing 	case GTPV0_TLV_MM_CONTEXT:
7801568fe7eSjsing 
7811568fe7eSjsing 		/* 09.60 7.9.19 - MM Context. */
7821568fe7eSjsing 		printf("MM Context");				/* XXX */
7831568fe7eSjsing 		break;
7841568fe7eSjsing 
7851568fe7eSjsing 	case GTPV0_TLV_PDP_CONTEXT:
7861568fe7eSjsing 
7871568fe7eSjsing 		/* 09.60 7.9.20 - PDP Context. */
7881568fe7eSjsing 		printf("PDP Context");				/* XXX */
7891568fe7eSjsing 		break;
7901568fe7eSjsing 
7911568fe7eSjsing 	case GTPV0_TLV_ACCESS_POINT_NAME:
7921568fe7eSjsing 
7931568fe7eSjsing 		/* 09.60 7.9.21 - Access Point Name. */
7941568fe7eSjsing 		printf("AP Name: ");
79556e8ec8dSjsing 		gtp_print_apn(cp, len);
7961568fe7eSjsing 		break;
7971568fe7eSjsing 
7981568fe7eSjsing 	case GTPV0_TLV_PROTOCOL_CONFIG_OPTIONS:
7991568fe7eSjsing 
8001568fe7eSjsing 		/* 09.60 7.9.22 - Protocol Configuration Options. */
8011568fe7eSjsing 		printf("Protocol Configuration Options");	/* XXX */
8021568fe7eSjsing 		break;
8031568fe7eSjsing 
8041568fe7eSjsing 	case GTPV0_TLV_GSN_ADDRESS:
8051568fe7eSjsing 
8061568fe7eSjsing 		/* 09.60 7.9.23 - GSN Address. */
8071568fe7eSjsing 		printf("GSN Address");
8081568fe7eSjsing 		if (len == 4)
8091568fe7eSjsing 			printf(": %s", ipaddr_string(cp));
8101568fe7eSjsing 		else if (len == 16)
8111568fe7eSjsing 			printf(": %s", ip6addr_string(cp));
8121568fe7eSjsing 		break;
8131568fe7eSjsing 
8141568fe7eSjsing 	case GTPV0_TLV_MS_ISDN:
8151568fe7eSjsing 
8161568fe7eSjsing 		/* 09.60 7.9.24 - MS International PSTN/ISDN Number. */
8171568fe7eSjsing 		printf("MSISDN ");
8181568fe7eSjsing 		data = (u_int8_t)cp[0];		/* XXX - Number type. */
8191568fe7eSjsing 		gtp_print_tbcd(cp + 1, len - 1);
8201568fe7eSjsing 		break;
8211568fe7eSjsing 
8221568fe7eSjsing 	case GTPV0_TLV_CHARGING_GATEWAY_ADDRESS:
8231568fe7eSjsing 
8241568fe7eSjsing 		/* 09.60 7.9.25 - Charging Gateway Address. */
8251568fe7eSjsing 		printf("Charging Gateway");
8261568fe7eSjsing 		if (len == 4)
8271568fe7eSjsing 			printf(": %s", ipaddr_string(cp));
8281568fe7eSjsing 		break;
8291568fe7eSjsing 
8301568fe7eSjsing 	case GTPV0_TLV_DATA_RECORD_PACKET:
8311568fe7eSjsing 
8321568fe7eSjsing 		/* 12.15 7.3.4.5.4 - Data Record Packet. */
8331568fe7eSjsing 		printf("Data Record: Records %u, Format %u, Format Version %u",
8341568fe7eSjsing 		    cp[0], cp[1], ntohs(*(u_int16_t *)(cp + 2)));
8351568fe7eSjsing 		break;
8361568fe7eSjsing 
8371568fe7eSjsing 	case GTPV0_TLV_REQUESTS_RESPONDED:
8381568fe7eSjsing 
8391568fe7eSjsing 		/* 12.15 7.3.4.6 - Requests Responded. */
8401568fe7eSjsing 		printf("Requests Responded:");
8411568fe7eSjsing 		seqno = (u_int16_t *)cp;
8421568fe7eSjsing 		while (len > 0) {
8431568fe7eSjsing 			printf(" %u", ntohs(*seqno));
8441568fe7eSjsing 			seqno++;
8451568fe7eSjsing 			len -= sizeof(*seqno);
8461568fe7eSjsing 		}
8471568fe7eSjsing 		break;
8481568fe7eSjsing 
8491568fe7eSjsing 	case GTPV0_TLV_RECOMMENDED_NODE:
8501568fe7eSjsing 
8511568fe7eSjsing 		/* 12.15 7.3.4.3 - Address of Recommended Node. */
8521568fe7eSjsing 		printf("Recommended Node");
8531568fe7eSjsing 		if (len == 4)
8541568fe7eSjsing 			printf(": %s", ipaddr_string(cp));
8551568fe7eSjsing 		else if (len == 16)
8561568fe7eSjsing 			printf(": %s", ip6addr_string(cp));
8571568fe7eSjsing 		break;
8581568fe7eSjsing 
8591568fe7eSjsing 	case GTPV0_TLV_PRIVATE_EXTENSION:
8601568fe7eSjsing 
8611568fe7eSjsing 		printf("Private Extension");
8621568fe7eSjsing 		break;
8631568fe7eSjsing 
8641568fe7eSjsing 	default:
8651568fe7eSjsing 		printf("TLV %u (len %u)", value, len);
8661568fe7eSjsing 	}
8671568fe7eSjsing 
8681568fe7eSjsing 	return ielen;
8691568fe7eSjsing 
8701568fe7eSjsing trunc:
8711568fe7eSjsing 	return -1;
8721568fe7eSjsing }
8731568fe7eSjsing 
8741568fe7eSjsing /*
8751568fe7eSjsing  * Decoding for GTP version 1, which consists of GTPv1-C, GTPv1-U and GTPv1'.
8761568fe7eSjsing  */
8771568fe7eSjsing void
gtp_v1_print(const u_char * cp,u_int length,u_short sport,u_short dport)8781568fe7eSjsing gtp_v1_print(const u_char *cp, u_int length, u_short sport, u_short dport)
8791568fe7eSjsing {
8801568fe7eSjsing 	struct gtp_v1_hdr *gh = (struct gtp_v1_hdr *)cp;
881031569f0Smmcc 	struct gtp_v1_hdr_ext *ghe = NULL;
8821568fe7eSjsing 	int nexthdr, hlen;
8831568fe7eSjsing 	u_char *p = (u_char *)cp;
8841568fe7eSjsing 
8851568fe7eSjsing 	TCHECK(gh->flags);
88634d9095cSjsg 	if ((gh->flags & GTPV1_HDR_PROTO_TYPE) == 0) {
8871568fe7eSjsing 		gtp_proto = GTP_V1_PRIME_PROTO;
88856e8ec8dSjsing 		printf(" GTPv1'");
8891568fe7eSjsing 		gtp_v1_print_prime(p, (struct gtp_v1_prime_hdr *)gh);
8901568fe7eSjsing 		return;
8911568fe7eSjsing 	}
8921568fe7eSjsing 
8931568fe7eSjsing 	if (dport == GTPV1_C_PORT || sport == GTPV1_C_PORT) {
8941568fe7eSjsing 		gtp_proto = GTP_V1_CTRL_PROTO;
8951568fe7eSjsing 		printf(" GTPv1-C");
8961568fe7eSjsing 	} else if (dport == GTPV1_U_PORT || sport == GTPV1_U_PORT) {
8971568fe7eSjsing 		gtp_proto = GTP_V1_USER_PROTO;
8981568fe7eSjsing 		printf(" GTPv1-U");
8991568fe7eSjsing 	} else if (dport == GTPV1_PRIME_PORT || sport == GTPV1_PRIME_PORT) {
9001568fe7eSjsing 		gtp_proto = GTP_V1_PRIME_PROTO;
9011568fe7eSjsing 		printf(" GTPv1'");
9021568fe7eSjsing 	}
9031568fe7eSjsing 
9041568fe7eSjsing 	/* Decode GTP header. */
9051568fe7eSjsing 	TCHECK(*gh);
9061568fe7eSjsing 	p += sizeof(struct gtp_v1_hdr);
9071568fe7eSjsing 
9081568fe7eSjsing 	printf(" (teid %u, len %u)", ntohl(gh->teid), ntohs(gh->length));
9091568fe7eSjsing 
9101568fe7eSjsing 	if (gh->flags & GTPV1_HDR_EXT) {
9111568fe7eSjsing 		ghe = (struct gtp_v1_hdr_ext *)cp;
9121568fe7eSjsing 		TCHECK(*ghe);
9131568fe7eSjsing 		p += sizeof(struct gtp_v1_hdr_ext) - sizeof(struct gtp_v1_hdr);
9141568fe7eSjsing 	}
9151568fe7eSjsing 
9161568fe7eSjsing 	if (gh->flags & GTPV1_HDR_SN_FLAG)
9171568fe7eSjsing 		printf(" [seq %u]", ntohs(ghe->seqno));
9181568fe7eSjsing 
9191568fe7eSjsing 	if (gh->flags & GTPV1_HDR_NPDU_FLAG)
9201568fe7eSjsing 		printf(" [N-PDU %u]", ghe->npduno);
9211568fe7eSjsing 
9221568fe7eSjsing 	if (gh->flags & GTPV1_HDR_EH_FLAG) {
9231568fe7eSjsing 
9241568fe7eSjsing 		/* Process next header... */
9251568fe7eSjsing 		nexthdr = ghe->nexthdr;
9261568fe7eSjsing 		while (nexthdr != GTPV1_EH_NONE) {
9271568fe7eSjsing 
9281568fe7eSjsing 			/* Header length is a 4 octet multiplier. */
9291568fe7eSjsing 			hlen = (int)p[0] * 4;
930*9d41c169Sjca 			if (hlen == 0) {
931*9d41c169Sjca 				printf(" [Invalid zero-length header %u]",
932*9d41c169Sjca 				    nexthdr);
933*9d41c169Sjca 				goto trunc;
934*9d41c169Sjca 			}
9351568fe7eSjsing 			TCHECK2(p[0], hlen);
9361568fe7eSjsing 
9371568fe7eSjsing 			switch (nexthdr) {
9381568fe7eSjsing 			case GTPV1_EH_MBMS_SUPPORT:
9391568fe7eSjsing 				printf(" [MBMS Support]");
9401568fe7eSjsing 				break;
9411568fe7eSjsing 
9421568fe7eSjsing 			case GTPV1_EH_MSI_CHANGE_RPT:
9431568fe7eSjsing 				printf(" [MS Info Change Reporting]");
9441568fe7eSjsing 				break;
9451568fe7eSjsing 
9461568fe7eSjsing 			case GTPV1_EH_PDCP_PDU_NO:
9471568fe7eSjsing 				printf(" [PDCP PDU %u]",
9481568fe7eSjsing 				    ntohs(*(u_int16_t *)(p + 1)));
9491568fe7eSjsing 				break;
9501568fe7eSjsing 
9511568fe7eSjsing 			case GTPV1_EH_SUSPEND_REQUEST:
9521568fe7eSjsing 				printf(" [Suspend Request]");
9531568fe7eSjsing 				break;
9541568fe7eSjsing 
9551568fe7eSjsing 			case GTPV1_EH_SUSPEND_RESPONSE:
9561568fe7eSjsing 				printf(" [Suspend Response]");
9571568fe7eSjsing 				break;
9581568fe7eSjsing 
9591568fe7eSjsing 			default:
9601568fe7eSjsing 				printf(" [Unknown Header %u]", nexthdr);
9611568fe7eSjsing 			}
9621568fe7eSjsing 
9631568fe7eSjsing 			p += hlen - 1;
9641568fe7eSjsing 			nexthdr = (int)p[0];
9651568fe7eSjsing 			p++;
9661568fe7eSjsing 		}
9671568fe7eSjsing 
9681568fe7eSjsing 	}
9691568fe7eSjsing 
9701568fe7eSjsing 	hlen = p - cp;
9711568fe7eSjsing 
9721568fe7eSjsing 	if (dport == GTPV1_C_PORT || sport == GTPV1_C_PORT)
9731568fe7eSjsing 		gtp_v1_print_ctrl(p, hlen, gh);
9741568fe7eSjsing 	else if (dport == GTPV1_U_PORT || sport == GTPV1_U_PORT)
9751568fe7eSjsing 		gtp_v1_print_user(p, hlen, gh);
9761568fe7eSjsing 
9771568fe7eSjsing 	return;
9781568fe7eSjsing 
9791568fe7eSjsing trunc:
9801568fe7eSjsing 	printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
9811568fe7eSjsing }
9821568fe7eSjsing 
9831568fe7eSjsing void
gtp_v1_print_ctrl(const u_char * cp,u_int hlen,struct gtp_v1_hdr * gh)9846ad041cbSmmcc gtp_v1_print_ctrl(const u_char *cp, u_int hlen, struct gtp_v1_hdr *gh)
9851568fe7eSjsing {
9861568fe7eSjsing 	int len;
9871568fe7eSjsing 
9881568fe7eSjsing 	/* Decode GTP control message. */
9891568fe7eSjsing 	printf(" %s", tok2str(gtp_v1_msgtype, "Message Type %u", gh->msgtype));
9901568fe7eSjsing 
9911568fe7eSjsing 	len = ntohs(gh->length) - hlen + sizeof(*gh);
9921568fe7eSjsing 	if (vflag)
9931568fe7eSjsing 		gtp_decode_ie(cp, GTP_VERSION_1, len);
9941568fe7eSjsing }
9951568fe7eSjsing 
9961568fe7eSjsing void
gtp_v1_print_user(const u_char * cp,u_int hlen,struct gtp_v1_hdr * gh)9976ad041cbSmmcc gtp_v1_print_user(const u_char *cp, u_int hlen, struct gtp_v1_hdr *gh)
9981568fe7eSjsing {
9991568fe7eSjsing 	int len, version;
10001568fe7eSjsing 
10011568fe7eSjsing 	/* Decode GTP user message. */
10021568fe7eSjsing 	printf(" %s", tok2str(gtp_v1_msgtype, "Message Type %u", gh->msgtype));
10031568fe7eSjsing 
10041568fe7eSjsing 	if (!vflag)
10051568fe7eSjsing 		return;
10061568fe7eSjsing 
10071568fe7eSjsing 	len = ntohs(gh->length) - hlen + sizeof(*gh);
10081568fe7eSjsing 
10091568fe7eSjsing 	if (gh->msgtype == GTPV1_G_PDU) {
10101568fe7eSjsing 
10111568fe7eSjsing 		TCHECK(cp[0]);
10121568fe7eSjsing 		version = cp[0] >> 4;
10131568fe7eSjsing 
10141568fe7eSjsing 		printf(" { ");
10151568fe7eSjsing 
10161568fe7eSjsing 		if (version == 4)
10171568fe7eSjsing 			ip_print(cp, len);
10181568fe7eSjsing 		else if (version == 6)
10191568fe7eSjsing 			ip6_print(cp, len);
10201568fe7eSjsing 		else
10211568fe7eSjsing 			printf("Unknown IP version %u", version);
10221568fe7eSjsing 
10231568fe7eSjsing 		printf(" }");
10241568fe7eSjsing 
10251568fe7eSjsing 	} else
10261568fe7eSjsing 		gtp_decode_ie(cp, GTP_VERSION_1, len);
10271568fe7eSjsing 
10281568fe7eSjsing 	return;
10291568fe7eSjsing 
10301568fe7eSjsing trunc:
10311568fe7eSjsing 	printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
10321568fe7eSjsing }
10331568fe7eSjsing 
10341568fe7eSjsing void
gtp_v1_print_prime(const u_char * cp,struct gtp_v1_prime_hdr * gph)10356ad041cbSmmcc gtp_v1_print_prime(const u_char *cp, struct gtp_v1_prime_hdr *gph)
10361568fe7eSjsing {
10371568fe7eSjsing 	int len;
10381568fe7eSjsing 
10391568fe7eSjsing 	/* Decode GTP prime header. */
10401568fe7eSjsing 	TCHECK(*gph);
10411568fe7eSjsing 	cp += sizeof(struct gtp_v1_prime_hdr);
10421568fe7eSjsing 
10431568fe7eSjsing 	len = ntohs(gph->length);
10441568fe7eSjsing 	printf(" (len %u, seq %u) ", len, ntohs(gph->seqno));
10451568fe7eSjsing 
10461568fe7eSjsing 	/* Decode GTP message. */
10471568fe7eSjsing 	printf("%s", tok2str(gtp_v1_msgtype, "Message Type %u", gph->msgtype));
10481568fe7eSjsing 
10491568fe7eSjsing 	if (vflag)
10501568fe7eSjsing 		gtp_decode_ie(cp, GTP_VERSION_1, len);
10511568fe7eSjsing 
10521568fe7eSjsing 	return;
10531568fe7eSjsing 
10541568fe7eSjsing trunc:
10551568fe7eSjsing 	printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
10561568fe7eSjsing }
10571568fe7eSjsing 
10581568fe7eSjsing int
gtp_v1_print_tv(const u_char * cp,u_int value)10596ad041cbSmmcc gtp_v1_print_tv(const u_char *cp, u_int value)
10601568fe7eSjsing {
10611568fe7eSjsing 	u_int32_t *dpl;
10621568fe7eSjsing 	u_int16_t *dps;
10631568fe7eSjsing 	u_int8_t data;
10641568fe7eSjsing 	int ielen = -1;
10651568fe7eSjsing 
10661568fe7eSjsing 	switch (value) {
10671568fe7eSjsing 	case GTPV1_TV_CAUSE:
10681568fe7eSjsing 
10691568fe7eSjsing 		/* 29.060 - 7.7.1 Cause. */
10701568fe7eSjsing 		TCHECK(cp[0]);
10711568fe7eSjsing 		data = (u_int8_t)cp[0];
10721568fe7eSjsing 		ielen = GTPV1_TV_CAUSE_LENGTH;
10731568fe7eSjsing 		printf("Cause: %s", tok2str(gtp_v1_cause, "#%u", data));
10741568fe7eSjsing 		break;
10751568fe7eSjsing 
10761568fe7eSjsing 	case GTPV1_TV_IMSI:
10771568fe7eSjsing 
10781568fe7eSjsing 		/* 29.060 7.7.2 - International Mobile Subscriber Identity. */
10791568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_IMSI_LENGTH - 1);
10801568fe7eSjsing 		printf("IMSI ");
10811568fe7eSjsing 		gtp_print_tbcd(cp, GTPV1_TV_IMSI_LENGTH - 1);
10821568fe7eSjsing 		ielen = GTPV1_TV_IMSI_LENGTH;
10831568fe7eSjsing 		break;
10841568fe7eSjsing 
10851568fe7eSjsing 	case GTPV1_TV_RAI:
10861568fe7eSjsing 
10871568fe7eSjsing 		/* 29.060 7.7.3 - Routing Area Identity (RAI). */
10881568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_RAI_LENGTH - 1);
10891568fe7eSjsing 		printf("RAI: MCC ");
10901568fe7eSjsing 		data = cp[1] | 0xf0;
10911568fe7eSjsing 		gtp_print_tbcd(cp, 1);
10921568fe7eSjsing 		gtp_print_tbcd(&data, 1);
10931568fe7eSjsing 		printf(", MNC ");
10941568fe7eSjsing 		data = (cp[1] >> 4) | 0xf0;
10951568fe7eSjsing 		gtp_print_tbcd(cp + 2, 1);
10961568fe7eSjsing 		gtp_print_tbcd(&data, 1);
10971568fe7eSjsing 		printf(", LAC 0x%x%x", cp[3], cp[4]);
10981568fe7eSjsing 		printf(", RAC 0x%x", cp[5]);
10991568fe7eSjsing 		ielen = GTPV1_TV_RAI_LENGTH;
11001568fe7eSjsing 		break;
11011568fe7eSjsing 
11021568fe7eSjsing 	case GTPV1_TV_TLLI:
11031568fe7eSjsing 
11041568fe7eSjsing 		/* 29.060 7.7.4 - Temporary Logical Link Identity (TLLI). */
11051568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_TLLI_LENGTH - 1);
11061568fe7eSjsing 		dpl = (u_int32_t *)cp;
11071568fe7eSjsing 		printf("TLLI 0x%x", ntohl(*dpl));
11081568fe7eSjsing 		ielen = GTPV1_TV_TLLI_LENGTH;
11091568fe7eSjsing 		break;
11101568fe7eSjsing 
11111568fe7eSjsing 	case GTPV1_TV_PTMSI:
11121568fe7eSjsing 
11131568fe7eSjsing 		/* 29.060 7.7.5 - Packet TMSI (P-TMSI). */
11141568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_PTMSI_LENGTH - 1);
11151568fe7eSjsing 		dpl = (u_int32_t *)cp;
11161568fe7eSjsing 		printf("P-TMSI 0x%x", ntohl(*dpl));
11171568fe7eSjsing 		ielen = GTPV1_TV_PTMSI_LENGTH;
11181568fe7eSjsing 		break;
11191568fe7eSjsing 
11201568fe7eSjsing 	case GTPV1_TV_REORDER:
11211568fe7eSjsing 
11221568fe7eSjsing 		/* 29.060 7.7.6 - Reordering Required. */
11231568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_REORDER_LENGTH - 1);
11241568fe7eSjsing 		printf("Reordering Required: ");
11251568fe7eSjsing 		if (cp[0] & 0x1)
11261568fe7eSjsing 			printf("yes");
11271568fe7eSjsing 		else
11281568fe7eSjsing 			printf("no");
11291568fe7eSjsing 		ielen = GTPV1_TV_REORDER_LENGTH;
11301568fe7eSjsing 		break;
11311568fe7eSjsing 
11321568fe7eSjsing 	case GTPV1_TV_AUTH:
11331568fe7eSjsing 
11341568fe7eSjsing 		/* 29.060 7.7.7 - Authentication Triplet. */
11351568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_AUTH_LENGTH - 1);
11361568fe7eSjsing 		dpl = (u_int32_t *)cp;
11371568fe7eSjsing 		printf("Auth: RAND 0x%x%x%x%x, SRES 0x%x, Kc 0x%x%x",
11381568fe7eSjsing 		    ntohl(dpl[0]), ntohl(dpl[1]), ntohl(dpl[2]), ntohl(dpl[3]),
11391568fe7eSjsing 		    ntohl(dpl[4]), ntohl(dpl[5]), ntohl(dpl[6]));
11401568fe7eSjsing 		ielen = GTPV1_TV_AUTH_LENGTH;
11411568fe7eSjsing 		break;
11421568fe7eSjsing 
11431568fe7eSjsing 	case GTPV1_TV_MAP_CAUSE:
11441568fe7eSjsing 
11451568fe7eSjsing 		/* 29.060 7.7.8 - MAP Cause. */
11461568fe7eSjsing 		/* Cause defined in 3GPP TS 29.002. */
11471568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_MAP_CAUSE_LENGTH - 1);
11481568fe7eSjsing 		printf("Map Cause: %u", cp[0]);
11491568fe7eSjsing 		ielen = GTPV1_TV_MAP_CAUSE_LENGTH;
11501568fe7eSjsing 		break;
11511568fe7eSjsing 
11521568fe7eSjsing 	case GTPV1_TV_PTMSI_SIGNATURE:
11531568fe7eSjsing 
11541568fe7eSjsing 		/* 29.060 7.7.9 - P-TMSI Signature. */
11551568fe7eSjsing 		/* Signature defined in 3GPP TS 24.008. */
11561568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_PTMSI_SIGNATURE_LENGTH - 1);
11571568fe7eSjsing 		printf("PTMSI Signature: 0x%x%x%x", cp[0], cp[1], cp[2]);
11581568fe7eSjsing 		ielen = GTPV1_TV_PTMSI_SIGNATURE_LENGTH;
11591568fe7eSjsing 		break;
11601568fe7eSjsing 
11611568fe7eSjsing 	case GTPV1_TV_MS_VALIDATED:
11621568fe7eSjsing 
11631568fe7eSjsing 		/* 29.060 7.7.10 - MS Validated. */
11641568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_MS_VALIDATED_LENGTH - 1);
11651568fe7eSjsing 		printf("MS Validated: ");
11661568fe7eSjsing 		if (cp[0] & 0x1)
11671568fe7eSjsing 			printf("yes");
11681568fe7eSjsing 		else
11691568fe7eSjsing 			printf("no");
11701568fe7eSjsing 		ielen = GTPV1_TV_MS_VALIDATED_LENGTH;
11711568fe7eSjsing 		break;
11721568fe7eSjsing 
11731568fe7eSjsing 	case GTPV1_TV_RECOVERY:
11741568fe7eSjsing 
11751568fe7eSjsing 		/* 29.060 7.7.11 - Recovery. */
11761568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_RECOVERY_LENGTH - 1);
11771568fe7eSjsing 		printf("Recovery: Restart counter %u", cp[0]);
11781568fe7eSjsing 		ielen = GTPV1_TV_RECOVERY_LENGTH;
11791568fe7eSjsing 		break;
11801568fe7eSjsing 
11811568fe7eSjsing 	case GTPV1_TV_SELECTION_MODE:
11821568fe7eSjsing 
11831568fe7eSjsing 		/* 29.060 7.7.12 - Selection Mode. */
11841568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_SELECTION_MODE_LENGTH - 1);
11851568fe7eSjsing 		data = (u_int8_t)cp[0];
11861568fe7eSjsing 		printf("Selection Mode: %u", data & 0x2);
11871568fe7eSjsing 		ielen = GTPV1_TV_SELECTION_MODE_LENGTH;
11881568fe7eSjsing 		break;
11891568fe7eSjsing 
11901568fe7eSjsing 	case GTPV1_TV_TEID_DATA_I:
11911568fe7eSjsing 
11921568fe7eSjsing 		/* 29.060 7.7.13 - Tunnel Endpoint Identifier Data I. */
11931568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_TEID_DATA_I_LENGTH - 1);
11941568fe7eSjsing 		dpl = (u_int32_t *)cp;
11951568fe7eSjsing 		printf("TEI Data I: %u", ntohl(*dpl));
11961568fe7eSjsing 		ielen = GTPV1_TV_TEID_DATA_I_LENGTH;
11971568fe7eSjsing 		break;
11981568fe7eSjsing 
11991568fe7eSjsing 	case GTPV1_TV_TEID_CTRL:
12001568fe7eSjsing 
12011568fe7eSjsing 		/* 29.060 7.7.14 - Tunnel Endpoint Identifier Control Plane. */
12021568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_TEID_CTRL_LENGTH - 1);
12031568fe7eSjsing 		dpl = (u_int32_t *)cp;
12041568fe7eSjsing 		printf("TEI Control Plane: %u", ntohl(*dpl));
12051568fe7eSjsing 		ielen = GTPV1_TV_TEID_CTRL_LENGTH;
12061568fe7eSjsing 		break;
12071568fe7eSjsing 
12081568fe7eSjsing 	case GTPV1_TV_TEID_DATA_II:
12091568fe7eSjsing 
12101568fe7eSjsing 		/* 29.060 7.7.15 - Tunnel Endpoint Identifier Data II. */
12111568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_TEID_DATA_II_LENGTH - 1);
12121568fe7eSjsing 		data = cp[0] & 0xf;
12131568fe7eSjsing 		dpl = (u_int32_t *)(cp + 1);
12141568fe7eSjsing 		printf("TEI Data II: %u, NSAPI %u", ntohl(*dpl), data);
12151568fe7eSjsing 		ielen = GTPV1_TV_TEID_DATA_II_LENGTH;
12161568fe7eSjsing 		break;
12171568fe7eSjsing 
12181568fe7eSjsing 	case GTPV1_TV_TEARDOWN:
12191568fe7eSjsing 
12201568fe7eSjsing 		/* 29.060 7.7.16 - Teardown Indicator. */
12211568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_TEARDOWN_LENGTH - 1);
12221568fe7eSjsing 		printf("Teardown: ");
12231568fe7eSjsing 		if (cp[0] & 0x1)
12241568fe7eSjsing 			printf("yes");
12251568fe7eSjsing 		else
12261568fe7eSjsing 			printf("no");
12271568fe7eSjsing 		ielen = GTPV1_TV_TEARDOWN_LENGTH;
12281568fe7eSjsing 		break;
12291568fe7eSjsing 
12301568fe7eSjsing 	case GTPV1_TV_NSAPI:
12311568fe7eSjsing 
12321568fe7eSjsing 		/* 29.060 7.7.17 - NSAPI. */
12331568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_NSAPI_LENGTH - 1);
12341568fe7eSjsing 		data = (u_int8_t)cp[0];
12351568fe7eSjsing 		printf("NSAPI %u", data & 0xf);
12361568fe7eSjsing 		ielen = GTPV1_TV_NSAPI_LENGTH;
12371568fe7eSjsing 		break;
12381568fe7eSjsing 
12391568fe7eSjsing 	case GTPV1_TV_RANAP:
12401568fe7eSjsing 
12411568fe7eSjsing 		/* 29.060 7.7.18 - RANAP Cause. */
12421568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_RANAP_LENGTH - 1);
12431568fe7eSjsing 		printf("RANAP Cause: %u", cp[0]);
12441568fe7eSjsing 		ielen = GTPV1_TV_RANAP_LENGTH;
12451568fe7eSjsing 		break;
12461568fe7eSjsing 
12471568fe7eSjsing 	case GTPV1_TV_RAB_CONTEXT:
12481568fe7eSjsing 
12491568fe7eSjsing 		/* 29.060 7.7.19 - RAB Context. */
12501568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_RAB_CONTEXT_LENGTH - 1);
12511568fe7eSjsing 		data = cp[0] & 0xf;
12521568fe7eSjsing 		dps = (u_int16_t *)(cp + 1);
12531568fe7eSjsing 		printf("RAB Context: NSAPI %u, DL GTP-U Seq No %u,"
12541568fe7eSjsing 		    "UL GTP-U Seq No %u, DL PDCP Seq No %u, UL PDCP Seq No %u",
12551568fe7eSjsing 		    data, ntohs(dps[0]), ntohs(dps[1]), ntohs(dps[2]),
12561568fe7eSjsing 		    ntohs(dps[3]));
12571568fe7eSjsing 		ielen = GTPV1_TV_RAB_CONTEXT_LENGTH;
12581568fe7eSjsing 		break;
12591568fe7eSjsing 
12601568fe7eSjsing 	case GTPV1_TV_RADIO_PRIORITY_SMS:
12611568fe7eSjsing 
12621568fe7eSjsing 		/* 29.060 7.7.20 - Radio Priority SMS. */
12631568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_RADIO_PRI_SMS_LENGTH - 1);
12641568fe7eSjsing 		printf("Radio Priority SMS: %u", cp[0] & 0x7);
12651568fe7eSjsing 		ielen = GTPV1_TV_RADIO_PRI_SMS_LENGTH;
12661568fe7eSjsing 		break;
12671568fe7eSjsing 
12681568fe7eSjsing 	case GTPV1_TV_RADIO_PRIORITY:
12691568fe7eSjsing 
12701568fe7eSjsing 		/* 29.060 7.7.21 - Radio Priority. */
12711568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_RADIO_PRI_LENGTH - 1);
12721568fe7eSjsing 		data = cp[0] >> 4;
12731568fe7eSjsing 		printf("Radio Priority: %u, NSAPI %u", cp[0] & 0x7, data);
12741568fe7eSjsing 		ielen = GTPV1_TV_RADIO_PRI_LENGTH;
12751568fe7eSjsing 		break;
12761568fe7eSjsing 
12771568fe7eSjsing 	case GTPV1_TV_PACKET_FLOW_ID:
12781568fe7eSjsing 
12791568fe7eSjsing 		/* 29.060 7.7.22 - Packet Flow ID. */
12801568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_PACKET_FLOW_ID_LENGTH - 1);
12811568fe7eSjsing 		printf("Packet Flow ID: %u, NSAPI %u", cp[1], cp[0] & 0xf);
12821568fe7eSjsing 		ielen = GTPV1_TV_PACKET_FLOW_ID_LENGTH;
12831568fe7eSjsing 		break;
12841568fe7eSjsing 
12851568fe7eSjsing 	case GTPV1_TV_CHARGING:
12861568fe7eSjsing 
12871568fe7eSjsing 		/* 29.060 7.7.23 - Charging Characteristics. */
12881568fe7eSjsing 		/* Charging defined in 3GPP TS 32.298. */
12891568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_CHARGING_LENGTH - 1);
12901568fe7eSjsing 		printf("Charging Characteristics");		/* XXX */
12911568fe7eSjsing 		ielen = GTPV1_TV_CHARGING_LENGTH;
12921568fe7eSjsing 		break;
12931568fe7eSjsing 
12941568fe7eSjsing 	case GTPV1_TV_TRACE_REFERENCE:
12951568fe7eSjsing 
12961568fe7eSjsing 		/* 29.060 7.7.24 - Trace Reference. */
12971568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_TRACE_REFERENCE_LENGTH - 1);
12981568fe7eSjsing 		dps = (u_int16_t *)cp;
12991568fe7eSjsing 		printf("Trace Reference: %u", ntohs(*dps));
13001568fe7eSjsing 		ielen = GTPV1_TV_TRACE_REFERENCE_LENGTH;
13011568fe7eSjsing 		break;
13021568fe7eSjsing 
13031568fe7eSjsing 	case GTPV1_TV_TRACE_TYPE:
13041568fe7eSjsing 
13051568fe7eSjsing 		/* 29.060 7.7.25 - Trace Type. */
13061568fe7eSjsing 		/* Trace type defined in GSM 12.08. */
13071568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_TRACE_TYPE_LENGTH - 1);
13081568fe7eSjsing 		dps = (u_int16_t *)cp;
13091568fe7eSjsing 		printf("Trace Type: %u", ntohs(*dps));
13101568fe7eSjsing 		ielen = GTPV1_TV_TRACE_TYPE_LENGTH;
13111568fe7eSjsing 		break;
13121568fe7eSjsing 
13131568fe7eSjsing 	case GTPV1_TV_MSNRR:
13141568fe7eSjsing 
13151568fe7eSjsing 		/* 29.060 7.7.26 - MS Not Reachable Reason. */
13161568fe7eSjsing 		/* Reason defined in 3GPP TS 23.040. */
13171568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_MSNRR_LENGTH - 1);
13181568fe7eSjsing 		printf("MS NRR: %u", cp[0]);
13191568fe7eSjsing 		ielen = GTPV1_TV_MSNRR_LENGTH;
13201568fe7eSjsing 		break;
13211568fe7eSjsing 
13221568fe7eSjsing 	case GTPV1_TV_PACKET_XFER_CMD:
13231568fe7eSjsing 
13241568fe7eSjsing 		/* 32.295 6.2.4.5.2 - Packet Transfer Command. */
13251568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_PACKET_XFER_CMD_LENGTH - 1);
13261568fe7eSjsing 		printf("Packet Transfer Command");
13271afdc05aSdlg 		gtp_print_str(gtp_packet_xfer_cmd, nitems(gtp_packet_xfer_cmd),
13281afdc05aSdlg 		    cp[0]);
13291568fe7eSjsing 		ielen = GTPV1_TV_PACKET_XFER_CMD_LENGTH;
13301568fe7eSjsing 		break;
13311568fe7eSjsing 
13321568fe7eSjsing 	case GTPV1_TV_CHARGING_ID:
13331568fe7eSjsing 
13341568fe7eSjsing 		/* 29.060 7.7.26 - Charging ID. */
13351568fe7eSjsing 		TCHECK2(cp[0], GTPV1_TV_CHARGING_ID_LENGTH - 1);
13361568fe7eSjsing 		dpl = (u_int32_t *)cp;
13371568fe7eSjsing 		printf("Charging ID: %u", ntohl(*dpl));
13381568fe7eSjsing 		ielen = GTPV1_TV_CHARGING_ID_LENGTH;
13391568fe7eSjsing 		break;
13401568fe7eSjsing 
13411568fe7eSjsing 	default:
13421568fe7eSjsing 		printf("TV %u", value);
13431568fe7eSjsing 	}
13441568fe7eSjsing 
13451568fe7eSjsing trunc:
13461568fe7eSjsing 	return ielen;
13471568fe7eSjsing }
13481568fe7eSjsing 
13491568fe7eSjsing int
gtp_v1_print_tlv(const u_char * cp,u_int value)13506ad041cbSmmcc gtp_v1_print_tlv(const u_char *cp, u_int value)
13511568fe7eSjsing {
13521568fe7eSjsing 	u_int8_t data;
13531568fe7eSjsing 	u_int16_t *lenp, *seqno, len;
13541568fe7eSjsing 	int ielen = -1;
13551568fe7eSjsing 
13561568fe7eSjsing 	/* Get length of IE. */
13571568fe7eSjsing 	TCHECK2(cp[0], 2);
13581568fe7eSjsing 	lenp = (u_int16_t *)cp;
13591568fe7eSjsing 	cp += 2;
13601568fe7eSjsing 	len = ntohs(*lenp);
13611568fe7eSjsing 	TCHECK2(cp[0], len);
13621568fe7eSjsing 	ielen = sizeof(data) + sizeof(len) + len;
13631568fe7eSjsing 
13641568fe7eSjsing 	switch (value) {
13651568fe7eSjsing 	case GTPV1_TLV_END_USER_ADDRESS:
13661568fe7eSjsing 
13671568fe7eSjsing 		/* 3GPP 29.060 - 7.7.27 End User Address. */
13681568fe7eSjsing 		printf("End User Address");
13691568fe7eSjsing 		gtp_print_user_address(cp, len);
13701568fe7eSjsing 		break;
13711568fe7eSjsing 
13721568fe7eSjsing 	case GTPV1_TLV_MM_CONTEXT:
13731568fe7eSjsing 
13741568fe7eSjsing 		/* 29.060 7.7.28 - MM Context. */
13751568fe7eSjsing 		printf("MM Context");				/* XXX */
13761568fe7eSjsing 		break;
13771568fe7eSjsing 
13781568fe7eSjsing 	case GTPV1_TLV_PDP_CONTEXT:
13791568fe7eSjsing 
13801568fe7eSjsing 		/* 29.260 7.7.29 - PDP Context. */
13811568fe7eSjsing 		printf("PDP Context");				/* XXX */
13821568fe7eSjsing 		break;
13831568fe7eSjsing 
13841568fe7eSjsing 	case GTPV1_TLV_ACCESS_POINT_NAME:
13851568fe7eSjsing 
13861568fe7eSjsing 		/* 29.060 7.7.30 - Access Point Name. */
138756e8ec8dSjsing 		printf("AP Name: ");
138856e8ec8dSjsing 		gtp_print_apn(cp, len);
13891568fe7eSjsing 		break;
13901568fe7eSjsing 
13911568fe7eSjsing 	case GTPV1_TLV_PROTOCOL_CONFIG_OPTIONS:
13921568fe7eSjsing 
13931568fe7eSjsing 		/* 29.060 7.7.31 - Protocol Configuration Options. */
13941568fe7eSjsing 		/* Defined in 3GPP TS 24.008. */
13951568fe7eSjsing 		printf("Config Options");			/* XXX */
13961568fe7eSjsing 		break;
13971568fe7eSjsing 
13981568fe7eSjsing 	case GTPV1_TLV_GSN_ADDRESS:
13991568fe7eSjsing 
14001568fe7eSjsing 		/* 29.060 7.7.32 - GSN Address. */
14011568fe7eSjsing 		/* Defined in 3GPP TS 23.003. */
14021568fe7eSjsing 		printf("GSN Address");
14031568fe7eSjsing 		if (len == 4)
14041568fe7eSjsing 			printf(": %s", ipaddr_string(cp));
14051568fe7eSjsing 		else if (len == 16)
14061568fe7eSjsing 			printf(": %s", ip6addr_string(cp));
14071568fe7eSjsing 		break;
14081568fe7eSjsing 
14091568fe7eSjsing 	case GTPV1_TLV_MSISDN:
14101568fe7eSjsing 
14111568fe7eSjsing 		/* 29.060 7.7.33 - MS International PSTN/ISDN Number. */
14121568fe7eSjsing 		printf("MSISDN ");
14131568fe7eSjsing 		data = (u_int8_t)cp[0];		/* XXX - Number type. */
14141568fe7eSjsing 		gtp_print_tbcd(cp + 1, len - 1);
14151568fe7eSjsing 		break;
14161568fe7eSjsing 
14171568fe7eSjsing 	case GTPV1_TLV_QOS_PROFILE:
14181568fe7eSjsing 
14191568fe7eSjsing 		/* 29.060 7.7.34 - QoS Profile. */
14201568fe7eSjsing 		/* QoS profile defined in 3GPP TS 24.008 10.5.6.5. */
14211568fe7eSjsing 		printf("QoS Profile: ");
14221568fe7eSjsing 		data = (u_int8_t)cp[0];
14231568fe7eSjsing 		printf("Delay Class %u, ", (data >> 3) & 0x7);
14241568fe7eSjsing 		printf("Reliability Class %u", data & 0x7);
14251568fe7eSjsing 		if (vflag > 1) {
14261568fe7eSjsing 			printf(", ");
14271568fe7eSjsing 			data = (u_int8_t)cp[1];
14281568fe7eSjsing 			printf("Precedence Class %u", data & 0x7);
14291568fe7eSjsing 			/* XXX - Decode more QoS fields. */
14301568fe7eSjsing 		}
14311568fe7eSjsing 		break;
14321568fe7eSjsing 
14331568fe7eSjsing 	case GTPV1_TLV_AUTHENTICATION:
14341568fe7eSjsing 
14351568fe7eSjsing 		/* 29.060 7.7.35 - Authentication. */
14361568fe7eSjsing 		printf("Authentication");			/* XXX */
14371568fe7eSjsing 		break;
14381568fe7eSjsing 
14391568fe7eSjsing 	case GTPV1_TLV_TRAFFIC_FLOW:
14401568fe7eSjsing 
14411568fe7eSjsing 		/* 29.060 7.7.36 - Traffic Flow Template. */
14421568fe7eSjsing 		printf("Traffic Flow Template");		/* XXX */
14431568fe7eSjsing 		break;
14441568fe7eSjsing 
14451568fe7eSjsing 	case GTPV1_TLV_TARGET_IDENTIFICATION:
14461568fe7eSjsing 
14471568fe7eSjsing 		/* 29.060 7.7.37 - Target Identification. */
14481568fe7eSjsing 		printf("Target ID");				/* XXX */
14491568fe7eSjsing 		break;
14501568fe7eSjsing 
14511568fe7eSjsing 	case GTPV1_TLV_UTRAN_CONTAINER:
14521568fe7eSjsing 
14531568fe7eSjsing 		/* 29.060 7.7.38 - UTRAN Transparent Container. */
14541568fe7eSjsing 		printf("UTRAN Container");			/* XXX */
14551568fe7eSjsing 		break;
14561568fe7eSjsing 
14571568fe7eSjsing 	case GTPV1_TLV_RAB_SETUP_INFORMATION:
14581568fe7eSjsing 
14591568fe7eSjsing 		/* 29.060 7.7.39 - RAB Setup Information. */
14601568fe7eSjsing 		printf("RAB Setup");				/* XXX */
14611568fe7eSjsing 		break;
14621568fe7eSjsing 
14631568fe7eSjsing 	case GTPV1_TLV_EXT_HEADER_TYPE_LIST:
14641568fe7eSjsing 
14651568fe7eSjsing 		/* 29.060 7.7.40 - Extension Header Type List. */
14661568fe7eSjsing 		printf("Extension Header List");		/* XXX */
14671568fe7eSjsing 		break;
14681568fe7eSjsing 
14691568fe7eSjsing 	case GTPV1_TLV_TRIGGER_ID:
14701568fe7eSjsing 
14711568fe7eSjsing 		/* 29.060 7.7.41 - Trigger ID. */
14721568fe7eSjsing 		printf("Trigger ID");				/* XXX */
14731568fe7eSjsing 		break;
14741568fe7eSjsing 
14751568fe7eSjsing 	case GTPV1_TLV_OMC_IDENTITY:
14761568fe7eSjsing 
14771568fe7eSjsing 		/* 29.060 7.7.42 - OMC Identity. */
14781568fe7eSjsing 		printf("OMC Identity");				/* XXX */
14791568fe7eSjsing 		break;
14801568fe7eSjsing 
14811568fe7eSjsing 	case GTPV1_TLV_RAN_CONTAINER:
14821568fe7eSjsing 
14831568fe7eSjsing 		/* 29.060 7.7.43 - RAN Transparent Container. */
14841568fe7eSjsing 		printf("RAN Container");			/* XXX */
14851568fe7eSjsing 		break;
14861568fe7eSjsing 
14871568fe7eSjsing 	case GTPV1_TLV_PDP_CONTEXT_PRIORITIZATION:
14881568fe7eSjsing 
14891568fe7eSjsing 		/* 29.060 7.7.45 - PDP Context Prioritization. */
14901568fe7eSjsing 		printf("PDP Context Prioritization");		/* XXX */
14911568fe7eSjsing 		break;
14921568fe7eSjsing 
14931568fe7eSjsing 	case GTPV1_TLV_ADDITIONAL_RAB_SETUP_INFO:
14941568fe7eSjsing 
14951568fe7eSjsing 		/* 29.060 7.7.45A - Additional RAB Setup Information. */
14961568fe7eSjsing 		printf("Additional RAB Setup");			/* XXX */
14971568fe7eSjsing 		break;
14981568fe7eSjsing 
14991568fe7eSjsing 	case GTPV1_TLV_SGSN_NUMBER:
15001568fe7eSjsing 
15011568fe7eSjsing 		/* 29.060 7.7.47 - SGSN Number. */
15021568fe7eSjsing 		printf("SGSN Number");				/* XXX */
15031568fe7eSjsing 		break;
15041568fe7eSjsing 
15051568fe7eSjsing 	case GTPV1_TLV_COMMON_FLAGS:
15061568fe7eSjsing 
15071568fe7eSjsing 		/* 29.060 7.7.48 - Common Flags. */
15081568fe7eSjsing 		printf("Common Flags");				/* XXX */
15091568fe7eSjsing 		break;
15101568fe7eSjsing 
15111568fe7eSjsing 	case GTPV1_TLV_APN_RESTRICTION:
15121568fe7eSjsing 
15131568fe7eSjsing 		/* 29.060 7.7.49 - APN Restriction. */
15141568fe7eSjsing 		data = (u_int8_t)cp[0];
15151568fe7eSjsing 		printf("APN Restriction: %u", data);
15161568fe7eSjsing 		break;
15171568fe7eSjsing 
15181568fe7eSjsing 	case GTPV1_TLV_RADIO_PRIORITY_LCS:
15191568fe7eSjsing 
15201568fe7eSjsing 		/* 29.060 7.7.25B - Radio Priority LCS. */
15211568fe7eSjsing 		printf("Radio Priority LCS: %u", cp[0] & 0x7);
15221568fe7eSjsing 		break;
15231568fe7eSjsing 
15241568fe7eSjsing 	case GTPV1_TLV_RAT_TYPE:
15251568fe7eSjsing 
15261568fe7eSjsing 		/* 29.060 7.7.50 - RAT Type. */
15271568fe7eSjsing 		printf("RAT");
15281afdc05aSdlg 		gtp_print_str(gtp_rat_type, nitems(gtp_rat_type), cp[0]);
15291568fe7eSjsing 		break;
15301568fe7eSjsing 
15311568fe7eSjsing 	case GTPV1_TLV_USER_LOCATION_INFO:
15321568fe7eSjsing 
15331568fe7eSjsing 		/* 29.060 7.7.51 - User Location Information. */
15341568fe7eSjsing 		printf("ULI");					/* XXX */
15351568fe7eSjsing 		break;
15361568fe7eSjsing 
15371568fe7eSjsing 	case GTPV1_TLV_MS_TIME_ZONE:
15381568fe7eSjsing 
15391568fe7eSjsing 		/* 29.060 7.7.52 - MS Time Zone. */
15401568fe7eSjsing 		printf("MSTZ");					/* XXX */
15411568fe7eSjsing 		break;
15421568fe7eSjsing 
15431568fe7eSjsing 	case GTPV1_TLV_IMEI_SV:
15441568fe7eSjsing 
15451568fe7eSjsing 		/* 29.060 7.7.53 - IMEI(SV). */
15461568fe7eSjsing 		printf("IMEI(SV) ");
15471568fe7eSjsing 		gtp_print_tbcd(cp, len);
15481568fe7eSjsing 		break;
15491568fe7eSjsing 
15501568fe7eSjsing 	case GTPV1_TLV_CAMEL_CHARGING_CONTAINER:
15511568fe7eSjsing 
15521568fe7eSjsing 		/* 29.060 7.7.54 - CAMEL Charging Information Container. */
15531568fe7eSjsing 		printf("CAMEL Charging");			/* XXX */
15541568fe7eSjsing 		break;
15551568fe7eSjsing 
15561568fe7eSjsing 	case GTPV1_TLV_MBMS_UE_CONTEXT:
15571568fe7eSjsing 
15581568fe7eSjsing 		/* 29.060 7.7.55 - MBMS UE Context. */
15591568fe7eSjsing 		printf("MBMS UE Context");			/* XXX */
15601568fe7eSjsing 		break;
15611568fe7eSjsing 
15621568fe7eSjsing 	case GTPV1_TLV_TMGI:
15631568fe7eSjsing 
15641568fe7eSjsing 		/* 29.060 7.7.56 - Temporary Mobile Group Identity. */
15651568fe7eSjsing 		printf("TMGI");					/* XXX */
15661568fe7eSjsing 		break;
15671568fe7eSjsing 
15681568fe7eSjsing 	case GTPV1_TLV_RIM_ROUTING_ADDRESS:
15691568fe7eSjsing 
15701568fe7eSjsing 		/* 29.060 7.7.57 - RIM Routing Address. */
15711568fe7eSjsing 		printf("RIM Routing Address");			/* XXX */
15721568fe7eSjsing 		break;
15731568fe7eSjsing 
15741568fe7eSjsing 	case GTPV1_TLV_MBMS_PROTOCOL_CONFIG_OPTIONS:
15751568fe7eSjsing 
15761568fe7eSjsing 		/* 29.060 7.7.58 - MBMS Protocol Configuration Options. */
15771568fe7eSjsing 		printf("MBMS Protocol Config Options");		/* XXX */
15781568fe7eSjsing 		break;
15791568fe7eSjsing 
15801568fe7eSjsing 	case GTPV1_TLV_MBMS_SERVICE_AREA:
15811568fe7eSjsing 
15821568fe7eSjsing 		/* 29.060 7.7.60 - MBMS Service Area. */
15831568fe7eSjsing 		printf("MBMS Service Area");			/* XXX */
15841568fe7eSjsing 		break;
15851568fe7eSjsing 
15861568fe7eSjsing 	case GTPV1_TLV_SOURCE_RNC_PDCP_CONTEXT_INFO:
15871568fe7eSjsing 
15881568fe7eSjsing 		/* 29.060 7.7.61 - Source RNC PDCP Context Information. */
15891568fe7eSjsing 		printf("Source RNC PDCP Context");		/* XXX */
15901568fe7eSjsing 		break;
15911568fe7eSjsing 
15921568fe7eSjsing 	case GTPV1_TLV_ADDITIONAL_TRACE_INFO:
15931568fe7eSjsing 
15941568fe7eSjsing 		/* 29.060 7.7.62 - Additional Trace Information. */
15951568fe7eSjsing 		printf("Additional Trace Info");		/* XXX */
15961568fe7eSjsing 		break;
15971568fe7eSjsing 
15981568fe7eSjsing 	case GTPV1_TLV_HOP_COUNTER:
15991568fe7eSjsing 
16001568fe7eSjsing 		/* 29.060 7.7.63 - Hop Counter. */
16011568fe7eSjsing 		printf("Hop Counter: %u", cp[0]);
16021568fe7eSjsing 		break;
16031568fe7eSjsing 
16041568fe7eSjsing 	case GTPV1_TLV_SELECTED_PLMN_ID:
16051568fe7eSjsing 
16061568fe7eSjsing 		/* 29.060 7.7.64 - Selected PLMN ID. */
16071568fe7eSjsing 		printf("Selected PLMN ID");			/* XXX */
16081568fe7eSjsing 		break;
16091568fe7eSjsing 
16101568fe7eSjsing 	case GTPV1_TLV_MBMS_SESSION_IDENTIFIER:
16111568fe7eSjsing 
16121568fe7eSjsing 		/* 29.060 7.7.65 - MBMS Session Identifier. */
16131568fe7eSjsing 		printf("MBMS Session ID: %u", cp[0]);
16141568fe7eSjsing 		break;
16151568fe7eSjsing 
16161568fe7eSjsing 	case GTPV1_TLV_MBMS_2G_3G_INDICATOR:
16171568fe7eSjsing 
16181568fe7eSjsing 		/* 29.060 7.7.66 - MBMS 2G/3G Indicator. */
16191568fe7eSjsing 		printf("MBMS 2G/3G Indicator");
16201afdc05aSdlg 		gtp_print_str(mbms_2g3g_indicator, nitems(mbms_2g3g_indicator),
16211afdc05aSdlg 		    cp[0]);
16221568fe7eSjsing 		break;
16231568fe7eSjsing 
16241568fe7eSjsing 	case GTPV1_TLV_ENHANCED_NSAPI:
16251568fe7eSjsing 
16261568fe7eSjsing 		/* 29.060 7.7.67 - Enhanced NSAPI. */
16271568fe7eSjsing 		printf("Enhanced NSAPI");			/* XXX */
16281568fe7eSjsing 		break;
16291568fe7eSjsing 
16301568fe7eSjsing 	case GTPV1_TLV_MBMS_SESSION_DURATION:
16311568fe7eSjsing 
16321568fe7eSjsing 		/* 29.060 7.7.59 - MBMS Session Duration. */
16331568fe7eSjsing 		printf("MBMS Session Duration");		/* XXX */
16341568fe7eSjsing 		break;
16351568fe7eSjsing 
16361568fe7eSjsing 	case GTPV1_TLV_ADDITIONAL_MBMS_TRACE_INFO:
16371568fe7eSjsing 
16381568fe7eSjsing 		/* 29.060 7.7.68 - Additional MBMS Trace Info. */
16391568fe7eSjsing 		printf("Additional MBMS Trace Info");		/* XXX */
16401568fe7eSjsing 		break;
16411568fe7eSjsing 
16421568fe7eSjsing 	case GTPV1_TLV_MBMS_SESSION_REPITITION_NO:
16431568fe7eSjsing 
16441568fe7eSjsing 		/* 29.060 7.7.69 - MBMS Session Repetition Number. */
16451568fe7eSjsing 		printf("MBMS Session Repetition No: %u", cp[0]);
16461568fe7eSjsing 		break;
16471568fe7eSjsing 
16481568fe7eSjsing 	case GTPV1_TLV_MBMS_TIME_TO_DATA_TRANSFER:
16491568fe7eSjsing 
16501568fe7eSjsing 		/* 29.060 7.7.70 - MBMS Time to Data Transfer. */
16511568fe7eSjsing 		printf("MBMS Time to Data Transfer: %u", cp[0]);
16521568fe7eSjsing 		break;
16531568fe7eSjsing 
16541568fe7eSjsing 	case GTPV1_TLV_PS_HANDOVER_REQUEST_CONTEXT:
16551568fe7eSjsing 
16561568fe7eSjsing 		/* 29.060 7.7.71 - PS Handover Request Context (Void). */
16571568fe7eSjsing 		break;
16581568fe7eSjsing 
16591568fe7eSjsing 	case GTPV1_TLV_BSS_CONTAINER:
16601568fe7eSjsing 
16611568fe7eSjsing 		/* 29.060 7.7.72 - BSS Container. */
16621568fe7eSjsing 		printf("BSS Container");			/* XXX */
16631568fe7eSjsing 		break;
16641568fe7eSjsing 
16651568fe7eSjsing 	case GTPV1_TLV_CELL_IDENTIFICATION:
16661568fe7eSjsing 
16671568fe7eSjsing 		/* 29.060 7.7.73 - Cell Identification. */
16681568fe7eSjsing 		printf("Cell Identification");			/* XXX */
16691568fe7eSjsing 		break;
16701568fe7eSjsing 
16711568fe7eSjsing 	case GTPV1_TLV_PDU_NUMBERS:
16721568fe7eSjsing 
16731568fe7eSjsing 		/* 29.060 7.7.74 - PDU Numbers. */
16741568fe7eSjsing 		printf("PDU Numbers");				/* XXX */
16751568fe7eSjsing 		break;
16761568fe7eSjsing 
16771568fe7eSjsing 	case GTPV1_TLV_BSSGP_CAUSE:
16781568fe7eSjsing 
16791568fe7eSjsing 		/* 29.060 7.7.75 - BSSGP Cause. */
16801568fe7eSjsing 		printf("BSSGP Cause: %u", cp[0]);
16811568fe7eSjsing 		break;
16821568fe7eSjsing 
16831568fe7eSjsing 	case GTPV1_TLV_REQUIRED_MBMS_BEARER_CAP:
16841568fe7eSjsing 
16851568fe7eSjsing 		/* 29.060 7.7.76 - Required MBMS Bearer Cap. */
16861568fe7eSjsing 		printf("Required MBMS Bearer Cap");		/* XXX */
16871568fe7eSjsing 		break;
16881568fe7eSjsing 
16891568fe7eSjsing 	case GTPV1_TLV_RIM_ROUTING_ADDRESS_DISC:
16901568fe7eSjsing 
16911568fe7eSjsing 		/* 29.060 7.7.77 - RIM Routing Address Discriminator. */
16921568fe7eSjsing 		printf("RIM Routing Address Discriminator: %u", cp[0] & 0xf);
16931568fe7eSjsing 		break;
16941568fe7eSjsing 
16951568fe7eSjsing 	case GTPV1_TLV_LIST_OF_SETUP_PFCS:
16961568fe7eSjsing 
16971568fe7eSjsing 		/* 29.060 7.7.78 - List of Setup PFCs. */
16981568fe7eSjsing 		printf("List of Setup PFCs");			/* XXX */
16991568fe7eSjsing 		break;
17001568fe7eSjsing 
17011568fe7eSjsing 	case GTPV1_TLV_PS_HANDOVER_XID_PARAMETERS:
17021568fe7eSjsing 
17031568fe7eSjsing 		/* 29.060 7.7.79 - PS Handover XID Parameters. */
17041568fe7eSjsing 		printf("PS Handover XID Parameters");		/* XXX */
17051568fe7eSjsing 		break;
17061568fe7eSjsing 
17071568fe7eSjsing 	case GTPV1_TLV_MS_INFO_CHANGE_REPORTING:
17081568fe7eSjsing 
17091568fe7eSjsing 		/* 29.060 7.7.80 - MS Info Change Reporting. */
17101568fe7eSjsing 		printf("MS Info Change Reporting");
17111afdc05aSdlg 		gtp_print_str(ms_info_change_rpt, nitems(ms_info_change_rpt),
17121afdc05aSdlg 		    cp[0]);
17131568fe7eSjsing 		break;
17141568fe7eSjsing 
17151568fe7eSjsing 	case GTPV1_TLV_DIRECT_TUNNEL_FLAGS:
17161568fe7eSjsing 
17171568fe7eSjsing 		/* 29.060 7.7.81 - Direct Tunnel Flags. */
17181568fe7eSjsing 		printf("Direct Tunnel Flags");			/* XXX */
17191568fe7eSjsing 		break;
17201568fe7eSjsing 
17211568fe7eSjsing 	case GTPV1_TLV_CORRELATION_ID:
17221568fe7eSjsing 
17231568fe7eSjsing 		/* 29.060 7.7.82 - Correlation ID. */
17241568fe7eSjsing 		printf("Correlation ID");			/* XXX */
17251568fe7eSjsing 		break;
17261568fe7eSjsing 
17271568fe7eSjsing 	case GTPV1_TLV_BEARER_CONTROL_MODE:
17281568fe7eSjsing 
17291568fe7eSjsing 		/* 29.060 7.7.83 - Bearer Control Mode. */
17301568fe7eSjsing 		printf("Bearer Control Mode");			/* XXX */
17311568fe7eSjsing 		break;
17321568fe7eSjsing 
17331568fe7eSjsing 	case GTPV1_TLV_MBMS_FLOW_IDENTIFIER:
17341568fe7eSjsing 
17351568fe7eSjsing 		/* 29.060 7.7.84 - MBMS Flow Identifier. */
17361568fe7eSjsing 		printf("MBMS Flow Identifier");			/* XXX */
17371568fe7eSjsing 		break;
17381568fe7eSjsing 
17391568fe7eSjsing 	case GTPV1_TLV_RELEASED_PACKETS:
17401568fe7eSjsing 
17411568fe7eSjsing 		/* 32.295 6.2.4.5.4 - Sequence Numbers of Released Packets. */
17421568fe7eSjsing 		printf("Released Packets:");
17431568fe7eSjsing 		seqno = (u_int16_t *)cp;
17441568fe7eSjsing 		while (len > 0) {
17451568fe7eSjsing 			printf(" %u", ntohs(*seqno));
17461568fe7eSjsing 			seqno++;
17471568fe7eSjsing 			len -= sizeof(*seqno);
17481568fe7eSjsing 		}
17491568fe7eSjsing 		break;
17501568fe7eSjsing 
17511568fe7eSjsing 	case GTPV1_TLV_CANCELLED_PACKETS:
17521568fe7eSjsing 
17531568fe7eSjsing 		/* 32.295 6.2.4.5.5 - Sequence Numbers of Cancelled Packets. */
17541568fe7eSjsing 		printf("Cancelled Packets:");
17551568fe7eSjsing 		seqno = (u_int16_t *)cp;
17561568fe7eSjsing 		while (len > 0) {
17571568fe7eSjsing 			printf(" %u", ntohs(*seqno));
17581568fe7eSjsing 			seqno++;
17591568fe7eSjsing 			len -= sizeof(*seqno);
17601568fe7eSjsing 		}
17611568fe7eSjsing 		break;
17621568fe7eSjsing 
17631568fe7eSjsing 	case GTPV1_TLV_CHARGING_GATEWAY_ADDRESS:
17641568fe7eSjsing 
17651568fe7eSjsing 		/* 29.060 7.7.44 - Charging Gateway Address. */
17661568fe7eSjsing 		printf("Charging Gateway");
17671568fe7eSjsing 		if (len == 4)
17681568fe7eSjsing 			printf(": %s", ipaddr_string(cp));
17691568fe7eSjsing 		else if (len == 16)
17701568fe7eSjsing 			printf(": %s", ip6addr_string(cp));
17711568fe7eSjsing 		break;
17721568fe7eSjsing 
17731568fe7eSjsing 	case GTPV1_TLV_DATA_RECORD_PACKET:
17741568fe7eSjsing 
17751568fe7eSjsing 		/* 32.295 6.2.4.5.3 - Data Record Packet. */
17761568fe7eSjsing 		printf("Data Record: Records %u, Format %u, Format Version %u",
17771568fe7eSjsing 		    cp[0], cp[1], ntohs(*(u_int16_t *)(cp + 2)));
17781568fe7eSjsing 		break;
17791568fe7eSjsing 
17801568fe7eSjsing 	case GTPV1_TLV_REQUESTS_RESPONDED:
17811568fe7eSjsing 
17821568fe7eSjsing 		/* 32.295 6.2.4.6 - Requests Responded. */
17831568fe7eSjsing 		printf("Requests Responded:");
17841568fe7eSjsing 		seqno = (u_int16_t *)cp;
17851568fe7eSjsing 		while (len > 0) {
17861568fe7eSjsing 			printf(" %u", ntohs(*seqno));
17871568fe7eSjsing 			seqno++;
17881568fe7eSjsing 			len -= sizeof(*seqno);
17891568fe7eSjsing 		}
17901568fe7eSjsing 		break;
17911568fe7eSjsing 
17921568fe7eSjsing 	case GTPV1_TLV_ADDRESS_OF_RECOMMENDED_NODE:
17931568fe7eSjsing 
17941568fe7eSjsing 		/* 32.295 6.2.4.3 - Address of Recommended Node. */
17951568fe7eSjsing 		printf("Address of Recommended Node");
17961568fe7eSjsing 		if (len == 4)
17971568fe7eSjsing 			printf(": %s", ipaddr_string(cp));
17981568fe7eSjsing 		else if (len == 16)
17991568fe7eSjsing 			printf(": %s", ip6addr_string(cp));
18001568fe7eSjsing 		break;
18011568fe7eSjsing 
18021568fe7eSjsing 	case GTPV1_TLV_PRIVATE_EXTENSION:
18031568fe7eSjsing 
18041568fe7eSjsing 		/* 29.060 7.7.46 - Private Extension. */
18051568fe7eSjsing 		printf("Private Extension");
18061568fe7eSjsing 		break;
18071568fe7eSjsing 
18081568fe7eSjsing 	default:
18091568fe7eSjsing 		printf("TLV %u (len %u)", value, len);
18101568fe7eSjsing 	}
18111568fe7eSjsing 
18121568fe7eSjsing 	return ielen;
18131568fe7eSjsing 
18141568fe7eSjsing trunc:
18151568fe7eSjsing 	return -1;
18161568fe7eSjsing }
1817