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