aboutsummaryrefslogtreecommitdiffstats
path: root/packet-gsm_a.c
diff options
context:
space:
mode:
Diffstat (limited to 'packet-gsm_a.c')
-rw-r--r--packet-gsm_a.c9780
1 files changed, 9780 insertions, 0 deletions
diff --git a/packet-gsm_a.c b/packet-gsm_a.c
new file mode 100644
index 0000000000..6dcf479621
--- /dev/null
+++ b/packet-gsm_a.c
@@ -0,0 +1,9780 @@
+/* packet-gsm_a.c
+ * Routines for GSM A Interface (BSSMAP/DTAP) dissection
+ *
+ * Copyright 2003, Michael Lum <mlum [AT] telostech.com>
+ * In association with Telos Technology Inc.
+ *
+ * Title 3GPP Other
+ *
+ * Reference [1]
+ * Mobile radio interface signalling layer 3;
+ * General Aspects
+ * (3GPP TS 24.007 version 3.9.0 Release 1999)
+ *
+ * Reference [2]
+ * Mobile-services Switching Centre - Base Station System
+ * (MSC - BSS) interface;
+ * Layer 3 specification
+ * (GSM 08.08 version 7.7.0 Release 1998) TS 100 590 v7.7.0
+ *
+ * Reference [3]
+ * Mobile radio interface Layer 3 specification;
+ * Core network protocols;
+ * Stage 3
+ * (3GPP TS 24.008 version 4.7.0 Release 4)
+ *
+ * Reference [4]
+ * Mobile radio interface layer 3 specification;
+ * Radio Resource Control Protocol
+ * (GSM 04.18 version 8.4.1 Release 1999)
+ *
+ * Reference [5]
+ * Point-to-Point (PP) Short Message Service (SMS)
+ * support on mobile radio interface
+ * (3GPP TS 24.011 version 4.1.1 Release 4)
+ *
+ * Reference [6]
+ * Mobile radio Layer 3 supplementary service specification;
+ * Formats and coding
+ * (3GPP TS 24.080 version 4.3.0 Release 4)
+ *
+ * $Id: packet-gsm_a.c,v 1.1 2003/10/30 07:00:18 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gmodule.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <string.h>
+
+#include "epan/packet.h"
+#include "prefs.h"
+
+#include "packet-bssap.h"
+
+/* PROTOTYPES/FORWARDS */
+
+static void (*dtap_msg_rr_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len);
+
+static const value_string gsm_bssmap_msg_strings[] = {
+ { 0x01, "Assignment Request" },
+ { 0x02, "Assignment Complete" },
+ { 0x03, "Assignment Failure" },
+ { 0x10, "Handover Request" },
+ { 0x11, "Handover Required" },
+ { 0x12, "Handover Request Acknowledge" },
+ { 0x13, "Handover Command" },
+ { 0x14, "Handover Complete" },
+ { 0x15, "Handover Succeeded" },
+ { 0x16, "Handover Failure" },
+ { 0x17, "Handover Performed" },
+ { 0x18, "Handover Candidate Enquire" },
+ { 0x19, "Handover Candidate Response" },
+ { 0x1a, "Handover Required Reject" },
+ { 0x1b, "Handover Detect" },
+ { 0x20, "Clear Command" },
+ { 0x21, "Clear Complete" },
+ { 0x22, "Clear Request" },
+ { 0x23, "Reserved" },
+ { 0x24, "Reserved" },
+ { 0x25, "SAPI 'n' Reject" },
+ { 0x26, "Confusion" },
+ { 0x28, "Suspend" },
+ { 0x29, "Resume" },
+ { 0x2a, "Connection Oriented Information" },
+ { 0x2b, "Perform Location Request" },
+ { 0x2c, "LSA Information" },
+ { 0x2d, "Perform Location Response" },
+ { 0x2e, "Perform Location Abort" },
+ { 0x30, "Reset" },
+ { 0x31, "Reset Acknowledge" },
+ { 0x32, "Overload" },
+ { 0x33, "Reserved" },
+ { 0x34, "Reset Circuit" },
+ { 0x35, "Reset Circuit Acknowledge" },
+ { 0x36, "MSC Invoke Trace" },
+ { 0x37, "BSS Invoke Trace" },
+ { 0x3a, "Connectionless Information" },
+ { 0x40, "Block" },
+ { 0x41, "Blocking Acknowledge" },
+ { 0x42, "Unblock" },
+ { 0x43, "Unblocking Acknowledge" },
+ { 0x44, "Circuit Group Block" },
+ { 0x45, "Circuit Group Blocking Acknowledge" },
+ { 0x46, "Circuit Group Unblock" },
+ { 0x47, "Circuit Group Unblocking Acknowledge" },
+ { 0x48, "Unequipped Circuit" },
+ { 0x4e, "Change Circuit" },
+ { 0x4f, "Change Circuit Acknowledge" },
+ { 0x50, "Resource Request" },
+ { 0x51, "Resource Indication" },
+ { 0x52, "Paging" },
+ { 0x53, "Cipher Mode Command" },
+ { 0x54, "Classmark Update" },
+ { 0x55, "Cipher Mode Complete" },
+ { 0x56, "Queuing Indication" },
+ { 0x57, "Complete Layer 3 Information" },
+ { 0x58, "Classmark Request" },
+ { 0x59, "Cipher Mode Reject" },
+ { 0x5a, "Load Indication" },
+ { 0x04, "VGCS/VBS Setup" },
+ { 0x05, "VGCS/VBS Setup Ack" },
+ { 0x06, "VGCS/VBS Setup Refuse" },
+ { 0x07, "VGCS/VBS Assignment Request" },
+ { 0x1c, "VGCS/VBS Assignment Result" },
+ { 0x1d, "VGCS/VBS Assignment Failure" },
+ { 0x1e, "VGCS/VBS Queuing Indication" },
+ { 0x1f, "Uplink Request" },
+ { 0x27, "Uplink Request Acknowledge" },
+ { 0x49, "Uplink Request Confirmation" },
+ { 0x4a, "Uplink Release Indication" },
+ { 0x4b, "Uplink Reject Command" },
+ { 0x4c, "Uplink Release Command" },
+ { 0x4d, "Uplink Seized Command" },
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_msg_mm_strings[] = {
+ { 0x01, "IMSI Detach Indication" },
+ { 0x02, "Location Updating Accept" },
+ { 0x04, "Location Updating Reject" },
+ { 0x08, "Location Updating Request" },
+ { 0x11, "Authentication Reject" },
+ { 0x12, "Authentication Request" },
+ { 0x14, "Authentication Response" },
+ { 0x1c, "Authentication Failure" },
+ { 0x18, "Identity Request" },
+ { 0x19, "Identity Response" },
+ { 0x1a, "TMSI Reallocation Command" },
+ { 0x1b, "TMSI Reallocation Complete" },
+ { 0x21, "CM Service Accept" },
+ { 0x22, "CM Service Reject" },
+ { 0x23, "CM Service Abort" },
+ { 0x24, "CM Service Request" },
+ { 0x25, "CM Service Prompt" },
+ { 0x26, "Reserved: was allocated in earlier phases of the protocol" },
+ { 0x28, "CM Re-establishment Request" },
+ { 0x29, "Abort" },
+ { 0x30, "MM Null" },
+ { 0x31, "MM Status" },
+ { 0x32, "MM Information" },
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_msg_rr_strings[] = {
+ { 0x3c, "RR Initialisation Request" },
+ { 0x3b, "Additional Assignment" },
+ { 0x3f, "Immediate Assignment" },
+ { 0x39, "Immediate Assignment Extended" },
+ { 0x3a, "Immediate Assignment Reject" },
+
+ { 0x48, "DTM Assignment Failure" },
+ { 0x49, "DTM Reject" },
+ { 0x4a, "DTM Request" },
+ { 0x4b, "Main DCCH Assignment Command" },
+ { 0x4c, "Packet Assignment Command" },
+
+ { 0x35, "Ciphering Mode Command" },
+ { 0x32, "Ciphering Mode Complete" },
+
+ { 0x30, "Configuration Change Command" },
+ { 0x31, "Configuration Change Ack." },
+ { 0x33, "Configuration Change Reject" },
+
+ { 0x2e, "Assignment Command" },
+ { 0x29, "Assignment Complete" },
+ { 0x2f, "Assignment Failure" },
+ { 0x2b, "Handover Command" },
+ { 0x2c, "Handover Complete" },
+ { 0x28, "Handover Failure" },
+ { 0x2d, "Physical Information" },
+ { 0x4d, "DTM Assignment Command" },
+
+ { 0x08, "RR-cell Change Order" },
+ { 0x23, "PDCH Assignment Command" },
+
+ { 0x0d, "Channel Release" },
+ { 0x0a, "Partial Release" },
+ { 0x0f, "Partial Release Complete" },
+
+ { 0x21, "Paging Request Type 1" },
+ { 0x22, "Paging Request Type 2" },
+ { 0x24, "Paging Request Type 3" },
+ { 0x27, "Paging Response" },
+ { 0x20, "Notification/NCH" },
+ { 0x25, "Reserved" },
+ { 0x26, "Notification/Response" },
+
+ { 0x0b, "Reserved" },
+
+/* { 0xc0, "Utran Classmark Change" }, CONFLICTS WITH Handover To UTRAN Command */
+ { 0xc1, "UE RAB Preconfiguration" },
+ { 0xc2, "cdma2000 Classmark Change" },
+
+ { 0x18, "System Information Type 8" },
+ { 0x19, "System Information Type 1" },
+ { 0x1a, "System Information Type 2" },
+ { 0x1b, "System Information Type 3" },
+ { 0x1c, "System Information Type 4" },
+ { 0x1d, "System Information Type 5" },
+ { 0x1e, "System Information Type 6" },
+ { 0x1f, "System Information Type 7" },
+
+ { 0x02, "System Information Type 2bis" },
+ { 0x03, "System Information Type 2ter" },
+ { 0x07, "System Information Type 2quater" },
+ { 0x05, "System Information Type 5bis" },
+ { 0x06, "System Information Type 5ter" },
+ { 0x04, "System Information Type 9" },
+ { 0x00, "System Information Type 13" },
+
+ { 0x3d, "System Information Type 16" },
+ { 0x3e, "System Information Type 17" },
+
+ { 0x40, "System Information Type 18" },
+ { 0x41, "System Information Type 19" },
+ { 0x42, "System Information Type 20" },
+
+ { 0x10, "Channel Mode Modify" },
+ { 0x12, "RR Status" },
+ { 0x17, "Channel Mode Modify Acknowledge" },
+ { 0x14, "Frequency Redefinition" },
+ { 0x15, "Measurement Report" },
+ { 0x16, "Classmark Change" },
+ { 0x13, "Classmark Enquiry" },
+ { 0x36, "Extended Measurement Report" },
+ { 0x37, "Extended Measurement Order" },
+ { 0x34, "GPRS Suspension Request" },
+
+ { 0x09, "VGCS Uplink Grant" },
+ { 0x0e, "Uplink Release" },
+ { 0x0c, "Reserved" },
+ { 0x2a, "Uplink Busy" },
+ { 0x11, "Talker Indication" },
+
+ { 0xc0, "UTRAN Classmark Change/Handover To UTRAN Command" }, /* spec conflict */
+
+ { 0x38, "Application Information" },
+
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_msg_cc_strings[] = {
+ { 0x01, "Alerting" },
+ { 0x08, "Call Confirmed" },
+ { 0x02, "Call Proceeding" },
+ { 0x07, "Connect" },
+ { 0x0f, "Connect Acknowledge" },
+ { 0x0e, "Emergency Setup" },
+ { 0x03, "Progress" },
+ { 0x04, "CC-Establishment" },
+ { 0x06, "CC-Establishment Confirmed" },
+ { 0x0b, "Recall" },
+ { 0x09, "Start CC" },
+ { 0x05, "Setup" },
+ { 0x17, "Modify" },
+ { 0x1f, "Modify Complete" },
+ { 0x13, "Modify Reject" },
+ { 0x10, "User Information" },
+ { 0x18, "Hold" },
+ { 0x19, "Hold Acknowledge" },
+ { 0x1a, "Hold Reject" },
+ { 0x1c, "Retrieve" },
+ { 0x1d, "Retrieve Acknowledge" },
+ { 0x1e, "Retrieve Reject" },
+ { 0x25, "Disconnect" },
+ { 0x2d, "Release" },
+ { 0x2a, "Release Complete" },
+ { 0x39, "Congestion Control" },
+ { 0x3e, "Notify" },
+ { 0x3d, "Status" },
+ { 0x34, "Status Enquiry" },
+ { 0x35, "Start DTMF" },
+ { 0x31, "Stop DTMF" },
+ { 0x32, "Stop DTMF Acknowledge" },
+ { 0x36, "Start DTMF Acknowledge" },
+ { 0x37, "Start DTMF Reject" },
+ { 0x3a, "Facility" },
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_msg_gmm_strings[] = {
+ { 0x01, "Attach Request" },
+ { 0x02, "Attach Accept" },
+ { 0x03, "Attach Complete" },
+ { 0x04, "Attach Reject" },
+ { 0x05, "Detach Request" },
+ { 0x06, "Detach Accept" },
+ { 0x08, "Routing Area Update Request" },
+ { 0x09, "Routing Area Update Accept" },
+ { 0x0a, "Routing Area Update Complete" },
+ { 0x0b, "Routing Area Update Reject" },
+ { 0x0c, "Service Request" },
+ { 0x0d, "Service Accept" },
+ { 0x0e, "Service Reject" },
+ { 0x10, "P-TMSI Reallocation Command" },
+ { 0x11, "P-TMSI Reallocation Complete" },
+ { 0x12, "Authentication and Ciphering Req" },
+ { 0x13, "Authentication and Ciphering Resp" },
+ { 0x14, "Authentication and Ciphering Rej" },
+ { 0x1c, "Authentication and Ciphering Failure" },
+ { 0x15, "Identity Request" },
+ { 0x16, "Identity Response" },
+ { 0x20, "GMM Status" },
+ { 0x21, "GMM Information" },
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_msg_sms_strings[] = {
+ { 0x01, "CP-DATA" },
+ { 0x04, "CP-ACK" },
+ { 0x10, "CP-ERROR" },
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_msg_sm_strings[] = {
+ { 0x41, "Activate PDP Context Request" },
+ { 0x42, "Activate PDP Context Accept" },
+ { 0x43, "Activate PDP Context Reject" },
+ { 0x44, "Request PDP Context Activation" },
+ { 0x45, "Request PDP Context Activation rej." },
+ { 0x46, "Deactivate PDP Context Request" },
+ { 0x47, "Deactivate PDP Context Accept" },
+ { 0x48, "Modify PDP Context Request(Network to MS direction)" },
+ { 0x49, "Modify PDP Context Accept (MS to network direction)" },
+ { 0x4a, "Modify PDP Context Request(MS to network direction)" },
+ { 0x4b, "Modify PDP Context Accept (Network to MS direction)" },
+ { 0x4c, "Modify PDP Context Reject" },
+ { 0x4d, "Activate Secondary PDP Context Request" },
+ { 0x4e, "Activate Secondary PDP Context Accept" },
+ { 0x4f, "Activate Secondary PDP Context Reject" },
+ { 0x50, "Reserved: was allocated in earlier phases of the protocol" },
+ { 0x51, "Reserved: was allocated in earlier phases of the protocol" },
+ { 0x52, "Reserved: was allocated in earlier phases of the protocol" },
+ { 0x53, "Reserved: was allocated in earlier phases of the protocol" },
+ { 0x54, "Reserved: was allocated in earlier phases of the protocol" },
+ { 0x55, "SM Status" },
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_msg_ss_strings[] = {
+ { 0x2a, "Release Complete" },
+ { 0x3a, "Facility" },
+ { 0x3b, "Register" },
+ { 0, NULL },
+};
+
+static const value_string gsm_rp_msg_strings[] = {
+ { 0x00, "RP-DATA (MS to Network)" },
+ { 0x01, "RP-DATA (Network to MS)" },
+ { 0x02, "RP-ACK (MS to Network)" },
+ { 0x03, "RP-ACK (Network to MS)" },
+ { 0x04, "RP-ERROR (MS to Network)" },
+ { 0x05, "RP-ERROR (Network to MS)" },
+ { 0x06, "RP-SMMA (MS to Network)" },
+ { 0, NULL },
+};
+
+static const value_string gsm_bssmap_elem_strings[] = {
+ { 0x01, "Circuit Identity Code" },
+ { 0x02, "Reserved" },
+ { 0x03, "Resource Available" },
+ { 0x04, "Cause" },
+ { 0x05, "Cell Identifier" },
+ { 0x06, "Priority" },
+ { 0x07, "Layer 3 Header Information" },
+ { 0x08, "IMSI" },
+ { 0x09, "TMSI" },
+ { 0x0a, "Encryption Information" },
+ { 0x0b, "Channel Type" },
+ { 0x0c, "Periodicity" },
+ { 0x0d, "Extended Resource Indicator" },
+ { 0x0e, "Number Of MSs" },
+ { 0x0f, "Reserved" },
+ { 0x10, "Reserved" },
+ { 0x11, "Reserved" },
+ { 0x12, "Classmark Information Type 2" },
+ { 0x13, "Classmark Information Type 3" },
+ { 0x14, "Interference Band To Be Used" },
+ { 0x15, "RR Cause" },
+ { 0x16, "Reserved" },
+ { 0x17, "Layer 3 Information" },
+ { 0x18, "DLCI" },
+ { 0x19, "Downlink DTX Flag" },
+ { 0x1a, "Cell Identifier List" },
+ { 0x1b, "Response Request" },
+ { 0x1c, "Resource Indication Method" },
+ { 0x1d, "Classmark Information Type 1" },
+ { 0x1e, "Circuit Identity Code List" },
+ { 0x1f, "Diagnostic" },
+ { 0x20, "Layer 3 Message Contents" },
+ { 0x21, "Chosen Channel" },
+ { 0x22, "Total Resource Accessible" },
+ { 0x23, "Cipher Response Mode" },
+ { 0x24, "Channel Needed" },
+ { 0x25, "Trace Type" },
+ { 0x26, "TriggerID" },
+ { 0x27, "Trace Reference" },
+ { 0x28, "TransactionID" },
+ { 0x29, "Mobile Identity" },
+ { 0x2a, "OMCID" },
+ { 0x2b, "Forward Indicator" },
+ { 0x2c, "Chosen Encryption Algorithm" },
+ { 0x2d, "Circuit Pool" },
+ { 0x2e, "Circuit Pool List" },
+ { 0x2f, "Time Indication" },
+ { 0x30, "Resource Situation" },
+ { 0x31, "Current Channel Type 1" },
+ { 0x32, "Queueing Indicator" },
+ { 0x40, "Speech Version" },
+ { 0x33, "Assignment Requirement" },
+ { 0x35, "Talker Flag" },
+ { 0x36, "Connection Release Requested" },
+ { 0x37, "Group Call Reference" },
+ { 0x38, "eMLPP Priority" },
+ { 0x39, "Configuration Evolution Indication" },
+ { 0x3a, "Old BSS to New BSS Information" },
+ { 0x3b, "LSA Identifier" },
+ { 0x3c, "LSA Identifier List" },
+ { 0x3d, "LSA Information" },
+ { 0x3e, "LCS QoS" },
+ { 0x3f, "LSA access control suppression" },
+ { 0x43, "LCS Priority" },
+ { 0x44, "Location Type" },
+ { 0x45, "Location Estimate" },
+ { 0x46, "Positioning Data" },
+ { 0x47, "LCS Cause" },
+ { 0x48, "LCS Client Type" },
+ { 0x49, "APDU" },
+ { 0x4a, "Network Element Identity" },
+ { 0x4b, "GPS Assistance Data" },
+ { 0x4c, "Deciphering Keys" },
+ { 0x4d, "Return Error Request" },
+ { 0x4e, "Return Error Cause" },
+ { 0x4f, "Segmentation" },
+ { 0, NULL },
+};
+
+static const value_string gsm_dtap_elem_strings[] = {
+ /* Common Information Elements 10.5.1 */
+ { 0x00, "Cell Identity" },
+ { 0x00, "Ciphering Key Sequence Number" },
+ { 0x00, "Location Area Identification" },
+ { 0x00, "Mobile Identity" },
+ { 0x00, "Mobile Station Classmark 1" },
+ { 0x00, "Mobile Station Classmark 2" },
+ { 0x00, "Mobile Station Classmark 3" },
+ { 0x00, "Descriptive group or broadcast call reference" },
+ { 0x00, "Group Cipher Key Number" },
+ { 0x00, "PD and SAPI $(CCBS)$" },
+ { 0x00, "Priority Level" },
+ { 0x00, "PLMN List" },
+ /* Radio Resource Management Information Elements 10.5.2, most are from 10.5.1 */
+ { 0x00, "RR Cause" },
+ /* Mobility Management Information Elements 10.5.3 */
+ { 0x00, "Authentication Parameter RAND" },
+ { 0x00, "Authentication Parameter AUTN (UMTS authentication challenge only)" },
+ { 0x00, "Authentication Response Parameter" },
+ { 0x00, "Authentication Response Parameter (extension) (UMTS authentication challenge only)" },
+ { 0x00, "Authentication Failure Parameter (UMTS authentication challenge only)" },
+ { 0x00, "CM Service Type" },
+ { 0x00, "Identity Type" },
+ { 0x00, "Location Updating Type" },
+ { 0x00, "Network Name" },
+ { 0x00, "Reject Cause" },
+ { 0x00, "Follow-on Proceed" },
+ { 0x00, "Time Zone" },
+ { 0x00, "Time Zone and Time" },
+ { 0x00, "CTS Permission" },
+ { 0x00, "LSA Identifier" },
+ { 0x00, "Daylight Saving Time" },
+ /* Call Control Information Elements 10.5.4 */
+ { 0x00, "Auxiliary States" },
+ { 0x00, "Bearer Capability" },
+ { 0x00, "Call Control Capabilities" },
+ { 0x00, "Call State" },
+ { 0x00, "Called Party BCD Number" },
+ { 0x00, "Called Party Subaddress" },
+ { 0x00, "Calling Party BCD Number" },
+ { 0x00, "Calling Party Subaddress" },
+ { 0x00, "Cause" },
+ { 0x00, "CLIR Suppression" },
+ { 0x00, "CLIR Invocation" },
+ { 0x00, "Congestion Level" },
+ { 0x00, "Connected Number" },
+ { 0x00, "Connected Subaddress" },
+ { 0x00, "Facility" },
+ { 0x00, "High Layer Compatibility" },
+ { 0x00, "Keypad Facility" },
+ { 0x00, "Low Layer Compatibility" },
+ { 0x00, "More Data" },
+ { 0x00, "Notification Indicator" },
+ { 0x00, "Progress Indicator" },
+ { 0x00, "Recall type $(CCBS)$" },
+ { 0x00, "Redirecting Party BCD Number" },
+ { 0x00, "Redirecting Party Subaddress" },
+ { 0x00, "Repeat Indicator" },
+ { 0x00, "Reverse Call Setup Direction" },
+ { 0x00, "SETUP Container $(CCBS)$" },
+ { 0x00, "Signal" },
+ { 0x00, "SS Version Indicator" },
+ { 0x00, "User-user" },
+ { 0x00, "Alerting Pattern $(NIA)$" },
+ { 0x00, "Allowed Actions $(CCBS)$" },
+ { 0x00, "Stream Identifier" },
+ { 0x00, "Network Call Control Capabilities" },
+ { 0x00, "Cause of No CLI" },
+ { 0x00, "Immediate Modification Indicator" },
+ { 0x00, "Supported Codec List" },
+ { 0x00, "Service Category" },
+ /* GPRS Mobility Management Information Elements 10.5.5 */
+ { 0x00, "Attach Result" },
+ { 0x00, "Attach Type" },
+ { 0x00, "TMSI Status" },
+ { 0x00, "Detach Type" },
+ { 0x00, "DRX Parameter" },
+ { 0x00, "Force to Standby" },
+ { 0x00, "P-TMSI Signature" },
+ { 0x00, "P-TMSI Signature 2" },
+ { 0x00, "Identity Type 2" },
+ { 0x00, "IMEISV Request" },
+ { 0x00, "Receive N-PDU Numbers List" },
+ { 0x00, "MS Network Capability" },
+ { 0x00, "MS Radio Access Capability" },
+ { 0x00, "GMM Cause" },
+ { 0x00, "Routing Area Identification" },
+ { 0x00, "Update Result" },
+ { 0x00, "A&C Reference Number" },
+ { 0x00, "Service Type" },
+ { 0x00, "Cell Notification" },
+ { 0x00, "Network Feature Support" },
+ /* Short Message Service Information Elements [5] 8.1.4 */
+ { 0x00, "CP-User Data" },
+ { 0x00, "CP-Cause" },
+ /* Short Message Service Information Elements [5] 8.2 */
+ { 0x00, "RP-Message Reference" },
+ { 0x00, "RP-Origination Address" },
+ { 0x00, "RP-Destination Address" },
+ { 0x00, "RP-User Data" },
+ { 0x00, "RP-Cause" },
+ /* Session Management Information Elements 10.5.6 */
+ { 0x00, "Access Point Name" },
+ { 0x00, "Network Service Access Point Identifier" },
+ { 0x00, "Protocol Configuration Options" },
+ { 0x00, "Packet Data Protocol Address" },
+ { 0x00, "Quality Of Service" },
+ { 0x00, "SM Cause" },
+ { 0x00, "Linked TI" },
+ { 0x00, "LLC Service Access Point Identifier" },
+ { 0x00, "Tear Down Indicator" },
+ { 0x00, "Packet Flow Identifier" },
+ { 0x00, "Traffic Flow Template" },
+ /* GPRS Common Information Elements 10.5.7 */
+ { 0x00, "PDP Context Status" },
+ { 0x00, "Radio Priority" },
+ { 0x00, "GPRS Timer" },
+ { 0x00, "GPRS Timer 2" },
+ { 0, NULL },
+};
+
+static const gchar *pd_str[] = {
+ "Group Call Control",
+ "Broadcast Call Control",
+ "Reserved: was allocated in earlier phases of the protocol",
+ "Call Control; call related SS messages",
+ "GPRS Transparent Transport Protocol (GTTP)",
+ "Mobility Management messages",
+ "Radio Resources Management messages",
+ "Unknown",
+ "GPRS Mobility Management messages",
+ "SMS messages",
+ "GPRS Session Management messages",
+ "Non call related SS messages",
+ "Location Services",
+ "Unknown",
+ "Reserved for extension of the PD to one octet length",
+ "Reserved for tests procedures"
+};
+
+static const value_string bssap_cc_values[] = {
+ { 0x00, "not further specified" },
+ { 0x80, "FACCH or SDCCH" },
+ { 0xc0, "SACCH" },
+ { 0, NULL } };
+
+static const value_string bssap_sapi_values[] = {
+ { 0x00, "RR/MM/CC" },
+ { 0x03, "SMS" },
+ { 0, NULL } };
+
+static const gchar *cell_disc_str[] = {
+ "The whole Cell Global Identification, CGI, is used to identify the cells",
+ "Location Area Code, LAC, and Cell Identify, CI, is used to identify the cells",
+ "Cell Identity, CI, is used to identify the cells",
+ "No cell is associated with the transaction",
+ "Location Area Identification, LAI, is used to identify all cells within a Location Area",
+ "Location Area Code, LAC, is used to identify all cells within a location area",
+ "All cells on the BSS are identified"
+};
+#define NUM_CELL_DISC_STR (sizeof(cell_disc_str)/sizeof(gchar *))
+
+#define DTAP_PD_MASK 0x0f
+#define DTAP_SKIP_MASK 0xf0
+#define DTAP_TI_MASK DTAP_SKIP_MASK
+#define DTAP_TIE_PRES_MASK 0x07 /* after TI shifted to right */
+#define DTAP_TIE_MASK 0x7f
+
+#define DTAP_MM_IEI_MASK 0x3f
+#define DTAP_RR_IEI_MASK 0xff
+#define DTAP_CC_IEI_MASK 0x3f
+#define DTAP_GMM_IEI_MASK 0xff
+#define DTAP_SMS_IEI_MASK 0xff
+#define DTAP_SM_IEI_MASK 0xff
+#define DTAP_SS_IEI_MASK 0x3f
+
+/* Initialize the protocol and registered fields */
+static int proto_a_bssmap = -1;
+static int proto_a_dtap = -1;
+static int proto_a_rp = -1;
+
+static int hf_gsm_a_none = -1;
+static int hf_gsm_a_bssmap_msg_type = -1;
+static int hf_gsm_a_dtap_msg_mm_type = -1;
+static int hf_gsm_a_dtap_msg_rr_type = -1;
+static int hf_gsm_a_dtap_msg_cc_type = -1;
+static int hf_gsm_a_dtap_msg_gmm_type = -1;
+static int hf_gsm_a_dtap_msg_sms_type = -1;
+static int hf_gsm_a_dtap_msg_sm_type = -1;
+static int hf_gsm_a_dtap_msg_ss_type = -1;
+static int hf_gsm_a_rp_msg_type = -1;
+static int hf_gsm_a_length = -1;
+static int hf_gsm_a_bssmap_elem_id = -1;
+static int hf_gsm_a_dtap_elem_id = -1;
+static int hf_gsm_a_imsi = -1;
+static int hf_gsm_a_tmsi = -1;
+static int hf_gsm_a_imei = -1;
+static int hf_gsm_a_imeisv = -1;
+static int hf_gsm_a_cld_party_bcd_num = -1;
+static int hf_gsm_a_clg_party_bcd_num = -1;
+static int hf_gsm_a_cell_ci = -1;
+static int hf_gsm_a_cell_lac = -1;
+static int hf_gsm_a_dlci_cc = -1;
+static int hf_gsm_a_dlci_spare = -1;
+static int hf_gsm_a_dlci_sapi = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_bssmap_msg = -1;
+static gint ett_dtap_msg = -1;
+static gint ett_rp_msg = -1;
+static gint ett_elems = -1;
+static gint ett_elem = -1;
+static gint ett_dtap_oct_1 = -1;
+static gint ett_cm_srvc_type = -1;
+static gint ett_gsm_enc_info = -1;
+static gint ett_cell_list = -1;
+static gint ett_dlci = -1;
+
+static char a_bigbuf[1024];
+static gchar a_add_string[1024];
+
+static dissector_handle_t data_handle;
+static dissector_handle_t bssmap_handle;
+static dissector_handle_t dtap_handle;
+static dissector_handle_t rp_handle;
+static dissector_table_t sms_dissector_table; /* SMS TPDU */
+
+static packet_info *g_pinfo;
+static proto_tree *g_tree;
+
+/*
+ * current RP message type
+ */
+static gint gsm_a_rp_type;
+
+/*
+ * this should be set on a per message basis, if possible
+ */
+#define IS_UPLINK_FALSE 0
+#define IS_UPLINK_TRUE 1
+#define IS_UPLINK_UNKNOWN 2
+static gint is_uplink;
+
+
+typedef struct dgt_set_t
+{
+ unsigned char out[15];
+}
+dgt_set_t;
+
+static dgt_set_t Dgt_mbcd = {
+ {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e */
+ '0','1','2','3','4','5','6','7','8','9','*','#','a','b','c'
+ }
+};
+
+static dgt_set_t Dgt_tbcd = {
+ {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e */
+ '0','1','2','3','4','5','6','7','8','9','?','B','C','*','#'
+ }
+};
+
+static dgt_set_t Dgt_msid = {
+ {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e */
+ '0','1','2','3','4','5','6','7','8','9','?','?','?','?','?'
+ }
+};
+
+/* FUNCTIONS */
+
+/*
+ * Unpack BCD input pattern into output ASCII pattern
+ *
+ * Input Pattern is supplied using the same format as the digits
+ *
+ * Returns: length of unpacked pattern
+ */
+static int
+my_dgt_tbcd_unpack(
+ char *out, /* ASCII pattern out */
+ guchar *in, /* packed pattern in */
+ int num_octs, /* Number of octets to unpack */
+ dgt_set_t *dgt /* Digit definitions */
+ )
+{
+ int cnt = 0;
+ unsigned char i;
+
+ while (num_octs)
+ {
+ /*
+ * unpack first value in byte
+ */
+ i = *in++;
+ *out++ = dgt->out[i & 0x0f];
+ cnt++;
+
+ /*
+ * unpack second value in byte
+ */
+ i >>= 4;
+
+ if (i == 0x0f) /* odd number bytes - hit filler */
+ break;
+
+ *out++ = dgt->out[i];
+ cnt++;
+ num_octs--;
+ }
+
+ *out = '\0';
+
+ return(cnt);
+}
+
+/* Generate, into "buf", a string showing the bits of a bitfield.
+ * Return a pointer to the character after that string.
+ */
+static char *
+my_decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
+{
+ int i;
+ guint32 bit;
+ char *p;
+
+ i = 0;
+ p = buf;
+ bit = 1 << (width - 1);
+
+ for (;;)
+ {
+ if (mask & bit)
+ {
+ /* This bit is part of the field. Show its value. */
+ if (val & bit)
+ {
+ *p++ = '1';
+ }
+ else
+ {
+ *p++ = '0';
+ }
+ }
+ else
+ {
+ /* This bit is not part of the field. */
+ *p++ = '.';
+ }
+
+ bit >>= 1;
+ i++;
+
+ if (i >= width) break;
+
+ if (i % 4 == 0) *p++ = ' ';
+ }
+
+ *p = '\0';
+
+ return(p);
+}
+
+static gchar *
+my_match_strval(guint32 val, const value_string *vs, gint *idx)
+{
+ gint i = 0;
+
+ while (vs[i].strptr)
+ {
+ if (vs[i].value == val)
+ {
+ *idx = i;
+ return(vs[i].strptr);
+ }
+
+ i++;
+ }
+
+ *idx = -1;
+ return(NULL);
+}
+
+/* ELEMENT FUNCTIONS */
+
+#define EXTRANEOUS_DATA_CHECK(edc_len, edc_max_len) \
+ if ((edc_len) > (edc_max_len)) \
+ { \
+ proto_tree_add_text(tree, tvb, \
+ curr_offset, (edc_len) - (edc_max_len), "Extraneous Data"); \
+ curr_offset += ((edc_len) - (edc_max_len)); \
+ }
+
+#define SHORT_DATA_CHECK(sdc_len, sdc_min_len) \
+ if ((sdc_len) < (sdc_min_len)) \
+ { \
+ proto_tree_add_text(tree, tvb, \
+ curr_offset, (sdc_len), "Short Data (?)"); \
+ curr_offset += (sdc_len); \
+ return(curr_offset - offset); \
+ }
+
+#define EXACT_DATA_CHECK(edc_len, edc_eq_len) \
+ if ((edc_len) != (edc_eq_len)) \
+ { \
+ proto_tree_add_text(tree, tvb, \
+ curr_offset, (edc_len), "Unexpected Data Length"); \
+ curr_offset += (edc_len); \
+ return(curr_offset - offset); \
+ }
+
+#define NO_MORE_DATA_CHECK(nmdc_len) \
+ if ((nmdc_len) == (curr_offset - offset)) return(nmdc_len);
+
+/*
+ * Decode the MCC/MNC from 3 octets in 'octs'
+ */
+static void
+mcc_mnc_aux(guint8 *octs, gchar *mcc, gchar *mnc)
+{
+ if ((octs[0] & 0x0f) <= 9)
+ {
+ mcc[0] = Dgt_tbcd.out[octs[0] & 0x0f];
+ }
+ else
+ {
+ mcc[0] = (octs[0] & 0x0f) + 55;
+ }
+
+ if (((octs[0] & 0xf0) >> 4) <= 9)
+ {
+ mcc[1] = Dgt_tbcd.out[(octs[0] & 0xf0) >> 4];
+ }
+ else
+ {
+ mcc[1] = ((octs[0] & 0xf0) >> 4) + 55;
+ }
+
+ if ((octs[1] & 0x0f) <= 9)
+ {
+ mcc[2] = Dgt_tbcd.out[octs[1] & 0x0f];
+ }
+ else
+ {
+ mcc[2] = (octs[1] & 0x0f) + 55;
+ }
+
+ mcc[3] = '\0';
+
+ if (((octs[1] & 0xf0) >> 4) <= 9)
+ {
+ mnc[2] = Dgt_tbcd.out[(octs[1] & 0xf0) >> 4];
+ }
+ else
+ {
+ mnc[2] = ((octs[1] & 0xf0) >> 4) + 55;
+ }
+
+ if ((octs[2] & 0x0f) <= 9)
+ {
+ mnc[0] = Dgt_tbcd.out[octs[2] & 0x0f];
+ }
+ else
+ {
+ mnc[0] = (octs[2] & 0x0f) + 55;
+ }
+
+ if (((octs[2] & 0xf0) >> 4) <= 9)
+ {
+ mnc[1] = Dgt_tbcd.out[(octs[2] & 0xf0) >> 4];
+ }
+ else
+ {
+ mnc[1] = ((octs[2] & 0xf0) >> 4) + 55;
+ }
+
+ if (mnc[1] == 'F')
+ {
+ /*
+ * only a 1 digit MNC (very old)
+ */
+ mnc[1] = '\0';
+ }
+ else if (mnc[2] == 'F')
+ {
+ /*
+ * only a 2 digit MNC
+ */
+ mnc[2] = '\0';
+ }
+ else
+ {
+ mnc[3] = '\0';
+ }
+}
+
+typedef enum
+{
+ BE_CIC, /* Circuit Identity Code */
+ BE_RSVD_1, /* Reserved */
+ BE_RES_AVAIL, /* Resource Available */
+ BE_CAUSE, /* Cause */
+ BE_CELL_ID, /* Cell Identifier */
+ BE_PRIO, /* Priority */
+ BE_L3_HEADER_INFO, /* Layer 3 Header Information */
+ BE_IMSI, /* IMSI */
+ BE_TMSI, /* TMSI */
+ BE_ENC_INFO, /* Encryption Information */
+ BE_CHAN_TYPE, /* Channel Type */
+ BE_PERIODICITY, /* Periodicity */
+ BE_EXT_RES_IND, /* Extended Resource Indicator */
+ BE_NUM_MS, /* Number Of MSs */
+ BE_RSVD_2, /* Reserved */
+ BE_RSVD_3, /* Reserved */
+ BE_RSVD_4, /* Reserved */
+ BE_CM_INFO_2, /* Classmark Information Type 2 */
+ BE_CM_INFO_3, /* Classmark Information Type 3 */
+ BE_INT_BAND, /* Interference Band To Be Used */
+ BE_RR_CAUSE, /* RR Cause */
+ BE_RSVD_5, /* Reserved */
+ BE_L3_INFO, /* Layer 3 Information */
+ BE_DLCI, /* DLCI */
+ BE_DOWN_DTX_FLAG, /* Downlink DTX Flag */
+ BE_CELL_ID_LIST, /* Cell Identifier List */
+ BE_RESP_REQ, /* Response Request */
+ BE_RES_IND_METHOD, /* Resource Indication Method */
+ BE_CM_INFO_1, /* Classmark Information Type 1 */
+ BE_CIC_LIST, /* Circuit Identity Code List */
+ BE_DIAG, /* Diagnostic */
+ BE_L3_MSG, /* Layer 3 Message Contents */
+ BE_CHOSEN_CHAN, /* Chosen Channel */
+ BE_TOT_RES_ACC, /* Total Resource Accessible */
+ BE_CIPH_RESP_MODE, /* Cipher Response Mode */
+ BE_CHAN_NEEDED, /* Channel Needed */
+ BE_TRACE_TYPE, /* Trace Type */
+ BE_TRIGGERID, /* TriggerID */
+ BE_TRACE_REF, /* Trace Reference */
+ BE_TRANSID, /* TransactionID */
+ BE_MID, /* Mobile Identity */
+ BE_OMCID, /* OMCID */
+ BE_FOR_IND, /* Forward Indicator */
+ BE_CHOSEN_ENC_ALG, /* Chosen Encryption Algorithm */
+ BE_CCT_POOL, /* Circuit Pool */
+ BE_CCT_POOL_LIST, /* Circuit Pool List */
+ BE_TIME_IND, /* Time Indication */
+ BE_RES_SIT, /* Resource Situation */
+ BE_CURR_CHAN_1, /* Current Channel Type 1 */
+ BE_QUE_IND, /* Queueing Indicator */
+ BE_SPEECH_VER, /* Speech Version */
+ BE_ASS_REQ, /* Assignment Requirement */
+ BE_TALKER_FLAG, /* Talker Flag */
+ BE_CONN_REL_REQ, /* Connection Release Requested */
+ BE_GROUP_CALL_REF, /* Group Call Reference */
+ BE_EMLPP_PRIO, /* eMLPP Priority */
+ BE_CONF_EVO_IND, /* Configuration Evolution Indication */
+ BE_OLD2NEW_INFO, /* Old BSS to New BSS Information */
+ BE_LSA_ID, /* LSA Identifier */
+ BE_LSA_ID_LIST, /* LSA Identifier List */
+ BE_LSA_INFO, /* LSA Information */
+ BE_LCS_QOS, /* LCS QoS */
+ BE_LSA_ACC_CTRL, /* LSA access control suppression */
+ BE_LCS_PRIO, /* LCS Priority */
+ BE_LOC_TYPE, /* Location Type */
+ BE_LOC_EST, /* Location Estimate */
+ BE_POS_DATA, /* Positioning Data */
+ BE_LCS_CAUSE, /* LCS Cause */
+ BE_LCS_CLIENT, /* LCS Client Type */
+ BE_APDU, /* APDU */
+ BE_NE_ID, /* Network Element Identity */
+ BE_GSP_ASSIST_DATA, /* GPS Assistance Data */
+ BE_DECIPH_KEYS, /* Deciphering Keys */
+ BE_RET_ERR_REQ, /* Return Error Request */
+ BE_RET_ERR_CAUSE, /* Return Error Cause */
+ BE_SEG, /* Segmentation */
+ BE_NONE, /* NONE */
+}
+bssmap_elem_idx_t;
+
+#define NUM_GSM_BSSMAP_ELEM (sizeof(gsm_bssmap_elem_strings)/sizeof(value_string))
+static gint ett_gsm_bssmap_elem[NUM_GSM_BSSMAP_ELEM];
+
+/*
+ * [2] 3.2.2.2
+ */
+static guint8
+be_cic(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+ guint32 value;
+
+ len = len;
+ curr_offset = offset;
+
+ value = tvb_get_ntohs(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, value, 0xffe0, 16);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 2,
+ "%s : PCM Multiplexer: %d",
+ a_bigbuf,
+ (value & 0xffe0) >> 5);
+
+ my_decode_bitfield_value(a_bigbuf, value, 0x001f, 16);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 2,
+ "%s : Timeslot: %d",
+ a_bigbuf,
+ value & 0x001f);
+
+ curr_offset += 2;
+
+ sprintf(add_string, " - (%1$d) (0x%1$04x)", value);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.5
+ */
+static guint8
+be_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 value;
+ guint32 curr_offset;
+ gchar *str = NULL;
+
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension: %s",
+ a_bigbuf,
+ (oct & 0x80) ? "extended" : "not extended");
+
+ if (oct & 0x80)
+ {
+ /* 2 octet cause */
+
+ if ((oct & 0x0f) == 0x00)
+ {
+ /* national cause */
+ switch ((oct & 0x70) >> 4)
+ {
+ case 0: str = "Normal Event"; break;
+ case 1: str = "Normal Event"; break;
+ case 2: str = "Resource Unavailable"; break;
+ case 3: str = "Service or option not available"; break;
+ case 4: str = "Service or option not implemented"; break;
+ case 5: str = "Invalid message (e.g., parameter out of range)"; break;
+ case 6: str = "Protocol error"; break;
+ default:
+ str = "Interworking";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Cause Class: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : National Cause",
+ a_bigbuf);
+
+ curr_offset++;
+
+ proto_tree_add_text(tree, tvb, curr_offset, 1,
+ "Cause Value");
+
+ curr_offset++;
+
+ strcpy(add_string, " - (National Cause)");
+ }
+ else
+ {
+ value = tvb_get_guint8(tvb, curr_offset + 1);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Cause (MSB): %d",
+ a_bigbuf,
+ ((oct & 0x7f) << 8) | value);
+
+ curr_offset++;
+
+ my_decode_bitfield_value(a_bigbuf, value, 0xff, 8);
+ proto_tree_add_text(tree, tvb, curr_offset, 1,
+ "%s : Cause (LSB)",
+ a_bigbuf);
+
+ curr_offset++;
+ }
+ }
+ else
+ {
+ switch (oct)
+ {
+ case 0x00: str = "Radio interface message failure"; break;
+ case 0x01: str = "Radio interface failure"; break;
+ case 0x02: str = "Uplink quality"; break;
+ case 0x03: str = "Uplink strength"; break;
+ case 0x04: str = "Downlink quality"; break;
+ case 0x05: str = "Downlink strength"; break;
+ case 0x06: str = "Distance"; break;
+ case 0x07: str = "O and M intervention"; break;
+ case 0x08: str = "Response to MSC invocation"; break;
+ case 0x09: str = "Call control"; break;
+ case 0x0a: str = "Radio interface failure, reversion to old channel"; break;
+ case 0x0b: str = "Handover successful"; break;
+ case 0x0c: str = "Better Cell"; break;
+ case 0x0d: str = "Directed Retry"; break;
+ case 0x0e: str = "Joined group call channel"; break;
+ case 0x0f: str = "Traffic"; break;
+
+ case 0x20: str = "Equipment failure"; break;
+ case 0x21: str = "No radio resource available"; break;
+ case 0x22: str = "Requested terrestrial resource unavailable"; break;
+ case 0x23: str = "CCCH overload"; break;
+ case 0x24: str = "Processor overload"; break;
+ case 0x25: str = "BSS not equipped"; break;
+ case 0x26: str = "MS not equipped"; break;
+ case 0x27: str = "Invalid cell"; break;
+ case 0x28: str = "Traffic Load"; break;
+ case 0x29: str = "Preemption"; break;
+
+ case 0x30: str = "Requested transcoding/rate adaption unavailable"; break;
+ case 0x31: str = "Circuit pool mismatch"; break;
+ case 0x32: str = "Switch circuit pool"; break;
+ case 0x33: str = "Requested speech version unavailable"; break;
+ case 0x34: str = "LSA not allowed"; break;
+
+ case 0x40: str = "Ciphering algorithm not supported"; break;
+
+ case 0x50: str = "Terrestrial circuit already allocated"; break;
+ case 0x51: str = "Invalid message contents"; break;
+ case 0x52: str = "Information element or field missing"; break;
+ case 0x53: str = "Incorrect value"; break;
+ case 0x54: str = "Unknown Message type"; break;
+ case 0x55: str = "Unknown Information Element"; break;
+
+ case 0x60: str = "Protocol Error between BSS and MSC"; break;
+ case 0x61: str = "VGCS/VBS call non existent"; break;
+
+ default:
+ if ((oct >= 0x10) && (oct <= 0x17)) { str = "Reserved for international use"; }
+ else if ((oct >= 0x18) && (oct <= 0x1f)) { str = "Reserved for national use"; }
+ else if ((oct >= 0x2a) && (oct <= 0x2f)) { str = "Reserved for national use"; }
+ else if ((oct >= 0x35) && (oct <= 0x3f)) { str = "Reserved for international use"; }
+ else if ((oct >= 0x41) && (oct <= 0x47)) { str = "Reserved for international use"; }
+ else if ((oct >= 0x48) && (oct <= 0x4f)) { str = "Reserved for national use"; }
+ else if ((oct >= 0x56) && (oct <= 0x57)) { str = "Reserved for international use"; }
+ else if ((oct >= 0x58) && (oct <= 0x5f)) { str = "Reserved for national use"; }
+ else if ((oct >= 0x62) && (oct <= 0x67)) { str = "Reserved for international use"; }
+ else if ((oct >= 0x68) && (oct <= 0x6f)) { str = "Reserved for national use"; }
+ else if ((oct >= 0x70) && (oct <= 0x77)) { str = "Reserved for international use"; }
+ else if ((oct >= 0x78) && (oct <= 0x7f)) { str = "Reserved for national use"; }
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Cause: (%d) %s",
+ a_bigbuf,
+ oct & 0x7f,
+ str);
+
+ curr_offset++;
+
+ sprintf(add_string, " - (%d) %s", oct & 0x7f, str);
+ }
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.7
+ */
+static guint8
+be_tmsi(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+ guint32 value;
+
+ curr_offset = offset;
+
+ value = tvb_get_ntohl(tvb, curr_offset);
+
+ proto_tree_add_uint(tree, hf_gsm_a_tmsi,
+ tvb, curr_offset, 4,
+ value);
+
+ sprintf(add_string, " - (0x%04x)", value);
+
+ curr_offset += 4;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.9
+ */
+static guint8
+be_l3_header_info(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, DTAP_PD_MASK, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Protocol Discriminator: %s",
+ a_bigbuf,
+ pd_str[oct & DTAP_PD_MASK]);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : TI flag: %s",
+ a_bigbuf,
+ ((oct & 0x08) ? "allocated by receiver" : "allocated by sender"));
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : TIO: %d",
+ a_bigbuf,
+ oct & 0x07);
+
+ curr_offset++;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.10
+ */
+static guint8
+be_enc_info(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint8 mask;
+ guint8 alg_id;
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ mask = 0x80;
+ alg_id = 7;
+
+ do
+ {
+ my_decode_bitfield_value(a_bigbuf, oct, mask, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : GSM A5/%d: %spermitted",
+ a_bigbuf,
+ alg_id,
+ (mask & oct) ? "" : "not ");
+
+ mask >>= 1;
+ alg_id--;
+ }
+ while (mask != 0x01);
+
+ my_decode_bitfield_value(a_bigbuf, oct, mask, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : No encryption: %spermitted",
+ a_bigbuf,
+ (mask & oct) ? "" : "not ");
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - (curr_offset - offset),
+ "Key");
+
+ curr_offset += len - (curr_offset - offset);
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.11
+ */
+static guint8
+be_chan_type(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint8 sdi;
+ guint8 num_chan;
+ guint32 curr_offset;
+ gchar *str;
+
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ sdi = oct & 0x0f;
+ switch (sdi)
+ {
+ case 1: str = "Speech"; break;
+ case 2: str = "Data"; break;
+ case 3: str = "Signalling"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Speech/Data Indicator: %s",
+ a_bigbuf,
+ str);
+
+ sprintf(add_string, " - (%s)", str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ if (sdi == 0x01)
+ {
+ /* speech */
+
+ switch (oct)
+ {
+ case 0x08: str = "Full rate TCH channel Bm. Prefer full rate TCH"; break;
+ case 0x09: str = "Half rate TCH channel Lm. Prefer half rate TCH"; break;
+ case 0x0a: str = "Full or Half rate channel, Full rate preferred changes allowed after first allocation"; break;
+ case 0x0b: str = "Full or Half rate channel, Half rate preferred changes allowed after first allocation"; break;
+ case 0x1a: str = "Full or Half rate channel, Full rate preferred changes between full and half rate not allowed after first allocation"; break;
+ case 0x1b: str = "Full or Half rate channel, Half rate preferred changes between full and half rate not allowed after first allocation"; break;
+ case 0x0f: str = "Full or Half rate channel, changes allowed after first allocation"; break;
+ case 0x1f: str = "Full or Half rate channel, changes between full and half rate not allowed after first allocation"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Channel Rate and Type: %s",
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ do
+ {
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension: %s",
+ a_bigbuf,
+ (oct & 0x80) ? "extended" : "not extended");
+
+ switch (oct & 0x7f)
+ {
+ case 0x01: str = "GSM speech full rate version 1"; break;
+ case 0x11: str = "GSM speech full rate version 2"; break;
+ case 0x21: str = "GSM speech full rate version 3 (AMR)"; break;
+
+ case 0x05: str = "GSM speech half rate version 1"; break;
+ case 0x15: str = "GSM speech half rate version 2"; break;
+ case 0x25: str = "GSM speech half rate version 3 (AMR)"; break;
+
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Speech version identifier: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+ }
+ while ((len - (curr_offset - offset)) > 0);
+ }
+ else if (sdi == 0x02)
+ {
+ /* data */
+
+ num_chan = 0;
+
+ switch (oct)
+ {
+ case 0x08: str = "Full rate TCH channel Bm"; break;
+ case 0x09: str = "Half rate TCH channel Lm"; break;
+ case 0x0a: str = "Full or Half rate TCH channel, Full rate preferred, changes allowed also after first channel allocation as a result of the request"; break;
+ case 0x0b: str = "Full or Half rate TCH channel, Half rate preferred, changes allowed also after first channel allocation as a result of the request"; break;
+ case 0x1a: str = "Full or Half rate TCH channel, Full rate preferred, changes not allowed after first channel allocation as a result of the request"; break;
+ case 0x1b: str = "Full or Half rate TCH channel. Half rate preferred, changes not allowed after first channel allocation as a result of the request"; break;
+ default:
+ if ((oct >= 0x20) && (oct <= 0x27))
+ {
+ str = "Full rate TCH channels in a multislot configuration, changes by the BSS of the the number of TCHs and if applicable the used radio interface rate per channel allowed after first channel allocation as a result of the request";
+
+ num_chan = (oct - 0x20) + 1;
+ }
+ else if ((oct >= 0x30) && (oct <= 0x37))
+ {
+ str = "Full rate TCH channels in a multislot configuration, changes by the BSS of the number of TCHs or the used radio interface rate per channel not allowed after first channel allocation as a result of the request";
+
+ num_chan = (oct - 0x30) + 1;
+ }
+ else
+ {
+ str = "Reserved";
+ }
+ break;
+ }
+
+ if (num_chan > 0)
+ {
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Channel Rate and Type: Max channels %d, %s",
+ num_chan,
+ str);
+ }
+ else
+ {
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Channel Rate and Type: %s",
+ str);
+ }
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension: %s",
+ a_bigbuf,
+ (oct & 0x80) ? "extended" : "not extended");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x40, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : %sTransparent service",
+ a_bigbuf,
+ (oct & 0x40) ? "Non-" : "");
+
+ if (num_chan == 0)
+ {
+ if (oct & 0x40)
+ {
+ /* non-transparent */
+
+ switch (oct & 0x3f)
+ {
+ case 0x00: str = "12 kbit/s if the channel is a full rate TCH, or 6 kbit/s if the channel is a half rate TCH"; break;
+ case 0x18: str = "14.5 kbit/s"; break;
+ case 0x10: str = "12 kbits/s"; break;
+ case 0x11: str = "6 kbits/s"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+ }
+ else
+ {
+ switch (oct & 0x3f)
+ {
+ case 0x18: str = "14.4 kbit/s"; break;
+ case 0x10: str = "9.6kbit/s"; break;
+ case 0x11: str = "4.8kbit/s"; break;
+ case 0x12: str = "2.4kbit/s"; break;
+ case 0x13: str = "1.2Kbit/s"; break;
+ case 0x14: str = "600 bit/s"; break;
+ case 0x15: str = "1200/75 bit/s (1200 network-to-MS / 75 MS-to-network)"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (oct & 0x40)
+ {
+ /* non-transparent */
+
+ switch (oct & 0x3f)
+ {
+ case 0x16: str = "58 kbit/s (4x14.5 kbit/s)"; break;
+ case 0x14: str = "48.0 / 43.5 kbit/s (4x12 kbit/s or 3x14.5 kbit/s)"; break;
+ case 0x13: str = "36.0 / 29.0 kbit/s (3x12 kbit/s or 2x14.5 kbit/s)"; break;
+ case 0x12: str = "24.0 / 24.0 (4x6 kbit/s or 2x12 kbit/s)"; break;
+ case 0x11: str = "18.0 / 14.5 kbit/s (3x6 kbit/s or 1x14.5 kbit/s)"; break;
+ case 0x10: str = "12.0 / 12.0 kbit/s (2x6 kbit/s or 1x12 kbit/s)"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+ }
+ else
+ {
+ switch (oct & 0x3f)
+ {
+ case 0x1f: str = "64 kbit/s, bit transparent"; break;
+ case 0x1e: str = "56 kbit/s, bit transparent"; break;
+ case 0x1d: str = "56 kbit/s"; break;
+ case 0x1c: str = "48 kbit/s"; break;
+ case 0x1b: str = "38.4 kbit/s"; break;
+ case 0x1a: str = "28.8 kbit/s"; break;
+ case 0x19: str = "19.2 kbit/s"; break;
+ case 0x18: str = "14.4 kbit/s"; break;
+ case 0x10: str = "9.6 kbit/s"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+ }
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Rate: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension: %s",
+ a_bigbuf,
+ (oct & 0x80) ? "extended" : "not extended");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ if (num_chan == 0)
+ {
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : 14.5 kbit/s (TCH/F14.4) %sallowed",
+ a_bigbuf,
+ (oct & 0x08) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x04, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x02, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : 12.0 kbit/s (TCH F/9.6) %sallowed",
+ a_bigbuf,
+ (oct & 0x02) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : 6.0 kbit/s (TCH F/4.8) %sallowed",
+ a_bigbuf,
+ (oct & 0x01) ? "" : "not ");
+ }
+ else
+ {
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : 14.5/14.4 kbit/s (TCH/F14.4) %sallowed",
+ a_bigbuf,
+ (oct & 0x08) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x04, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x02, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : 12.0/9.6 kbit/s (TCH F/9.6) %sallowed",
+ a_bigbuf,
+ (oct & 0x02) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : 6.0/4.8 kbit/s (TCH F/4.8) %sallowed",
+ a_bigbuf,
+ (oct & 0x01) ? "" : "not ");
+ }
+
+ curr_offset++;
+ }
+ else if (sdi == 0x03)
+ {
+ /* signalling */
+
+ switch (oct)
+ {
+ case 0x00: str = "SDCCH or Full rate TCH channel Bm or Half rate TCH channel Lm"; break;
+ case 0x01: str = "SDCCH"; break;
+ case 0x02: str = "SDCCH or Full rate TCH channel Bm"; break;
+ case 0x03: str = "SDCCH or Half rate TCH channel Lm"; break;
+ case 0x08: str = "Full rate TCH channel Bm"; break;
+ case 0x09: str = "Half rate TCH channel Lm"; break;
+ case 0x0a: str = "Full or Half rate TCH channel, Full rate preferred, changes allowed also after first channel allocation as a result of the request"; break;
+ case 0x0b: str = "Full or Half rate TCH channel, Half rate preferred, changes allowed also after first channel allocation as a result of the request"; break;
+ case 0x1a: str = "Full or Half rate TCH channel, Full rate preferred, changes not allowed after first channel allocation as a result of the request"; break;
+ case 0x1b: str = "Full or Half rate TCH channel. Half rate preferred, changes not allowed after first channel allocation as a result of the request"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Channel Rate and Type: %s",
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - (curr_offset - offset),
+ "Spare");
+
+ curr_offset += len - (curr_offset - offset);
+ }
+ else
+ {
+ /* unknown format */
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - (curr_offset - offset),
+ "Unknown format");
+
+ curr_offset += len - (curr_offset - offset);
+ }
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.17
+ * Formats everything after the discriminator, shared function
+ */
+static guint8
+be_cell_id_aux(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string, guint8 disc)
+{
+ guint8 octs[3];
+ guint32 value;
+ guint32 curr_offset;
+ gchar mcc[4];
+ gchar mnc[4];
+
+ add_string[0] = '\0';
+ curr_offset = offset;
+
+ switch (disc)
+ {
+ case 0x00:
+ /* FALLTHRU */
+
+ case 0x04:
+ octs[0] = tvb_get_guint8(tvb, curr_offset);
+ octs[1] = tvb_get_guint8(tvb, curr_offset + 1);
+ octs[2] = tvb_get_guint8(tvb, curr_offset + 2);
+
+ mcc_mnc_aux(octs, mcc, mnc);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 3,
+ "Mobile Country Code (MCC): %s, Mobile Network Code (MNC): %s",
+ mcc,
+ mnc);
+
+ curr_offset += 3;
+
+ /* FALLTHRU */
+
+ case 0x01:
+ case 0x05:
+
+ /* LAC */
+
+ value = tvb_get_ntohs(tvb, curr_offset);
+
+ proto_tree_add_uint(tree, hf_gsm_a_cell_lac, tvb,
+ curr_offset, 2, value);
+
+ curr_offset += 2;
+
+ sprintf(add_string, " - LAC (0x%04x)", value);
+
+ if ((disc == 0x04) || (disc == 0x05)) break;
+
+ /* FALLTHRU */
+
+ case 0x02:
+
+ /* CI */
+
+ value = tvb_get_ntohs(tvb, curr_offset);
+
+ proto_tree_add_uint(tree, hf_gsm_a_cell_ci, tvb,
+ curr_offset, 2, value);
+
+ curr_offset += 2;
+
+ if (add_string[0] == '\0')
+ {
+ sprintf(add_string, " - CI (%d)", value);
+ }
+ else
+ {
+ sprintf(add_string, "%s/CI (%d)", add_string, value);
+ }
+ break;
+
+ default:
+ proto_tree_add_text(tree, tvb, curr_offset, len - 1,
+ "Cell ID - Unknown format");
+
+ curr_offset += (len - 1);
+ break;
+ }
+
+ return(curr_offset - offset);
+}
+
+static guint8
+be_cell_id(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint8 disc;
+ guint32 curr_offset;
+ const gchar *str = NULL;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ disc = oct & 0x0f;
+
+ if (disc >= (gint) NUM_CELL_DISC_STR)
+ {
+ str = "Unknown";
+ }
+ else
+ {
+ str = cell_disc_str[disc];
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Cell Identification Discriminator: (%d) %s",
+ a_bigbuf,
+ disc,
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ curr_offset +=
+ be_cell_id_aux(tvb, tree, curr_offset, len - (curr_offset - offset), add_string, disc);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.18
+ */
+static guint8
+be_prio(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x40, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Preemption Capability Indicator (PCI): this allocation request %s preempt an existing connection",
+ a_bigbuf,
+ (oct & 0x40) ? "may" : "shall not");
+
+ switch ((oct & 0x3c) >> 2)
+ {
+ case 0x00: str = "Spare"; break;
+ case 0x0f: str = "priority not used"; break;
+ default:
+ str = "1 is highest";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x3c, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Priority Level: (%d) %s",
+ a_bigbuf,
+ (oct & 0x3c) >> 2,
+ str);
+
+ sprintf(add_string, " - (%d)", (oct & 0x3c) >> 2);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x02, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Queuing Allowed Indicator (QA): queuing %sallowed",
+ a_bigbuf,
+ (oct & 0x02) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Preemption Vulnerability Indicator (PVI): this connection %s be preempted by another allocation request",
+ a_bigbuf,
+ (oct & 0x01) ? "might" : "shall not");
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.24
+ */
+static guint8
+be_l3_info(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+ tvbuff_t *l3_tvb;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree, tvb, curr_offset, len,
+ "Layer 3 Information value");
+
+ /*
+ * dissect the embedded DTAP message
+ */
+ l3_tvb = tvb_new_subset(tvb, curr_offset, len, len);
+
+ call_dissector(dtap_handle, l3_tvb, g_pinfo, g_tree);
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.25
+ */
+static guint8
+be_dlci(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ proto_item *item = NULL;
+ proto_tree *subtree = NULL;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ item =
+ proto_tree_add_text(tree, tvb, curr_offset, 1,
+ "Data Link Connection Identifier");
+
+ subtree = proto_item_add_subtree(item, ett_dlci);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ proto_tree_add_uint(subtree, hf_gsm_a_dlci_cc, tvb, curr_offset, 1, oct);
+ proto_tree_add_uint(subtree, hf_gsm_a_dlci_spare, tvb, curr_offset, 1, oct);
+ proto_tree_add_uint(subtree, hf_gsm_a_dlci_sapi, tvb, curr_offset, 1, oct);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.26
+ */
+static guint8
+be_down_dtx_flag(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint oct;
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xfe, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : BSS is %s to activate DTX in the downlink direction",
+ a_bigbuf,
+ (oct & 0x01) ? "forbidden" : "allowed");
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.27
+ */
+static guint8
+be_cell_id_list(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint8 consumed;
+ guint8 disc;
+ guint8 num_cells;
+ guint32 curr_offset;
+ proto_item *item = NULL;
+ proto_tree *subtree = NULL;
+ const gchar *str = NULL;
+
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ disc = oct & 0x0f;
+
+ if (disc >= (gint) NUM_CELL_DISC_STR)
+ {
+ str = "Unknown";
+ }
+ else
+ {
+ str = cell_disc_str[disc];
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Cell Identification Discriminator: (%d) %s",
+ a_bigbuf,
+ disc,
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ num_cells = 0;
+ do
+ {
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, -1,
+ "Cell %d",
+ num_cells + 1);
+
+ subtree = proto_item_add_subtree(item, ett_cell_list);
+
+ add_string[0] = '\0';
+ consumed =
+ be_cell_id_aux(tvb, subtree, curr_offset, len - (curr_offset - offset), add_string, disc);
+
+ if (add_string[0] != '\0')
+ {
+ proto_item_append_text(item, add_string);
+ }
+
+ proto_item_set_len(item, consumed);
+
+ curr_offset += consumed;
+
+ num_cells++;
+ }
+ while ((len - (curr_offset - offset)) > 0);
+
+ sprintf(add_string, " - %d cell%s",
+ num_cells, plurality(num_cells, "", "s"));
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.33
+ */
+static guint8
+be_chosen_chan(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str = NULL;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch ((oct & 0xf0) >> 4)
+ {
+ case 0: str = "No channel mode indication"; break;
+ case 9: str = "Speech (full rate or half rate)"; break;
+ case 14: str = "Data, 14.5 kbit/s radio interface rate"; break;
+ case 11: str = "Data, 12.0 kbit/s radio interface rate"; break;
+ case 12: str = "Data, 6.0 kbit/s radio interface rate"; break;
+ case 13: str = "Data, 3.6 kbit/s radio interface rate"; break;
+ case 8: str = "Signalling only"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Channel mode: %s",
+ a_bigbuf,
+ str);
+
+ switch (oct & 0x0f)
+ {
+ case 0: str = "None"; break;
+ case 1: str = "SDCCH"; break;
+ case 8: str = "1 Full rate TCH"; break;
+ case 9: str = "1 Half rate TCH"; break;
+ case 10: str = "2 Full Rate TCHs"; break;
+ case 11: str = "3 Full Rate TCHs"; break;
+ case 12: str = "4 Full Rate TCHs"; break;
+ case 13: str = "5 Full Rate TCHs"; break;
+ case 14: str = "6 Full Rate TCHs"; break;
+ case 15: str = "7 Full Rate TCHs"; break;
+ case 4: str = "8 Full Rate TCHs"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Channel: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.34
+ */
+static guint8
+be_ciph_resp_mode(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xfe, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : IMEISV must %sbe included by the mobile station",
+ a_bigbuf,
+ (oct & 0x01) ? "" : "not ");
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.35
+ */
+static guint8
+be_l3_msg(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+ tvbuff_t *l3_tvb;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree, tvb, curr_offset, len,
+ "Layer 3 Message Contents");
+
+ /*
+ * dissect the embedded DTAP message
+ */
+ l3_tvb = tvb_new_subset(tvb, curr_offset, len, len);
+
+ call_dissector(dtap_handle, l3_tvb, g_pinfo, g_tree);
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.43
+ */
+static guint8
+be_for_ind(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str = NULL;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x0f)
+ {
+ case 1: str = "forward to subsequent BSS, no trace at MSC"; break;
+ case 2: str = "forward to subsequent BSS, and trace at MSC"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.44
+ */
+static guint8
+be_chosen_enc_alg(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str = NULL;
+
+ len = len;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch (oct)
+ {
+ case 0x01: str = "No encryption used"; break;
+ case 0x02: str = "GSM A5/1"; break;
+ case 0x03: str = "GSM A5/2"; break;
+ case 0x04: str = "GSM A5/3"; break;
+ case 0x05: str = "GSM A5/4"; break;
+ case 0x06: str = "GSM A5/5"; break;
+ case 0x07: str = "GSM A5/6"; break;
+ case 0x08: str = "GSM A5/7"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Algorithm Identifier: %s",
+ str);
+
+ curr_offset++;
+
+ sprintf(add_string, " - %s", str);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.45
+ */
+static guint8
+be_cct_pool(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str = NULL;
+
+ len = len;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ if (oct <= 32)
+ {
+ str = "";
+ }
+ else if ((oct >= 0x80) && (oct <= 0x8f))
+ {
+ str = ", for national/local use";
+ }
+ else
+ {
+ str = ", reserved for future international use";
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Circuit pool number: %d%s",
+ oct,
+ str);
+
+ curr_offset++;
+
+ sprintf(add_string, " - (%d)", oct);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.49
+ */
+static guint8
+be_curr_chan_1(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch ((oct & 0xf0) >> 4)
+ {
+ case 0x00: str = "Signalling only"; break;
+ case 0x01: str = "Speech (full rate or half rate)"; break;
+ case 0x06: str = "Data, 14.5 kbit/s radio interface rate"; break;
+ case 0x03: str = "Data, 12.0 kbit/s radio interface rate"; break;
+ case 0x04: str = "Data, 6.0 kbit/s radio interface rate"; break;
+ case 0x05: str = "Data, 3.6 kbit/s radio interface rate"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Channel Mode: %s",
+ a_bigbuf,
+ str);
+
+ switch (oct & 0x0f)
+ {
+ case 0x01: str = "SDCCH"; break;
+ case 0x08: str = "1 Full rate TCH"; break;
+ case 0x09: str = "1 Half rate TCH"; break;
+ case 0x0a: str = "2 Full Rate TCHs"; break;
+ case 0x0b: str = "3 Full Rate TCHs"; break;
+ case 0x0c: str = "4 Full Rate TCHs"; break;
+ case 0x0d: str = "5 Full Rate TCHs"; break;
+ case 0x0e: str = "6 Full Rate TCHs"; break;
+ case 0x0f: str = "7 Full Rate TCHs"; break;
+ case 0x04: str = "8 Full Rate TCHs"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Channel: (%d) %s",
+ a_bigbuf,
+ oct & 0x0f,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.50
+ */
+static guint8
+be_que_ind(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xfc, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x02, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : qri: it is recommended %sto allow queuing",
+ a_bigbuf,
+ (oct & 0x02) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.51
+ */
+static guint8
+be_speech_ver(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str = NULL;
+ gchar *short_str = NULL;
+
+ len = len;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x7f)
+ {
+ case 0x01: str = "GSM speech full rate version 1"; short_str = "FR1"; break;
+ case 0x11: str = "GSM speech full rate version 2"; short_str = "FR2"; break;
+ case 0x21: str = "GSM speech full rate version 3 (AMR)"; short_str = "FR3 (AMR)"; break;
+
+ case 0x05: str = "GSM speech half rate version 1"; short_str = "HR1"; break;
+ case 0x15: str = "GSM speech half rate version 2"; short_str = "HR2"; break;
+ case 0x25: str = "GSM speech half rate version 3 (AMR)"; short_str = "HR3 (AMR)"; break;
+
+ default:
+ str = "Reserved";
+ short_str = str;
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Speech version identifier: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ sprintf(add_string, " - (%s)", short_str);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [2] 3.2.2.68
+ */
+static guint8
+be_apdu(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree, tvb, curr_offset, len,
+ "APDU");
+
+ /*
+ * dissect the embedded APDU message
+ * if someone writes a TS 09.31 dissector
+ */
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+typedef enum
+{
+ /* Common Information Elements 10.5.1 */
+ DE_CELL_ID, /* Cell Identity */
+ DE_CIPH_KEY_SEQ_NUM, /* Ciphering Key Sequence Number */
+ DE_LAI, /* Location Area Identification */
+ DE_MID, /* Mobile Identity */
+ DE_MS_CM_1, /* Mobile Station Classmark 1 */
+ DE_MS_CM_2, /* Mobile Station Classmark 2 */
+ DE_MS_CM_3, /* Mobile Station Classmark 3 */
+ DE_D_GB_CALL_REF, /* Descriptive group or broadcast call reference */
+ DE_G_CIPH_KEY_NUM, /* Group Cipher Key Number */
+ DE_PD_SAPI, /* PD and SAPI $(CCBS)$ */
+ DE_PRIO, /* Priority Level */
+ DE_PLMN_LIST, /* PLMN List */
+ /* Radio Resource Management Information Elements 10.5.2, most are from 10.5.1 */
+ DE_RR_CAUSE, /* RR Cause */
+ /* Mobility Management Information Elements 10.5.3 */
+ DE_AUTH_PARAM_RAND, /* Authentication Parameter RAND */
+ DE_AUTH_PARAM_AUTN, /* Authentication Parameter AUTN (UMTS authentication challenge only) */
+ DE_AUTH_RESP_PARAM, /* Authentication Response Parameter */
+ DE_AUTH_RESP_PARAM_EXT, /* Authentication Response Parameter (extension) (UMTS authentication challenge only) */
+ DE_AUTH_FAIL_PARAM, /* Authentication Failure Parameter (UMTS authentication challenge only) */
+ DE_CM_SRVC_TYPE, /* CM Service Type */
+ DE_ID_TYPE, /* Identity Type */
+ DE_LOC_UPD_TYPE, /* Location Updating Type */
+ DE_NETWORK_NAME, /* Network Name */
+ DE_REJ_CAUSE, /* Reject Cause */
+ DE_FOP, /* Follow-on Proceed */
+ DE_TIME_ZONE, /* Time Zone */
+ DE_TIME_ZONE_TIME, /* Time Zone and Time */
+ DE_CTS_PERM, /* CTS Permission */
+ DE_LSA_ID, /* LSA Identifier */
+ DE_DAY_SAVING_TIME, /* Daylight Saving Time */
+ /* Call Control Information Elements 10.5.4 */
+ DE_AUX_STATES, /* Auxiliary States */
+ DE_BEARER_CAP, /* Bearer Capability */
+ DE_CC_CAP, /* Call Control Capabilities */
+ DE_CALL_STATE, /* Call State */
+ DE_CLD_PARTY_BCD_NUM, /* Called Party BCD Number */
+ DE_CLD_PARTY_SUB_ADDR, /* Called Party Subaddress */
+ DE_CLG_PARTY_BCD_NUM, /* Calling Party BCD Number */
+ DE_CLG_PARTY_SUB_ADDR, /* Calling Party Subaddress */
+ DE_CAUSE, /* Cause */
+ DE_CLIR_SUP, /* CLIR Suppression */
+ DE_CLIR_INV, /* CLIR Invocation */
+ DE_CONGESTION, /* Congestion Level */
+ DE_CONN_NUM, /* Connected Number */
+ DE_CONN_SUB_ADDR, /* Connected Subaddress */
+ DE_FACILITY, /* Facility */
+ DE_HLC, /* High Layer Compatibility */
+ DE_KEYPAD_FACILITY, /* Keypad Facility */
+ DE_LLC, /* Low Layer Compatibility */
+ DE_MORE_DATA, /* More Data */
+ DE_NOT_IND, /* Notification Indicator */
+ DE_PROG_IND, /* Progress Indicator */
+ DE_RECALL_TYPE, /* Recall type $(CCBS)$ */
+ DE_RED_PARTY_BCD_NUM, /* Redirecting Party BCD Number */
+ DE_RED_PARTY_SUB_ADDR, /* Redirecting Party Subaddress */
+ DE_REPEAT_IND, /* Repeat Indicator */
+ DE_REV_CALL_SETUP_DIR, /* Reverse Call Setup Direction */
+ DE_SETUP_CONTAINER, /* SETUP Container $(CCBS)$ */
+ DE_SIGNAL, /* Signal */
+ DE_SS_VER_IND, /* SS Version Indicator */
+ DE_USER_USER, /* User-user */
+ DE_ALERT_PATTERN, /* Alerting Pattern $(NIA)$ */
+ DE_ALLOWED_ACTIONS, /* Allowed Actions $(CCBS)$ */
+ DE_SI, /* Stream Identifier */
+ DE_NET_CC_CAP, /* Network Call Control Capabilities */
+ DE_CAUSE_NO_CLI, /* Cause of No CLI */
+ DE_IMM_MOD_IND, /* Immediate Modification Indicator */
+ DE_SUP_CODEC_LIST, /* Supported Codec List */
+ DE_SRVC_CAT, /* Service Category */
+ /* GPRS Mobility Management Information Elements 10.5.5 */
+ DE_ATTACH_RES, /* Attach Result */
+ DE_ATTACH_TYPE, /* Attach Type */
+ DE_TMSI_STAT, /* TMSI Status */
+ DE_DETACH_TYPE, /* Detach Type */
+ DE_DRX_PARAM, /* DRX Parameter */
+ DE_FORCE_TO_STAND, /* Force to Standby */
+ DE_P_TMSI_SIG, /* P-TMSI Signature */
+ DE_P_TMSI_SIG_2, /* P-TMSI Signature 2 */
+ DE_ID_TYPE_2, /* Identity Type 2 */
+ DE_IMEISV_REQ, /* IMEISV Request */
+ DE_REC_N_PDU_NUM_LIST, /* Receive N-PDU Numbers List */
+ DE_MS_NET_CAP, /* MS Network Capability */
+ DE_MS_RAD_ACC_CAP, /* MS Radio Access Capability */
+ DE_GMM_CAUSE, /* GMM Cause */
+ DE_RAI, /* Routing Area Identification */
+ DE_UPD_RES, /* Update Result */
+ DE_AC_REF_NUM, /* A&C Reference Number */
+ DE_SRVC_TYPE, /* Service Type */
+ DE_CELL_NOT, /* Cell Notification */
+ DE_NET_FEAT_SUP, /* Network Feature Support */
+ /* Short Message Service Information Elements [5] 8.1.4 */
+ DE_CP_USER_DATA, /* CP-User Data */
+ DE_CP_CAUSE, /* CP-Cause */
+ /* Short Message Service Information Elements [5] 8.2 */
+ DE_RP_MESSAGE_REF, /* RP-Message Reference */
+ DE_RP_ORIG_ADDR, /* RP-Origination Address */
+ DE_RP_DEST_ADDR, /* RP-Destination Address */
+ DE_RP_USER_DATA, /* RP-User Data */
+ DE_RP_CAUSE, /* RP-Cause */
+ /* Session Management Information Elements 10.5.6 */
+ DE_ACC_POINT_NAME, /* Access Point Name */
+ DE_NET_SAPI, /* Network Service Access Point Identifier */
+ DE_PRO_CONF_OPT, /* Protocol Configuration Options */
+ DE_PD_PRO_ADDR, /* Packet Data Protocol Address */
+ DE_QOS, /* Quality Of Service */
+ DE_SM_CAUSE, /* SM Cause */
+ DE_LINKED_TI, /* Linked TI */
+ DE_LLC_SAPI, /* LLC Service Access Point Identifier */
+ DE_TEAR_DOWN_IND, /* Tear Down Indicator */
+ DE_PACKET_FLOW_ID, /* Packet Flow Identifier */
+ DE_TRAFFIC_FLOW_TEMPLATE, /* Traffic Flow Template */
+ /* GPRS Common Information Elements 10.5.7 */
+ DE_PDP_CONTEXT_STAT, /* PDP Context Status */
+ DE_RAD_PRIO, /* Radio Priority */
+ DE_GPRS_TIMER, /* GPRS Timer */
+ DE_GPRS_TIMER_2, /* GPRS Timer 2 */
+ DE_NONE, /* NONE */
+}
+dtap_elem_idx_t;
+
+#define NUM_GSM_DTAP_ELEM (sizeof(gsm_dtap_elem_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_elem[NUM_GSM_DTAP_ELEM];
+
+/*
+ * [3] 10.5.1.1
+ */
+static guint8
+de_cell_id(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ curr_offset = offset;
+
+ curr_offset +=
+ be_cell_id_aux(tvb, tree, offset, len, add_string, 0x02);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.3
+ */
+static guint8
+de_lai(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 octs[3];
+ guint16 value;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar mcc[4];
+ gchar mnc[4];
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ octs[0] = tvb_get_guint8(tvb, curr_offset);
+ octs[1] = tvb_get_guint8(tvb, curr_offset + 1);
+ octs[2] = tvb_get_guint8(tvb, curr_offset + 2);
+
+ mcc_mnc_aux(octs, mcc, mnc);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 5,
+ gsm_dtap_elem_strings[DE_LAI].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_LAI]);
+
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 3,
+ "Mobile Country Code (MCC): %s, Mobile Network Code (MNC): %s",
+ mcc,
+ mnc);
+
+ curr_offset += 3;
+
+ value = tvb_get_ntohs(tvb, curr_offset);
+
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 2,
+ "Location Area Code (LAC): 0x%04x (%d)",
+ value,
+ value);
+
+ proto_item_append_text(item, " - LAC (0x%04x)", value);
+
+ curr_offset += 2;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.4
+ */
+static guint8
+de_mid(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ guint8 *poctets;
+ guint32 value;
+ gboolean odd;
+
+ curr_offset = offset;
+ odd = FALSE;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch (oct & 0x07)
+ {
+ case 0: /* No Identity */
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Unused",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Odd/Even Indicator: %s",
+ a_bigbuf,
+ (oct & 0x08) ? "ODD" : "EVEN");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of Identity: No Identity Code",
+ a_bigbuf);
+
+ strcpy(add_string, " - No Identity Code");
+
+ curr_offset++;
+
+ if (len > 1)
+ {
+ proto_tree_add_text(tree, tvb, curr_offset, len - 1,
+ "Format not supported");
+ }
+
+ curr_offset += len - 1;
+ break;
+
+ case 3: /* IMEISV */
+
+ /* FALLTHRU */
+
+ case 1: /* IMSI */
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Identity Digit 1: %c",
+ a_bigbuf,
+ Dgt_msid.out[(oct & 0xf0) >> 4]);
+
+ odd = oct & 0x08;
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Odd/Even Indicator: %s",
+ a_bigbuf,
+ odd ? "ODD" : "EVEN");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of Identity: %s",
+ a_bigbuf,
+ ((oct & 0x07) == 3) ? "IMEISV" : "IMSI");
+
+ a_bigbuf[0] = Dgt_msid.out[(oct & 0xf0) >> 4];
+ curr_offset++;
+
+ poctets = tvb_get_string(tvb, curr_offset, len - (curr_offset - offset));
+
+ my_dgt_tbcd_unpack(&a_bigbuf[1], poctets, len - (curr_offset - offset),
+ &Dgt_msid);
+ g_free(poctets);
+
+ proto_tree_add_string_format(tree,
+ ((oct & 0x07) == 3) ? hf_gsm_a_imeisv : hf_gsm_a_imsi,
+ tvb, curr_offset, len - (curr_offset - offset),
+ a_bigbuf,
+ "BCD Digits: %s",
+ a_bigbuf);
+
+ sprintf(add_string, " - %s (%s)",
+ ((oct & 0x07) == 3) ? "IMEISV" : "IMSI",
+ a_bigbuf);
+
+ curr_offset += len - (curr_offset - offset);
+
+ if (!odd)
+ {
+ oct = tvb_get_guint8(tvb, curr_offset - 1);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset - 1, 1,
+ "%s : Filler",
+ a_bigbuf);
+ }
+ break;
+
+ case 2: /* IMEI */
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Identity Digit 1: %c",
+ a_bigbuf,
+ Dgt_msid.out[(oct & 0xf0) >> 4]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Odd/Even Indicator: %s",
+ a_bigbuf,
+ (oct & 0x08) ? "ODD" : "EVEN");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of Identity: IMEI",
+ a_bigbuf);
+
+ a_bigbuf[0] = Dgt_msid.out[(oct & 0xf0) >> 4];
+ curr_offset++;
+
+ poctets = tvb_get_string(tvb, curr_offset, len - (curr_offset - offset));
+
+ my_dgt_tbcd_unpack(&a_bigbuf[1], poctets, len - (curr_offset - offset),
+ &Dgt_msid);
+ g_free(poctets);
+
+ proto_tree_add_string_format(tree,
+ hf_gsm_a_imei,
+ tvb, curr_offset, len - (curr_offset - offset),
+ a_bigbuf,
+ "BCD Digits: %s",
+ a_bigbuf);
+
+ sprintf(add_string, " - IMEI (%s)", a_bigbuf);
+
+ curr_offset += len - (curr_offset - offset);
+ break;
+
+ case 4: /* TMSI/P-TMSI */
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Unused",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Odd/Even Indicator: %s",
+ a_bigbuf,
+ (oct & 0x08) ? "ODD" : "EVEN");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of Identity: TMSI/P-TMSI",
+ a_bigbuf);
+
+ curr_offset++;
+
+ value = tvb_get_ntohl(tvb, curr_offset);
+
+ proto_tree_add_uint(tree, hf_gsm_a_tmsi,
+ tvb, curr_offset, 4,
+ value);
+
+ sprintf(add_string, " - TMSI/P-TMSI (0x%04x)", value);
+
+ curr_offset += 4;
+ break;
+
+ default: /* Reserved */
+ proto_tree_add_text(tree, tvb, curr_offset, len,
+ "Format Unknown");
+
+ strcpy(add_string, " - Format Unknown");
+
+ curr_offset += len;
+ break;
+ }
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.5
+ */
+static guint8
+de_ms_cm_1(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_MS_CM_1].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_MS_CM_1]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch ((oct & 0x60) >> 5)
+ {
+ case 0: str = "Reserved for GSM phase 1"; break;
+ case 1: str = "Used by GSM phase 2 mobile stations"; break;
+ case 2: str = "Used by mobile stations supporting R99 or later versions of the protocol"; break;
+ default:
+ str = "Reserved for future use";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x60, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Revision Level: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x10, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : ES IND: Controlled Early Classmark Sending is %simplemented",
+ a_bigbuf,
+ (oct & 0x10) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : A5/1: encryption algorithm A5/1 %savailable",
+ a_bigbuf,
+ (oct & 0x08) ? "not " : "");
+
+ switch (oct & 0x07)
+ {
+ case 0: str = "Class 1"; break;
+ case 1: str = "Class 2"; break;
+ case 2: str = "Class 3"; break;
+ case 3: str = "Class 4"; break;
+ case 4: str = "Class 5"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : RF power capability: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.6
+ */
+static guint8
+de_ms_cm_2(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch ((oct & 0x60) >> 5)
+ {
+ case 0: str = "Reserved for GSM phase 1"; break;
+ case 1: str = "Used by GSM phase 2 mobile stations"; break;
+ case 2: str = "Used by mobile stations supporting R99 or later versions of the protocol"; break;
+ default:
+ str = "Reserved for future use";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x60, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Revision Level: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x10, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : ES IND: Controlled Early Classmark Sending is %simplemented",
+ a_bigbuf,
+ (oct & 0x10) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : A5/1: encryption algorithm A5/1 %savailable",
+ a_bigbuf,
+ (oct & 0x08) ? "not " : "");
+
+ switch (oct & 0x07)
+ {
+ case 0: str = "Class 1"; break;
+ case 1: str = "Class 2"; break;
+ case 2: str = "Class 3"; break;
+ case 3: str = "Class 4"; break;
+ case 4: str = "Class 5"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : RF power capability: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x40, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : PS capability (pseudo-synchronization capability): %spresent",
+ a_bigbuf,
+ (oct & 0x40) ? "" : "not ");
+
+ switch ((oct & 0x30) >> 4)
+ {
+ case 0: str = "Default value for phase 1"; break;
+ case 1: str = "Capability of handling of ellipsis notation and phase 2 error handling"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x30, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : SS Screening Indicator: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : SM capability (MT SMS pt to pt capability): MS %s MT SMS",
+ a_bigbuf,
+ (oct & 0x08) ? "supports" : "does not support");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x04, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : VBS notification reception: %s",
+ a_bigbuf,
+ (oct & 0x04) ? "VBS capability and notifications wanted" :
+ "no VBS capability or no notifications wanted");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x02, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : VGCS notification reception: %s",
+ a_bigbuf,
+ (oct & 0x02) ? "VGCS capability and notifications wanted" :
+ "no VGCS capability or no notifications wanted");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : FC Frequency Capability",
+ a_bigbuf);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : CM3: %s",
+ a_bigbuf,
+ (oct & 0x80) ?
+ "The MS supports options that are indicated in classmark 3 IE" :
+ "The MS does not support any options that are indicated in CM3");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x40, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x20, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : LCS VA capability: LCS value added location request notification capability %ssupported",
+ a_bigbuf,
+ (oct & 0x20) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x10, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : UCS2 treatment: %s",
+ a_bigbuf,
+ (oct & 0x10) ?
+ "the ME has no preference between the use of the default alphabet and the use of UCS2" :
+ "the ME has a preference for the default alphabet (defined in 3GPP TS 03.38) over UCS2");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : SoLSA: the ME %s SoLSA",
+ a_bigbuf,
+ (oct & 0x08) ? "supports" : "does not support");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x04, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : CMSP (CM Service Prompt): %s",
+ a_bigbuf,
+ (oct & 0x04) ?
+ "'Network initiated MO CM connection request' supported for at least one CM protocol" :
+ "'Network initiated MO CM connection request' not supported");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x02, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : A5/3: encryption algorithm A5/3 %savailable",
+ a_bigbuf,
+ (oct & 0x02) ? "" : "not ");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : A5/2: encryption algorithm A5/2 %savailable",
+ a_bigbuf,
+ (oct & 0x01) ? "" : "not ");
+
+ curr_offset++;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.9
+ */
+static guint8
+de_d_gb_call_ref(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 value;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ value = tvb_get_ntohl(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, value, 0xffffffe0, 32);
+ proto_tree_add_text(tree, tvb, curr_offset, 4,
+ "%s : Group or Broadcast call reference: %d (0x%04x)",
+ a_bigbuf,
+ (value & 0xffffffe0) >> 5,
+ (value & 0xffffffe0) >> 5);
+
+ my_decode_bitfield_value(a_bigbuf, value, 0x00000010, 32);
+ proto_tree_add_text(tree, tvb, curr_offset, 4,
+ "%s : SF Service Flag: %s",
+ a_bigbuf,
+ (value & 0x00000010) ?
+ "VGCS (Group call reference)" : "VBS (Broadcast call reference)");
+
+ my_decode_bitfield_value(a_bigbuf, value, 0x00000008, 32);
+ proto_tree_add_text(tree, tvb, curr_offset, 4,
+ "%s : AF Acknowledgement Flag: acknowledgment is %srequired",
+ a_bigbuf,
+ (value & 0x00000008) ? "" : "not ");
+
+ switch (value & 0x00000007)
+ {
+ case 1: str = "call priority level 4"; break;
+ case 2: str = "call priority level 3"; break;
+ case 3: str = "call priority level 2"; break;
+ case 4: str = "call priority level 1"; break;
+ case 5: str = "call priority level 0"; break;
+ case 6: str = "call priority level B"; break;
+ case 7: str = "call priority level A"; break;
+ default:
+ str = "no priority applied";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, value, 0x00000007, 32);
+ proto_tree_add_text(tree, tvb, curr_offset, 4,
+ "%s : Call Priority: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset += 4;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree, tvb, curr_offset, 1,
+ "%s : Ciphering Information",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree, tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.10a
+ */
+static guint8
+de_pd_sapi(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_PD_SAPI].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_PD_SAPI]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xc0, 8);
+ proto_tree_add_text(subtree, tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch ((oct & 0x30) >> 4)
+ {
+ case 0: str = "SAPI 0"; break;
+ case 3: str = "SAPI 3"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x30, 8);
+ proto_tree_add_text(subtree, tvb, curr_offset, 1,
+ "%s : SAPI (Sevice Access Point Identifier): %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(subtree, tvb, curr_offset, 1,
+ "%s : PD (Protocol Discriminator): %s",
+ a_bigbuf,
+ pd_str[oct & 0x0f]);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.11
+ */
+static guint8
+de_prio(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x07)
+ {
+ case 1: str = "Call priority level 4"; break;
+ case 2: str = "Call priority level 3"; break;
+ case 3: str = "Call priority level 2"; break;
+ case 4: str = "Call priority level 1"; break;
+ case 5: str = "Call priority level 0"; break;
+ case 6: str = "Call priority level B"; break;
+ case 7: str = "Call priority level A"; break;
+ default:
+ str = "No priority applied";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.1.13
+ */
+static guint8
+de_plmn_list(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 octs[3];
+ guint32 curr_offset;
+ gchar mcc[4];
+ gchar mnc[4];
+ guint8 num_plmn;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ num_plmn = 0;
+ while ((len - (curr_offset - offset)) >= 3)
+ {
+ octs[0] = tvb_get_guint8(tvb, curr_offset);
+ octs[1] = tvb_get_guint8(tvb, curr_offset + 1);
+ octs[2] = tvb_get_guint8(tvb, curr_offset + 2);
+
+ mcc_mnc_aux(octs, mcc, mnc);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 3,
+ "PLMN[%d] Mobile Country Code (MCC): %s, Mobile Network Code (MNC): %s",
+ num_plmn + 1,
+ mcc,
+ mnc);
+
+ curr_offset += 3;
+
+ num_plmn++;
+ }
+
+ sprintf(add_string, " - %d PLMN%s",
+ num_plmn, plurality(num_plmn, "", "s"));
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.2.31
+ */
+static guint8
+de_rr_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch (oct)
+ {
+ case 0x00: str = "Normal event"; break;
+ case 0x01: str = "Abnormal release, unspecified"; break;
+ case 0x02: str = "Abnormal release, channel unacceptable"; break;
+ case 0x03: str = "Abnormal release, timer expired"; break;
+ case 0x04: str = "Abnormal release, no activity on the radio path"; break;
+ case 0x05: str = "Preemptive release"; break;
+ case 0x08: str = "Handover impossible, timing advance out of range"; break;
+ case 0x09: str = "Channel mode unacceptable"; break;
+ case 0x0a: str = "Frequency not implemented"; break;
+ case 0x41: str = "Call already cleared"; break;
+ case 0x5f: str = "Semantically incorrect message"; break;
+ case 0x60: str = "Invalid mandatory information"; break;
+ case 0x61: str = "Message type non-existent or not implemented"; break;
+ case 0x62: str = "Message type not compatible with protocol state"; break;
+ case 0x64: str = "Conditional IE error"; break;
+ case 0x65: str = "No cell allocation available"; break;
+ case 0x6f: str = "Protocol error unspecified"; break;
+ default:
+ str = "Reserved, treat as Normal event";
+ break;
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "RR Cause value: 0x%02x (%d) %s",
+ oct,
+ oct,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.1
+ */
+static guint8
+de_auth_param_rand(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+/*
+ * 12 octets == 128 bits
+ */
+#define AUTH_PARAM_RAND_LEN 12
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, AUTH_PARAM_RAND_LEN,
+ "RAND value");
+
+ curr_offset += AUTH_PARAM_RAND_LEN;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.1.1
+ */
+static guint8
+de_auth_param_autn(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len,
+ "AUTN value");
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.2
+ */
+static guint8
+de_auth_resp_param(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+/*
+ * 4 octets == 32 bits
+ */
+#define AUTH_PARAM_RESP_LEN 4
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, AUTH_PARAM_RESP_LEN,
+ "SRES value");
+
+ curr_offset += AUTH_PARAM_RESP_LEN;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.2.1
+ */
+static guint8
+de_auth_resp_param_ext(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len,
+ "RES (extension) value");
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.2.2
+ */
+static guint8
+de_auth_fail_param(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len,
+ "AUTS value");
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.5a
+ */
+static guint8
+de_network_name(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ switch ((oct & 0x70) >> 4)
+ {
+ case 0x00: str = "Cell Broadcast data coding scheme, GSM default alphabet, language unspecified, defined in 3GPP TS 03.38"; break;
+ case 0x01: str = "UCS2 (16 bit)"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Coding Scheme: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Add CI: The MS should %s",
+ a_bigbuf,
+ (oct & 0x08) ?
+ "add the letters for the Country's Initials and a separator (e.g. a space) to the text string" :
+ "The MS should not add the letters for the Country's Initials to the text string");
+
+ switch (oct & 0x07)
+ {
+ case 1: str = "bit 8 is spare and set to '0' in octet n"; break;
+ case 2: str = "bits 7 and 8 are spare and set to '0' in octet n"; break;
+ case 3: str = "bits 6 to 8(inclusive) are spare and set to '0' in octet n"; break;
+ case 4: str = "bits 5 to 8(inclusive) are spare and set to '0' in octet n"; break;
+ case 5: str = "bits 4 to 8(inclusive) are spare and set to '0' in octet n"; break;
+ case 6: str = "bits 3 to 8(inclusive) are spare and set to '0' in octet n"; break;
+ case 7: str = "bits 2 to 8(inclusive) are spare and set to '0' in octet n"; break;
+ default:
+ str = "this field carries no information about the number of spare bits in octet n";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Number of spare bits in last octet: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - 1,
+ "Text string encoded according to Coding Scheme");
+
+ curr_offset += len - 1;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.6
+ */
+static guint8
+de_rej_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch (oct)
+ {
+ case 0x02: str = "IMSI unknown in HLR"; break;
+ case 0x03: str = "Illegal MS"; break;
+ case 0x04: str = "IMSI unknown in VLR"; break;
+ case 0x05: str = "IMEI not accepted"; break;
+ case 0x06: str = "Illegal ME"; break;
+ case 0x0b: str = "PLMN not allowed"; break;
+ case 0x0c: str = "Location Area not allowed"; break;
+ case 0x0d: str = "Roaming not allowed in this location area"; break;
+ case 0x0f: str = "No Suitable Cells In Location Area"; break;
+ case 0x11: str = "Network failure"; break;
+ case 0x14: str = "MAC failure"; break;
+ case 0x15: str = "Synch failure"; break;
+ case 0x16: str = "Congestion"; break;
+ case 0x17: str = "GSM authentication unacceptable"; break;
+ case 0x20: str = "Service option not supported"; break;
+ case 0x21: str = "Requested service option not subscribed"; break;
+ case 0x22: str = "Service option temporarily out of order"; break;
+ case 0x26: str = "Call cannot be identified"; break;
+ case 0x5f: str = "Semantically incorrect message"; break;
+ case 0x60: str = "Invalid mandatory information"; break;
+ case 0x61: str = "Message type non-existent or not implemented"; break;
+ case 0x62: str = "Message type not compatible with the protocol state"; break;
+ case 0x63: str = "Information element non-existent or not implemented"; break;
+ case 0x64: str = "Conditional IE error"; break;
+ case 0x65: str = "Message not compatible with the protocol state"; break;
+ case 0x6f: str = "Protocol error, unspecified"; break;
+ default:
+ switch (is_uplink)
+ {
+ case IS_UPLINK_FALSE:
+ str = "Service option temporarily out of order";
+ break;
+ default:
+ str = "Protocol error, unspecified";
+ break;
+ }
+ break;
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Reject Cause value: 0x%02x (%d) %s",
+ oct,
+ oct,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.8
+ */
+static guint8
+de_time_zone(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Time Zone: 0x%02x (%d)",
+ oct,
+ oct);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.9
+ */
+static guint8
+de_time_zone_time(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct, oct2, oct3;
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+ oct2 = tvb_get_guint8(tvb, curr_offset+1);
+ oct3 = tvb_get_guint8(tvb, curr_offset+2);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 3,
+ "Year %d%d, Month %d%d, Day %d%d",
+ oct & 0x0f,
+ (oct & 0xf0) >> 4,
+ oct2 & 0x0f,
+ (oct2 & 0xf0) >> 4,
+ oct3 & 0x0f,
+ (oct3 & 0xf0) >> 4);
+
+ curr_offset += 3;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+ oct2 = tvb_get_guint8(tvb, curr_offset+1);
+ oct3 = tvb_get_guint8(tvb, curr_offset+2);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 3,
+ "Hour %d%d, Minutes %d%d, Seconds %d%d",
+ oct & 0x0f,
+ (oct & 0xf0) >> 4,
+ oct2 & 0x0f,
+ (oct2 & 0xf0) >> 4,
+ oct3 & 0x0f,
+ (oct3 & 0xf0) >> 4);
+
+ curr_offset += 3;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Time Zone: 0x%02x (%d)",
+ oct,
+ oct);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.11
+ */
+static guint8
+de_lsa_id(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len,
+ "LSA ID");
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.3.12
+ */
+static guint8
+de_day_saving_time(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xfc, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x03)
+ {
+ case 0: str = "No adjustment for Daylight Saving Time"; break;
+ case 1: str = "+1 hour adjustment for Daylight Saving Time"; break;
+ case 2: str = "+2 hours adjustment for Daylight Saving Time"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x03, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.4
+ */
+static guint8
+de_aux_states(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch ((oct & 0x0c) >> 2)
+ {
+ case 0: str = "Idle"; break;
+ case 1: str = "Hold request"; break;
+ case 2: str = "Call held"; break;
+ default:
+ str = "Retrieve request";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0c, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Hold auxiliary state: %s",
+ a_bigbuf,
+ str);
+
+ switch (oct & 0x03)
+ {
+ case 0: str = "Idle"; break;
+ case 1: str = "MPTY request"; break;
+ case 2: str = "Call in MPTY"; break;
+ default:
+ str = "Split request";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x03, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Multi party auxiliary state: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.5a
+ */
+static guint8
+de_cc_cap(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+
+ switch ((oct & 0xf0) >> 4)
+ {
+ case 0:
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Maximum number of supported bearers: 1",
+ a_bigbuf);
+ break;
+
+ default:
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Maximum number of supported bearers: %d",
+ a_bigbuf,
+ (oct & 0xf0) >> 4);
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0c, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x02, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : PCP: the mobile station %s the Prolonged Clearing Procedure",
+ a_bigbuf,
+ (oct & 0x02) ? "supports" : "does not support");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x01, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : DTMF: %s",
+ a_bigbuf,
+ (oct & 0x01) ?
+ "the mobile station supports DTMF as specified in subclause 5.5.7 of TS 24.008" :
+ "reserved for earlier versions of the protocol");
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Maximum number of speech bearers: %d",
+ a_bigbuf,
+ oct & 0x0f);
+
+ curr_offset++;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.6
+ */
+static guint8
+de_call_state(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CALL_STATE].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CALL_STATE]);
+
+ switch ((oct & 0xc0) >> 6)
+ {
+ case 0: str = "Coding as specified in ITU-T Rec. Q.931"; break;
+ case 1: str = "Reserved for other international standards"; break;
+ case 2: str = "National standard"; break;
+ default:
+ str = "Standard defined for the GSM PLMNS";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xc0, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Coding standard: %s",
+ a_bigbuf,
+ str);
+
+ switch (oct & 0x3f)
+ {
+ case 0x00: str = "UO - null NO - null"; break;
+ case 0x02: str = "U0.1- MM connection pending N0.1- MM connection pending"; break;
+ case 0x22: str = "U0.2- CC prompt present N0.2- CC connection pending"; break;
+ case 0x23: str = "U0.3- Wait for network information N0.3- Network answer pending"; break;
+ case 0x24: str = "U0.4- CC-Establishment present N0.4- CC-Establishment present"; break;
+ case 0x25: str = "U0.5- CC-Establishment confirmed N0.5- CC-Establishment confirmed"; break;
+ case 0x26: str = "U0.6- Recall present N0.6- Recall present"; break;
+ case 0x01: str = "U1 - call initiated N1 - call initiated"; break;
+ case 0x03: str = "U3 - mobile originating call proceeding N3 - mobile originating call proceeding"; break;
+ case 0x04: str = "U4 - call delivered N4 - call delivered"; break;
+ case 0x06: str = "U6 - call present N6 - call present"; break;
+ case 0x07: str = "U7 - call received N7 - call received"; break;
+ case 0x08: str = "U8 - connect request N8 - connect request"; break;
+ case 0x09: str = "U9 - mobile terminating call confirmed N9 - mobile terminating call confirmed"; break;
+ case 0x0a: str = "U10- active N10- active"; break;
+ case 0x0b: str = "U11- disconnect request"; break;
+ case 0x0c: str = "U12- disconnect indication N12-disconnect indication"; break;
+ case 0x13: str = "U19- release request N19- release request"; break;
+ case 0x1a: str = "U26- mobile originating modify N26- mobile originating modify"; break;
+ case 0x1b: str = "U27- mobile terminating modify N27- mobile terminating modify"; break;
+ case 0x1c: str = " N28- connect indication"; break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Call state value: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.7
+ */
+static guint8
+de_cld_party_bcd_num(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint8 ton;
+ guint8 *poctets;
+ guint32 curr_offset;
+ gchar *str;
+
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ ton = (oct & 0x70) >> 4;
+ switch (ton)
+ {
+ case 0: str = "Unknown"; break;
+ case 1: str = "International number"; break;
+ case 2: str = "National number"; break;
+ case 3: str = "Network specific number"; break;
+ case 4: str = "Dedicated access, short code"; break;
+ case 7: str = "Reserved for extension"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of number: %s",
+ a_bigbuf,
+ str);
+
+ if ((ton == 0) ||
+ (ton == 1) ||
+ (ton == 2) ||
+ (ton == 4))
+ {
+ switch (oct & 0x0f)
+ {
+ case 0: str = "Unknown"; break;
+ case 1: str = "ISDN/telephony numbering plan (Rec. E.164/E.163)"; break;
+ case 3: str = "Data numbering plan (Recommendation X.121)"; break;
+ case 4: str = "Telex numbering plan (Recommendation F.69)"; break;
+ case 8: str = "National numbering plan"; break;
+ case 9: str = "Private numbering plan"; break;
+ case 11: str = "Reserved for CTS (see 3GPP TS 44.056)"; break;
+ case 15: str = "Reserved for extension"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+ }
+ else
+ {
+ str = "not applicable";
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Numbering plan identification: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ poctets = tvb_get_string(tvb, curr_offset, len - (curr_offset - offset));
+
+ my_dgt_tbcd_unpack(a_bigbuf, poctets, len - (curr_offset - offset),
+ &Dgt_mbcd);
+ g_free(poctets);
+
+ proto_tree_add_string_format(tree, hf_gsm_a_cld_party_bcd_num,
+ tvb, curr_offset, len - (curr_offset - offset),
+ a_bigbuf,
+ "BCD Digits: %s",
+ a_bigbuf);
+
+ curr_offset += len - (curr_offset - offset);
+
+ sprintf(add_string, " - (%s)", a_bigbuf);
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.8
+ */
+static guint8
+de_cld_party_sub_addr(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ switch ((oct & 0x70) >> 4)
+ {
+ case 0: str = "NSAP (X.213/ISO 8348 AD2)"; break;
+ case 2: str = "User specified"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of subaddress: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Odd/Even indicator: %s",
+ a_bigbuf,
+ (oct & 0x08) ?
+ "odd number of address signals" : "even number of address signals");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - (curr_offset - offset),
+ "Subaddress information");
+
+ curr_offset += len - (curr_offset - offset);
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.9
+ */
+static guint8
+de_clg_party_bcd_num(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint8 ton;
+ guint8 *poctets;
+ guint32 curr_offset;
+ gchar *str;
+
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ ton = (oct & 0x70) >> 4;
+ switch (ton)
+ {
+ case 0: str = "Unknown"; break;
+ case 1: str = "International number"; break;
+ case 2: str = "National number"; break;
+ case 3: str = "Network specific number"; break;
+ case 4: str = "Dedicated access, short code"; break;
+ case 7: str = "Reserved for extension"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of number: %s",
+ a_bigbuf,
+ str);
+
+ if ((ton == 0) ||
+ (ton == 1) ||
+ (ton == 2) ||
+ (ton == 4))
+ {
+ switch (oct & 0x0f)
+ {
+ case 0: str = "Unknown"; break;
+ case 1: str = "ISDN/telephony numbering plan (Rec. E.164/E.163)"; break;
+ case 3: str = "Data numbering plan (Recommendation X.121)"; break;
+ case 4: str = "Telex numbering plan (Recommendation F.69)"; break;
+ case 8: str = "National numbering plan"; break;
+ case 9: str = "Private numbering plan"; break;
+ case 11: str = "Reserved for CTS (see 3GPP TS 44.056)"; break;
+ case 15: str = "Reserved for extension"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+ }
+ else
+ {
+ str = "not applicable";
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Numbering plan identification: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ switch ((oct & 0x60) >> 5)
+ {
+ case 0: str = "Presentation allowed"; break;
+ case 1: str = "Presentation restricted"; break;
+ case 2: str = "Number not available due to interworking"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x60, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Presentation indicator: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x1c, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x03)
+ {
+ case 0: str = "User-provided, not screened"; break;
+ case 1: str = "User-provided, verified and passed"; break;
+ case 2: str = "User-provided, verified and failed"; break;
+ default:
+ str = "Network provided";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x03, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Screening indicator: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ poctets = tvb_get_string(tvb, curr_offset, len - (curr_offset - offset));
+
+ my_dgt_tbcd_unpack(a_bigbuf, poctets, len - (curr_offset - offset),
+ &Dgt_mbcd);
+ g_free(poctets);
+
+ proto_tree_add_string_format(tree, hf_gsm_a_clg_party_bcd_num,
+ tvb, curr_offset, len - (curr_offset - offset),
+ a_bigbuf,
+ "BCD Digits: %s",
+ a_bigbuf);
+
+ curr_offset += len - (curr_offset - offset);
+
+ sprintf(add_string, " - (%s)", a_bigbuf);
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.10
+ */
+static guint8
+de_clg_party_sub_addr(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ switch ((oct & 0x70) >> 4)
+ {
+ case 0: str = "NSAP (X.213/ISO 8348 AD2)"; break;
+ case 2: str = "User specified"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Type of subaddress: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Odd/Even indicator: %s",
+ a_bigbuf,
+ (oct & 0x08) ?
+ "odd number of address signals" : "even number of address signals");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ curr_offset++;
+
+ NO_MORE_DATA_CHECK(len);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - (curr_offset - offset),
+ "Subaddress information");
+
+ curr_offset += len - (curr_offset - offset);
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.11
+ */
+static guint8
+de_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint8 cause;
+ guint32 curr_offset;
+ gchar *str;
+
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension: %s",
+ a_bigbuf,
+ (oct & 0x80) ? "not extended" : "extended");
+
+ switch ((oct & 0x60) >> 5)
+ {
+ case 0: str = "Coding as specified in ITU-T Rec. Q.931"; break;
+ case 1: str = "Reserved for other international standards"; break;
+ case 2: str = "National standard"; break;
+ default:
+ str = "Standard defined for the GSM PLMNS";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x60, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Coding standard: %s",
+ a_bigbuf,
+ str);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x10, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x0f)
+ {
+ case 0: str = "User"; break;
+ case 1: str = "Private network serving the local user"; break;
+ case 2: str = "Public network serving the local user"; break;
+ case 3: str = "Transit network"; break;
+ case 4: str = "Public network serving the remote user"; break;
+ case 5: str = "Private network serving the remote user"; break;
+ case 7: str = "International network"; break;
+ case 10: str = "Network beyond interworking point"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Location: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ if (!(oct & 0x80))
+ {
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Recommendation",
+ a_bigbuf);
+
+ curr_offset++;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ cause = oct & 0x7f;
+ switch (cause)
+ {
+ case 1: str = "Unassigned (unallocated) number"; break;
+ case 3: str = "No route to destination"; break;
+ case 6: str = "Channel unacceptable"; break;
+ case 8: str = "Operator determined barring"; break;
+ case 16: str = "Normal call clearing"; break;
+ case 17: str = "User busy"; break;
+ case 18: str = "No user responding"; break;
+ case 19: str = "User alerting, no answer"; break;
+ case 21: str = "Call rejected"; break;
+ case 22: str = "Number changed"; break;
+ case 25: str = "Pre-emption"; break;
+ case 26: str = "Non selected user clearing"; break;
+ case 27: str = "Destination out of order"; break;
+ case 28: str = "Invalid number format (incomplete number)"; break;
+ case 29: str = "Facility rejected"; break;
+ case 30: str = "Response to STATUS ENQUIRY"; break;
+ case 31: str = "Normal, unspecified"; break;
+ case 34: str = "No circuit/channel available"; break;
+ case 38: str = "Network out of order"; break;
+ case 41: str = "Temporary failure"; break;
+ case 42: str = "Switching equipment congestion"; break;
+ case 43: str = "Access information discarded"; break;
+ case 44: str = "requested circuit/channel not available"; break;
+ case 47: str = "Resources unavailable, unspecified"; break;
+ case 49: str = "Quality of service unavailable"; break;
+ case 50: str = "Requested facility not subscribed"; break;
+ case 55: str = "Incoming calls barred within the CUG"; break;
+ case 57: str = "Bearer capability not authorized"; break;
+ case 58: str = "Bearer capability not presently available"; break;
+ case 63: str = "Service or option not available, unspecified"; break;
+ case 65: str = "Bearer service not implemented"; break;
+ case 68: str = "ACM equal to or greater than ACMmax"; break;
+ case 69: str = "Requested facility not implemented"; break;
+ case 70: str = "Only restricted digital information bearer capability is available"; break;
+ case 79: str = "Service or option not implemented, unspecified"; break;
+ case 81: str = "Invalid transaction identifier value"; break;
+ case 87: str = "User not member of CUG"; break;
+ case 88: str = "Incompatible destination"; break;
+ case 91: str = "Invalid transit network selection"; break;
+ case 95: str = "Semantically incorrect message"; break;
+ case 96: str = "Invalid mandatory information"; break;
+ case 97: str = "Message type non-existent or not implemented"; break;
+ case 98: str = "Message type not compatible with protocol state"; break;
+ case 99: str = "Information element non-existent or not implemented"; break;
+ case 100: str = "Conditional IE error"; break;
+ case 101: str = "Message not compatible with protocol state"; break;
+ case 102: str = "Recovery on timer expiry"; break;
+ case 111: str = "Protocol error, unspecified"; break;
+ case 127: str = "Interworking, unspecified"; break;
+ default:
+ if (cause <= 31) { str = "Treat as Normal, unspecified"; }
+ else if ((cause >= 32) && (cause <= 47)) { str = "Treat as Resources unavailable, unspecified"; }
+ else if ((cause >= 48) && (cause <= 63)) { str = "Treat as Service or option not available, unspecified"; }
+ else if ((cause >= 64) && (cause <= 79)) { str = "Treat as Service or option not implemented, unspecified"; }
+ else if ((cause >= 80) && (cause <= 95)) { str = "Treat as Semantically incorrect message"; }
+ else if ((cause >= 96) && (cause <= 111)) { str = "Treat as Protocol error, unspecified"; }
+ else if ((cause >= 112) && (cause <= 127)) { str = "Treat as Interworking, unspecified"; }
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Cause: (%d) %s",
+ a_bigbuf,
+ cause,
+ str);
+
+ curr_offset++;
+
+ sprintf(add_string, " - (%d) %s", cause, str);
+
+ NO_MORE_DATA_CHECK(len);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - (curr_offset - offset),
+ "Diagnostics");
+
+ curr_offset += len - (curr_offset - offset);
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.17
+ */
+static guint8
+de_keypad_facility(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch ((oct & 0x60) >> 5)
+ {
+ case 0: str = "Coding as specified in ITU-T Rec. Q.931"; break;
+ case 1: str = "Reserved for other international standards"; break;
+ case 2: str = "National standard"; break;
+ default:
+ str = "Standard defined for the GSM PLMNS";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Keypad information: %c",
+ a_bigbuf,
+ oct & 0x7f);
+
+ curr_offset++;
+
+ sprintf(add_string, " - %c", oct & 0x7f);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [3] 10.5.4.22
+ */
+static guint8
+de_repeat_ind(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch (oct & 0x0f)
+ {
+ case 1: str = "Circular for successive selection 'mode 1 alternate mode 2'"; break;
+ case 2: str = "Support of fallback mode 1 preferred, mode 2 selected if setup of mode 1 fails"; break;
+ case 3: str = "Reserved: was allocated in earlier phases of the protocol"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [6] 3.7.2
+ */
+static guint8
+de_ss_ver_ind(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch (oct)
+ {
+ case 0: str = "Phase 2 service, ellipsis notation, and phase 2 error handling is supported"; break;
+ case 1: str = "SS-Protocol version 3 is supported, and phase 2 error handling is supported"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s",
+ str);
+
+ curr_offset++;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [5] 8.1.4.1
+ */
+static guint8
+de_cp_user_data(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+ tvbuff_t *rp_tvb;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree, tvb, curr_offset, len,
+ "RPDU");
+
+ /*
+ * dissect the embedded RP message
+ */
+ rp_tvb = tvb_new_subset(tvb, curr_offset, len, len);
+
+ call_dissector(rp_handle, rp_tvb, g_pinfo, g_tree);
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [5] 8.1.4.2
+ */
+static guint8
+de_cp_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ len = len;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ switch (oct)
+ {
+ case 17: str = "Network failure"; break;
+ case 22: str = "Congestion"; break;
+ case 81: str = "Invalid Transaction Identifier value"; break;
+ case 95: str = "Semantically incorrect message"; break;
+ case 96: str = "Invalid mandatory information"; break;
+ case 97: str = "Message type non-existent or not implemented"; break;
+ case 98: str = "Message not compatible with the short message protocol state"; break;
+ case 99: str = "Information element non-existent or not implemented"; break;
+ case 111: str = "Protocol error, unspecified"; break;
+ default:
+ str = "Reserved, treat as Protocol error, unspecified";
+ break;
+ }
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "Cause: (%d) %s",
+ oct,
+ str);
+
+ curr_offset++;
+
+ sprintf(add_string, " - (%d) %s", oct, str);
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [5] 8.2.3
+ */
+static guint8
+de_rp_message_ref(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+
+ len = len;
+ add_string = add_string;
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "RP-Message Reference: 0x%02x (%d)",
+ oct,
+ oct);
+
+ curr_offset++;
+
+ /* no length check possible */
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [5] 8.2.5.1
+ */
+static guint8
+de_rp_orig_addr(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ return(de_cld_party_bcd_num(tvb, tree, offset, len, add_string));
+}
+
+/*
+ * [5] 8.2.5.2
+ */
+static guint8
+de_rp_dest_addr(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ return(de_cld_party_bcd_num(tvb, tree, offset, len, add_string));
+}
+
+/*
+ * [5] 8.2.5.3
+ */
+static guint8
+de_rp_user_data(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint32 curr_offset;
+ tvbuff_t *tpdu_tvb;
+
+ add_string = add_string;
+ curr_offset = offset;
+
+ proto_tree_add_text(tree, tvb, curr_offset, len,
+ "TPDU");
+
+ /*
+ * dissect the embedded TPDU message
+ */
+ tpdu_tvb = tvb_new_subset(tvb, curr_offset, len, len);
+
+ dissector_try_port(sms_dissector_table, gsm_a_rp_type, tpdu_tvb, g_pinfo, g_tree);
+
+ curr_offset += len;
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+/*
+ * [5] 8.2.5.4
+ */
+static guint8
+de_rp_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ gchar *str;
+
+ curr_offset = offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Extension: %s",
+ a_bigbuf,
+ (oct & 0x80) ? "extended" : "not extended");
+
+ switch (oct & 0x7f)
+ {
+ case 1: str = "Unassigned (unallocated) number"; break;
+ case 8: str = "Operator determined barring"; break;
+ case 10: str = "Call barred"; break;
+ case 11: str = "Reserved"; break;
+ case 21: str = "Short message transfer rejected"; break;
+ case 22: str = "Memory capacity exceeded"; break;
+ case 27: str = "Destination out of order"; break;
+ case 28: str = "Unidentified subscriber"; break;
+ case 29: str = "Facility rejected"; break;
+ case 30: str = "Unknown subscriber"; break;
+ case 38: str = "Network out of order"; break;
+ case 41: str = "Temporary failure"; break;
+ case 42: str = "Congestion"; break;
+ case 47: str = "Resources unavailable, unspecified"; break;
+ case 50: str = "Requested facility not subscribed"; break;
+ case 69: str = "Requested facility not implemented"; break;
+ case 81: str = "Invalid short message transfer reference value"; break;
+ case 95: str = "Semantically incorrect message"; break;
+ case 96: str = "Invalid mandatory information"; break;
+ case 97: str = "Message type non-existent or not implemented"; break;
+ case 98: str = "Message not compatible with short message protocol state"; break;
+ case 99: str = "Information element non-existent or not implemented"; break;
+ case 111: str = "Protocol error, unspecified"; break;
+ case 127: str = "Interworking, unspecified"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Cause: (%d) %s",
+ a_bigbuf,
+ oct & 0x7f,
+ str);
+
+ curr_offset++;
+
+ sprintf(add_string, " - (%d) %s", oct & 0x7f, str);
+
+ NO_MORE_DATA_CHECK(len);
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, len - (curr_offset - offset),
+ "Diagnostic field");
+
+ curr_offset += len - (curr_offset - offset);
+
+ EXTRANEOUS_DATA_CHECK(len, curr_offset - offset);
+
+ return(curr_offset - offset);
+}
+
+static guint8 (*bssmap_elem_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string) = {
+ be_cic, /* Circuit Identity Code */
+ NULL, /* Reserved */
+ NULL, /* Resource Available */
+ be_cause, /* Cause */
+ be_cell_id, /* Cell Identifier */
+ be_prio, /* Priority */
+ be_l3_header_info, /* Layer 3 Header Information */
+ de_mid, /* IMSI */
+ be_tmsi, /* TMSI */
+ be_enc_info, /* Encryption Information */
+ be_chan_type, /* Channel Type */
+ NULL, /* Periodicity */
+ NULL, /* Extended Resource Indicator */
+ NULL, /* Number Of MSs */
+ NULL, /* Reserved */
+ NULL, /* Reserved */
+ NULL, /* Reserved */
+ de_ms_cm_2, /* Classmark Information Type 2 */
+ NULL, /* Classmark Information Type 3 */
+ NULL, /* Interference Band To Be Used */
+ de_rr_cause, /* RR Cause */
+ NULL, /* Reserved */
+ be_l3_info, /* Layer 3 Information */
+ be_dlci, /* DLCI */
+ be_down_dtx_flag, /* Downlink DTX Flag */
+ be_cell_id_list, /* Cell Identifier List */
+ NULL /* no associated data */, /* Response Request */
+ NULL, /* Resource Indication Method */
+ de_ms_cm_1, /* Classmark Information Type 1 */
+ NULL, /* Circuit Identity Code List */
+ NULL, /* Diagnostic */
+ be_l3_msg, /* Layer 3 Message Contents */
+ be_chosen_chan, /* Chosen Channel */
+ NULL, /* Total Resource Accessible */
+ be_ciph_resp_mode, /* Cipher Response Mode */
+ NULL, /* Channel Needed */
+ NULL, /* Trace Type */
+ NULL, /* TriggerID */
+ NULL, /* Trace Reference */
+ NULL, /* TransactionID */
+ de_mid, /* Mobile Identity */
+ NULL, /* OMCID */
+ be_for_ind, /* Forward Indicator */
+ be_chosen_enc_alg, /* Chosen Encryption Algorithm */
+ be_cct_pool, /* Circuit Pool */
+ NULL, /* Circuit Pool List */
+ NULL, /* Time Indication */
+ NULL, /* Resource Situation */
+ be_curr_chan_1, /* Current Channel Type 1 */
+ be_que_ind, /* Queueing Indicator */
+ be_speech_ver, /* Speech Version */
+ NULL, /* Assignment Requirement */
+ NULL /* no associated data */, /* Talker Flag */
+ NULL /* no associated data */, /* Connection Release Requested */
+ NULL, /* Group Call Reference */
+ NULL, /* eMLPP Priority */
+ NULL, /* Configuration Evolution Indication */
+ NULL /* no decode required */, /* Old BSS to New BSS Information */
+ NULL, /* LSA Identifier */
+ NULL, /* LSA Identifier List */
+ NULL, /* LSA Information */
+ NULL, /* LCS QoS */
+ NULL, /* LSA access control suppression */
+ NULL, /* LCS Priority */
+ NULL, /* Location Type */
+ NULL, /* Location Estimate */
+ NULL, /* Positioning Data */
+ NULL, /* LCS Cause */
+ NULL, /* LCS Client Type */
+ be_apdu, /* APDU */
+ NULL, /* Network Element Identity */
+ NULL, /* GPS Assistance Data */
+ NULL, /* Deciphering Keys */
+ NULL, /* Return Error Request */
+ NULL, /* Return Error Cause */
+ NULL, /* Segmentation */
+ NULL, /* NONE */
+};
+
+static guint8 (*dtap_elem_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string) = {
+ /* Common Information Elements 10.5.1 */
+ de_cell_id, /* Cell Identity */
+ NULL /* handled inline */, /* Ciphering Key Sequence Number */
+ de_lai, /* Location Area Identification */
+ de_mid, /* Mobile Identity */
+ de_ms_cm_1, /* Mobile Station Classmark 1 */
+ de_ms_cm_2, /* Mobile Station Classmark 2 */
+ NULL, /* Mobile Station Classmark 3 */
+ de_d_gb_call_ref, /* Descriptive group or broadcast call reference */
+ NULL /* handled inline */, /* Group Cipher Key Number */
+ de_pd_sapi, /* PD and SAPI $(CCBS)$ */
+ de_prio /* handled inline */, /* Priority Level */
+ de_plmn_list, /* PLMN List */
+ /* Radio Resource Management Information Elements 10.5.2, most are from 10.5.1 */
+ de_rr_cause, /* RR Cause */
+ /* Mobility Management Information Elements 10.5.3 */
+ de_auth_param_rand, /* Authentication Parameter RAND */
+ de_auth_param_autn, /* Authentication Parameter AUTN (UMTS authentication challenge only) */
+ de_auth_resp_param, /* Authentication Response Parameter */
+ de_auth_resp_param_ext, /* Authentication Response Parameter (extension) (UMTS authentication challenge only) */
+ de_auth_fail_param, /* Authentication Failure Parameter (UMTS authentication challenge only) */
+ NULL /* handled inline */, /* CM Service Type */
+ NULL /* handled inline */, /* Identity Type */
+ NULL /* handled inline */, /* Location Updating Type */
+ de_network_name, /* Network Name */
+ de_rej_cause, /* Reject Cause */
+ NULL /* no associated data */, /* Follow-on Proceed */
+ de_time_zone, /* Time Zone */
+ de_time_zone_time, /* Time Zone and Time */
+ NULL /* no associated data */, /* CTS Permission */
+ de_lsa_id, /* LSA Identifier */
+ de_day_saving_time, /* Daylight Saving Time */
+ /* Call Control Information Elements 10.5.4 */
+ de_aux_states, /* Auxiliary States */
+ NULL, /* Bearer Capability */
+ de_cc_cap, /* Call Control Capabilities */
+ de_call_state, /* Call State */
+ de_cld_party_bcd_num, /* Called Party BCD Number */
+ de_cld_party_sub_addr, /* Called Party Subaddress */
+ de_clg_party_bcd_num, /* Calling Party BCD Number */
+ de_clg_party_sub_addr, /* Calling Party Subaddress */
+ de_cause, /* Cause */
+ NULL /* no associated data */, /* CLIR Suppression */
+ NULL /* no associated data */, /* CLIR Invocation */
+ NULL /* handled inline */, /* Congestion Level */
+ NULL, /* Connected Number */
+ NULL, /* Connected Subaddress */
+ NULL, /* Facility */
+ NULL, /* High Layer Compatibility */
+ de_keypad_facility, /* Keypad Facility */
+ NULL, /* Low Layer Compatibility */
+ NULL, /* More Data */
+ NULL, /* Notification Indicator */
+ NULL, /* Progress Indicator */
+ NULL, /* Recall type $(CCBS)$ */
+ NULL, /* Redirecting Party BCD Number */
+ NULL, /* Redirecting Party Subaddress */
+ de_repeat_ind, /* Repeat Indicator */
+ NULL /* no associated data */, /* Reverse Call Setup Direction */
+ NULL, /* SETUP Container $(CCBS)$ */
+ NULL, /* Signal */
+ de_ss_ver_ind, /* SS Version Indicator */
+ NULL, /* User-user */
+ NULL, /* Alerting Pattern $(NIA)$ */
+ NULL, /* Allowed Actions $(CCBS)$ */
+ NULL, /* Stream Identifier */
+ NULL, /* Network Call Control Capabilities */
+ NULL, /* Cause of No CLI */
+ NULL, /* Immediate Modification Indicator */
+ NULL, /* Supported Codec List */
+ NULL, /* Service Category */
+ /* GPRS Mobility Management Information Elements 10.5.5 */
+ NULL, /* Attach Result */
+ NULL, /* Attach Type */
+ NULL, /* TMSI Status */
+ NULL, /* Detach Type */
+ NULL, /* DRX Parameter */
+ NULL, /* Force to Standby */
+ NULL, /* P-TMSI Signature */
+ NULL, /* P-TMSI Signature 2 */
+ NULL, /* Identity Type 2 */
+ NULL, /* IMEISV Request */
+ NULL, /* Receive N-PDU Numbers List */
+ NULL, /* MS Network Capability */
+ NULL, /* MS Radio Access Capability */
+ NULL, /* GMM Cause */
+ NULL, /* Routing Area Identification */
+ NULL, /* Update Result */
+ NULL, /* A&C Reference Number */
+ NULL, /* Service Type */
+ NULL, /* Cell Notification */
+ NULL, /* Network Feature Support */
+ /* Short Message Service Information Elements [5] 8.1.4 */
+ de_cp_user_data, /* CP-User Data */
+ de_cp_cause, /* CP-Cause */
+ /* Short Message Service Information Elements [5] 8.2 */
+ de_rp_message_ref, /* RP-Message Reference */
+ de_rp_orig_addr, /* RP-Origination Address */
+ de_rp_dest_addr, /* RP-Destination Address */
+ de_rp_user_data, /* RP-User Data */
+ de_rp_cause, /* RP-Cause */
+ /* Session Management Information Elements 10.5.6 */
+ NULL, /* Access Point Name */
+ NULL, /* Network Service Access Point Identifier */
+ NULL, /* Protocol Configuration Options */
+ NULL, /* Packet Data Protocol Address */
+ NULL, /* Quality Of Service */
+ NULL, /* SM Cause */
+ NULL, /* Linked TI */
+ NULL, /* LLC Service Access Point Identifier */
+ NULL, /* Tear Down Indicator */
+ NULL, /* Packet Flow Identifier */
+ NULL, /* Traffic Flow Template */
+ /* GPRS Common Information Elements 10.5.7 */
+ NULL, /* PDP Context Status */
+ NULL, /* Radio Priority */
+ NULL, /* GPRS Timer */
+ NULL, /* GPRS Timer 2 */
+ NULL, /* NONE */
+};
+
+#define SET_ELEM_VARS(SEV_pdu_type, SEV_elem_names, SEV_elem_ett, SEV_elem_funcs) \
+ switch (SEV_pdu_type) \
+ { \
+ case BSSAP_PDU_TYPE_BSSMAP: \
+ SEV_elem_names = gsm_bssmap_elem_strings; \
+ SEV_elem_ett = ett_gsm_bssmap_elem; \
+ SEV_elem_funcs = bssmap_elem_fcn; \
+ break; \
+ case BSSAP_PDU_TYPE_DTAP: \
+ SEV_elem_names = gsm_dtap_elem_strings; \
+ SEV_elem_ett = ett_gsm_dtap_elem; \
+ SEV_elem_funcs = dtap_elem_fcn; \
+ break; \
+ default: \
+ proto_tree_add_text(tree, \
+ tvb, curr_offset, -1, \
+ "Unknown PDU type (%d)", SEV_pdu_type); \
+ return(consumed); \
+ }
+
+/*
+ * Type Length Value (TLV) element dissector
+ */
+static guint8
+elem_tlv(tvbuff_t *tvb, proto_tree *tree, guint8 iei, gint pdu_type, int idx, guint32 offset, guint len, gchar *name_add)
+{
+ guint8 oct, parm_len;
+ guint8 consumed;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ const value_string *elem_names;
+ gint *elem_ett;
+ guint8 (**elem_funcs)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string);
+
+ len = len;
+ curr_offset = offset;
+ consumed = 0;
+
+ SET_ELEM_VARS(pdu_type, elem_names, elem_ett, elem_funcs);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ if (oct == iei)
+ {
+ parm_len = tvb_get_guint8(tvb, curr_offset + 1);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, parm_len + 2,
+ "%s%s",
+ elem_names[idx].strptr,
+ (name_add == NULL) || (name_add[0] == '\0') ? "" : name_add);
+
+ subtree = proto_item_add_subtree(item, elem_ett[idx]);
+
+ proto_tree_add_uint(subtree,
+ (BSSAP_PDU_TYPE_BSSMAP == pdu_type) ? hf_gsm_a_bssmap_elem_id : hf_gsm_a_dtap_elem_id, tvb,
+ curr_offset, 1, oct);
+
+ proto_tree_add_uint(subtree, hf_gsm_a_length, tvb,
+ curr_offset + 1, 1, parm_len);
+
+ if (parm_len > 0)
+ {
+ if (elem_funcs[idx] == NULL)
+ {
+ proto_tree_add_text(subtree,
+ tvb, curr_offset + 2, parm_len,
+ "Element Value");
+
+ consumed = parm_len;
+ }
+ else
+ {
+ a_add_string[0] = '\0';
+ consumed =
+ (*elem_funcs[idx])(tvb, subtree, curr_offset + 2,
+ parm_len, a_add_string);
+
+ if (a_add_string[0] != '\0')
+ {
+ proto_item_append_text(item, a_add_string);
+ a_add_string[0] = '\0';
+ }
+ }
+ }
+
+ consumed += 2;
+ }
+
+ return(consumed);
+}
+
+/*
+ * Type Value (TV) element dissector
+ *
+ * Length cannot be used in these functions, big problem if a element dissector
+ * is not defined for these.
+ */
+static guint8
+elem_tv(tvbuff_t *tvb, proto_tree *tree, guint8 iei, gint pdu_type, int idx, guint32 offset, gchar *name_add)
+{
+ guint8 oct;
+ guint8 consumed;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ const value_string *elem_names;
+ gint *elem_ett;
+ guint8 (**elem_funcs)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string);
+
+ curr_offset = offset;
+ consumed = 0;
+
+ SET_ELEM_VARS(pdu_type, elem_names, elem_ett, elem_funcs);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ if (oct == iei)
+ {
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, -1,
+ "%s%s",
+ elem_names[idx].strptr,
+ (name_add == NULL) || (name_add[0] == '\0') ? "" : name_add);
+
+ subtree = proto_item_add_subtree(item, elem_ett[idx]);
+
+ proto_tree_add_uint(subtree,
+ (BSSAP_PDU_TYPE_BSSMAP == pdu_type) ? hf_gsm_a_bssmap_elem_id : hf_gsm_a_dtap_elem_id, tvb,
+ curr_offset, 1, oct);
+
+ if (elem_funcs[idx] == NULL)
+ {
+ /* BAD THING, CANNOT DETERMINE LENGTH */
+
+ proto_tree_add_text(subtree,
+ tvb, curr_offset + 1, 1,
+ "No element dissector, rest of dissection may be incorrect");
+
+ consumed = 1;
+ }
+ else
+ {
+ a_add_string[0] = '\0';
+ consumed = (*elem_funcs[idx])(tvb, subtree, curr_offset + 1, -1, a_add_string);
+
+ if (a_add_string[0] != '\0')
+ {
+ proto_item_append_text(item, a_add_string);
+ a_add_string[0] = '\0';
+ }
+ }
+
+ consumed++;
+
+ proto_item_set_len(item, consumed);
+ }
+
+ return(consumed);
+}
+
+/*
+ * Type Value (TV) element dissector
+ * Where top half nibble is IEI and bottom half nibble is value.
+ *
+ * Length cannot be used in these functions, big problem if a element dissector
+ * is not defined for these.
+ */
+static guint8
+elem_tv_short(tvbuff_t *tvb, proto_tree *tree, guint8 iei, gint pdu_type, int idx, guint32 offset, gchar *name_add)
+{
+ guint8 oct;
+ guint8 consumed;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ const value_string *elem_names;
+ gint *elem_ett;
+ guint8 (**elem_funcs)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string);
+
+ curr_offset = offset;
+ consumed = 0;
+
+ SET_ELEM_VARS(pdu_type, elem_names, elem_ett, elem_funcs);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ if ((oct & 0xf0) == (iei & 0xf0))
+ {
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, -1,
+ "%s%s",
+ elem_names[idx].strptr,
+ (name_add == NULL) || (name_add[0] == '\0') ? "" : name_add);
+
+ subtree = proto_item_add_subtree(item, elem_ett[idx]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Element ID",
+ a_bigbuf);
+
+ if (elem_funcs[idx] == NULL)
+ {
+ /* BAD THING, CANNOT DETERMINE LENGTH */
+
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "No element dissector, rest of dissection may be incorrect");
+
+ consumed++;
+ }
+ else
+ {
+ a_add_string[0] = '\0';
+ consumed = (*elem_funcs[idx])(tvb, subtree, curr_offset, -1, a_add_string);
+
+ if (a_add_string[0] != '\0')
+ {
+ proto_item_append_text(item, a_add_string);
+ a_add_string[0] = '\0';
+ }
+ }
+
+ proto_item_set_len(item, consumed);
+ }
+
+ return(consumed);
+}
+
+/*
+ * Type (T) element dissector
+ */
+static guint8
+elem_t(tvbuff_t *tvb, proto_tree *tree, guint8 iei, gint pdu_type, int idx, guint32 offset, gchar *name_add)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ guint8 consumed;
+ const value_string *elem_names;
+ gint *elem_ett;
+ guint8 (**elem_funcs)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string);
+
+ curr_offset = offset;
+ consumed = 0;
+
+ SET_ELEM_VARS(pdu_type, elem_names, elem_ett, elem_funcs);
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ if (oct == iei)
+ {
+ proto_tree_add_uint_format(tree,
+ (BSSAP_PDU_TYPE_BSSMAP == pdu_type) ? hf_gsm_a_bssmap_elem_id : hf_gsm_a_dtap_elem_id, tvb,
+ curr_offset, 1, oct,
+ "%s%s",
+ elem_names[idx].strptr,
+ (name_add == NULL) || (name_add[0] == '\0') ? "" : name_add);
+
+ consumed = 1;
+ }
+
+ return(consumed);
+}
+
+/*
+ * Length Value (LV) element dissector
+ */
+static guint8
+elem_lv(tvbuff_t *tvb, proto_tree *tree, gint pdu_type, int idx, guint32 offset, guint len, gchar *name_add)
+{
+ guint8 parm_len;
+ guint8 consumed;
+ guint32 curr_offset;
+ proto_tree *subtree;
+ proto_item *item;
+ const value_string *elem_names;
+ gint *elem_ett;
+ guint8 (**elem_funcs)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string);
+
+ len = len;
+ curr_offset = offset;
+ consumed = 0;
+
+ SET_ELEM_VARS(pdu_type, elem_names, elem_ett, elem_funcs);
+
+ parm_len = tvb_get_guint8(tvb, curr_offset);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, parm_len + 1,
+ "%s%s",
+ elem_names[idx].strptr,
+ (name_add == NULL) || (name_add[0] == '\0') ? "" : name_add);
+
+ subtree = proto_item_add_subtree(item, elem_ett[idx]);
+
+ proto_tree_add_uint(subtree, hf_gsm_a_length, tvb,
+ curr_offset, 1, parm_len);
+
+ if (parm_len > 0)
+ {
+ if (elem_funcs[idx] == NULL)
+ {
+ proto_tree_add_text(subtree,
+ tvb, curr_offset + 1, parm_len,
+ "Element Value");
+
+ consumed = parm_len;
+ }
+ else
+ {
+ a_add_string[0] = '\0';
+ consumed =
+ (*elem_funcs[idx])(tvb, subtree, curr_offset + 1,
+ parm_len, a_add_string);
+
+ if (a_add_string[0] != '\0')
+ {
+ proto_item_append_text(item, a_add_string);
+ a_add_string[0] = '\0';
+ }
+ }
+ }
+
+ return(consumed + 1);
+}
+
+/*
+ * Value (V) element dissector
+ *
+ * Length cannot be used in these functions, big problem if a element dissector
+ * is not defined for these.
+ */
+static guint8
+elem_v(tvbuff_t *tvb, proto_tree *tree, gint pdu_type, int idx, guint32 offset)
+{
+ guint8 consumed;
+ guint32 curr_offset;
+ const value_string *elem_names;
+ gint *elem_ett;
+ guint8 (**elem_funcs)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string);
+
+ curr_offset = offset;
+ consumed = 0;
+
+ SET_ELEM_VARS(pdu_type, elem_names, elem_ett, elem_funcs);
+
+ if (elem_funcs[idx] == NULL)
+ {
+ /* BAD THING, CANNOT DETERMINE LENGTH */
+
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "No element dissector, rest of dissection may be incorrect");
+
+ consumed = 1;
+ }
+ else
+ {
+ a_add_string[0] = '\0';
+ consumed = (*elem_funcs[idx])(tvb, tree, curr_offset, -1, a_add_string);
+ a_add_string[0] = '\0';
+ }
+
+ return(consumed);
+}
+
+#define ELEM_MAND_TLV(EMT_iei, EMT_pdu_type, EMT_elem_idx, EMT_elem_name_addition) \
+{\
+ if ((consumed = elem_tlv(tvb, tree, EMT_iei, EMT_pdu_type, EMT_elem_idx, curr_offset, curr_len, EMT_elem_name_addition)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ else \
+ { \
+ proto_tree_add_text(tree, \
+ tvb, curr_offset, 0, \
+ "Missing Mandatory element (0x%02x) %s%s, rest of dissection is suspect", \
+ EMT_iei, \
+ (EMT_pdu_type == BSSAP_PDU_TYPE_BSSMAP) ? \
+ gsm_bssmap_elem_strings[EMT_elem_idx].strptr : gsm_dtap_elem_strings[EMT_elem_idx].strptr, \
+ (EMT_elem_name_addition == NULL) || (EMT_elem_name_addition[0] == '\0') ? "" : EMT_elem_name_addition \
+ ); \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+#define ELEM_OPT_TLV(EOT_iei, EOT_pdu_type, EOT_elem_idx, EOT_elem_name_addition) \
+{\
+ if ((consumed = elem_tlv(tvb, tree, EOT_iei, EOT_pdu_type, EOT_elem_idx, curr_offset, curr_len, EOT_elem_name_addition)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+#define ELEM_MAND_TV(EMT_iei, EMT_pdu_type, EMT_elem_idx, EMT_elem_name_addition) \
+{\
+ if ((consumed = elem_tv(tvb, tree, EMT_iei, EMT_pdu_type, EMT_elem_idx, curr_offset, EMT_elem_name_addition)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ else \
+ { \
+ proto_tree_add_text(tree, \
+ tvb, curr_offset, 0, \
+ "Missing Mandatory element (0x%02x) %s%s, rest of dissection is suspect", \
+ EMT_iei, \
+ (EMT_pdu_type == BSSAP_PDU_TYPE_BSSMAP) ? \
+ gsm_bssmap_elem_strings[EMT_elem_idx].strptr : gsm_dtap_elem_strings[EMT_elem_idx].strptr, \
+ (EMT_elem_name_addition == NULL) || (EMT_elem_name_addition[0] == '\0') ? "" : EMT_elem_name_addition \
+ ); \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+#define ELEM_OPT_TV(EOT_iei, EOT_pdu_type, EOT_elem_idx, EOT_elem_name_addition) \
+{\
+ if ((consumed = elem_tv(tvb, tree, EOT_iei, EOT_pdu_type, EOT_elem_idx, curr_offset, EOT_elem_name_addition)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+#define ELEM_OPT_TV_SHORT(EOT_iei, EOT_pdu_type, EOT_elem_idx, EOT_elem_name_addition) \
+{\
+ if ((consumed = elem_tv_short(tvb, tree, EOT_iei, EOT_pdu_type, EOT_elem_idx, curr_offset, EOT_elem_name_addition)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+#define ELEM_OPT_T(EOT_iei, EOT_pdu_type, EOT_elem_idx, EOT_elem_name_addition) \
+{\
+ if ((consumed = elem_t(tvb, tree, EOT_iei, EOT_pdu_type, EOT_elem_idx, curr_offset, EOT_elem_name_addition)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+#define ELEM_MAND_LV(EML_pdu_type, EML_elem_idx, EML_elem_name_addition) \
+{\
+ if ((consumed = elem_lv(tvb, tree, EML_pdu_type, EML_elem_idx, curr_offset, curr_len, EML_elem_name_addition)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ else \
+ { \
+ /* Mandatory, but nothing we can do */ \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+#define ELEM_MAND_V(EMV_pdu_type, EMV_elem_idx) \
+{\
+ if ((consumed = elem_v(tvb, tree, EMV_pdu_type, EMV_elem_idx, curr_offset)) > 0) \
+ { \
+ curr_offset += consumed; \
+ curr_len -= consumed; \
+ } \
+ else \
+ { \
+ /* Mandatory, but nothing we can do */ \
+ } \
+ if (curr_len <= 0) return; \
+}
+
+
+/* MESSAGE FUNCTIONS */
+
+/*
+ * [2] 3.2.1.1
+ */
+static void
+bssmap_ass_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CHAN_TYPE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHAN_TYPE, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_L3_HEADER_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_L3_HEADER_INFO, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_PRIO].value, BSSAP_PDU_TYPE_BSSMAP, BE_PRIO, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_DOWN_DTX_FLAG].value, BSSAP_PDU_TYPE_BSSMAP, BE_DOWN_DTX_FLAG, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_INT_BAND].value, BSSAP_PDU_TYPE_BSSMAP, BE_INT_BAND, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CM_INFO_2].value, BSSAP_PDU_TYPE_BSSMAP, BE_CM_INFO_2, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_GROUP_CALL_REF].value, BSSAP_PDU_TYPE_BSSMAP, BE_GROUP_CALL_REF, "");
+
+ ELEM_OPT_T(gsm_bssmap_elem_strings[BE_TALKER_FLAG].value, BSSAP_PDU_TYPE_BSSMAP, BE_TALKER_FLAG, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_LSA_ACC_CTRL].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_ACC_CTRL, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.2
+ */
+static void
+bssmap_ass_complete(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_RR_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_RR_CAUSE, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_CHAN].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_CHAN, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_ENC_ALG].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_ENC_ALG, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CCT_POOL].value, BSSAP_PDU_TYPE_BSSMAP, BE_CCT_POOL, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_SPEECH_VER].value, BSSAP_PDU_TYPE_BSSMAP, BE_SPEECH_VER, " (Chosen)");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_LSA_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_ID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.3
+ */
+static void
+bssmap_ass_failure(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_RR_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_RR_CAUSE, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CCT_POOL].value, BSSAP_PDU_TYPE_BSSMAP, BE_CCT_POOL, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CCT_POOL_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CCT_POOL_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.4
+ */
+static void
+bssmap_block(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_OPT_T(gsm_bssmap_elem_strings[BE_CONN_REL_REQ].value, BSSAP_PDU_TYPE_BSSMAP, BE_CONN_REL_REQ, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.5
+ */
+static void
+bssmap_block_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.6
+ */
+static void
+bssmap_unblock(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_OPT_T(gsm_bssmap_elem_strings[BE_CONN_REL_REQ].value, BSSAP_PDU_TYPE_BSSMAP, BE_CONN_REL_REQ, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.7
+ */
+static void
+bssmap_unblock_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.8
+ */
+static void
+bssmap_ho_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CHAN_TYPE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHAN_TYPE, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_ENC_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_ENC_INFO, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CM_INFO_1].value, BSSAP_PDU_TYPE_BSSMAP, BE_CM_INFO_1, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CM_INFO_2].value, BSSAP_PDU_TYPE_BSSMAP, BE_CM_INFO_2, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, " (Serving)");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_PRIO].value, BSSAP_PDU_TYPE_BSSMAP, BE_PRIO, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_DOWN_DTX_FLAG].value, BSSAP_PDU_TYPE_BSSMAP, BE_DOWN_DTX_FLAG, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, " (Target)");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_INT_BAND].value, BSSAP_PDU_TYPE_BSSMAP, BE_INT_BAND, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CM_INFO_3].value, BSSAP_PDU_TYPE_BSSMAP, BE_CM_INFO_3, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CURR_CHAN_1].value, BSSAP_PDU_TYPE_BSSMAP, BE_CURR_CHAN_1, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_SPEECH_VER].value, BSSAP_PDU_TYPE_BSSMAP, BE_SPEECH_VER, " (Used)");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_GROUP_CALL_REF].value, BSSAP_PDU_TYPE_BSSMAP, BE_GROUP_CALL_REF, "");
+
+ ELEM_OPT_T(gsm_bssmap_elem_strings[BE_TALKER_FLAG].value, BSSAP_PDU_TYPE_BSSMAP, BE_TALKER_FLAG, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CONF_EVO_IND].value, BSSAP_PDU_TYPE_BSSMAP, BE_CONF_EVO_IND, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_ENC_ALG].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_ENC_ALG, " (Serving)");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_OLD2NEW_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_OLD2NEW_INFO, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_LSA_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_INFO, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_LSA_ACC_CTRL].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_ACC_CTRL, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.9
+ */
+static void
+bssmap_ho_reqd(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_OPT_T(gsm_bssmap_elem_strings[BE_RESP_REQ].value, BSSAP_PDU_TYPE_BSSMAP, BE_RESP_REQ, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID_LIST, " (Preferred)");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CCT_POOL_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CCT_POOL_LIST, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CURR_CHAN_1].value, BSSAP_PDU_TYPE_BSSMAP, BE_CURR_CHAN_1, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_SPEECH_VER].value, BSSAP_PDU_TYPE_BSSMAP, BE_SPEECH_VER, " (Used)");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_QUE_IND].value, BSSAP_PDU_TYPE_BSSMAP, BE_QUE_IND, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_OLD2NEW_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_OLD2NEW_INFO, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.10
+ */
+static void
+bssmap_ho_req_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_L3_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_L3_INFO, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_CHAN].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_CHAN, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_ENC_ALG].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_ENC_ALG, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CCT_POOL].value, BSSAP_PDU_TYPE_BSSMAP, BE_CCT_POOL, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_SPEECH_VER].value, BSSAP_PDU_TYPE_BSSMAP, BE_SPEECH_VER, " (Chosen)");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_LSA_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_ID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.11
+ */
+static void
+bssmap_ho_cmd(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_L3_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_L3_INFO, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.12
+ */
+static void
+bssmap_ho_complete(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_RR_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_RR_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.14
+ */
+static void
+bssmap_ho_cand_enq(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_NUM_MS].value, BSSAP_PDU_TYPE_BSSMAP, BE_NUM_MS, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID_LIST, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.15
+ */
+static void
+bssmap_ho_cand_resp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_NUM_MS].value, BSSAP_PDU_TYPE_BSSMAP, BE_NUM_MS, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.16
+ */
+static void
+bssmap_ho_failure(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_RR_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_RR_CAUSE, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CCT_POOL].value, BSSAP_PDU_TYPE_BSSMAP, BE_CCT_POOL, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CCT_POOL_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CCT_POOL_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.19
+ */
+static void
+bssmap_paging(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_IMSI].value, BSSAP_PDU_TYPE_BSSMAP, BE_IMSI, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_TMSI].value, BSSAP_PDU_TYPE_BSSMAP, BE_TMSI, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID_LIST, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CHAN_NEEDED].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHAN_NEEDED, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_EMLPP_PRIO].value, BSSAP_PDU_TYPE_BSSMAP, BE_EMLPP_PRIO, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.20
+ */
+static void
+bssmap_clear_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.21
+ */
+static void
+bssmap_clear_cmd(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_L3_HEADER_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_L3_HEADER_INFO, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.23
+ */
+static void
+bssmap_reset(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_UNKNOWN;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.25
+ */
+static void
+bssmap_ho_performed(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_CHAN].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_CHAN, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_ENC_ALG].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_ENC_ALG, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_SPEECH_VER].value, BSSAP_PDU_TYPE_BSSMAP, BE_SPEECH_VER, " (Chosen)");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_LSA_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_ID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.26
+ */
+static void
+bssmap_overload(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.29
+ */
+static void
+bssmap_cm_upd(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CM_INFO_2].value, BSSAP_PDU_TYPE_BSSMAP, BE_CM_INFO_2, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CM_INFO_3].value, BSSAP_PDU_TYPE_BSSMAP, BE_CM_INFO_3, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.30
+ */
+static void
+bssmap_ciph_mode_cmd(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_L3_HEADER_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_L3_HEADER_INFO, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_ENC_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_ENC_INFO, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CIPH_RESP_MODE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIPH_RESP_MODE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.31
+ */
+static void
+bssmap_ciph_mode_complete(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_L3_MSG].value, BSSAP_PDU_TYPE_BSSMAP, BE_L3_MSG, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_ENC_ALG].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_ENC_ALG, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.32
+ */
+static void
+bssmap_cl3_info(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint8 consumed;
+ guint32 curr_offset;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_L3_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_L3_INFO, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CHOSEN_CHAN].value, BSSAP_PDU_TYPE_BSSMAP, BE_CHOSEN_CHAN, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_LSA_ID_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_ID_LIST, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_APDU].value, BSSAP_PDU_TYPE_BSSMAP, BE_APDU, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.34
+ */
+static void
+bssmap_sapi_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint8 consumed;
+ guint32 curr_offset;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_DLCI].value, BSSAP_PDU_TYPE_BSSMAP, BE_DLCI, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.37
+ */
+static void
+bssmap_ho_reqd_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.38
+ */
+static void
+bssmap_reset_cct(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.39
+ */
+static void
+bssmap_reset_cct_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.41
+ */
+static void
+bssmap_cct_group_block(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.42
+ */
+static void
+bssmap_cct_group_block_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.43
+ */
+static void
+bssmap_cct_group_unblock(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.44
+ */
+static void
+bssmap_cct_group_unblock_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.45
+ */
+static void
+bssmap_confusion(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_DIAG].value, BSSAP_PDU_TYPE_BSSMAP, BE_DIAG, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.47
+ */
+static void
+bssmap_unequipped_cct(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ ELEM_OPT_TV(gsm_bssmap_elem_strings[BE_CIC_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.48
+ */
+static void
+bssmap_ciph_mode_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.49
+ */
+static void
+bssmap_load_ind(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_TIME_IND].value, BSSAP_PDU_TYPE_BSSMAP, BE_TIME_IND, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID, "");
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CELL_ID_LIST].value, BSSAP_PDU_TYPE_BSSMAP, BE_CELL_ID_LIST, " (Target)");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_RES_SIT].value, BSSAP_PDU_TYPE_BSSMAP, BE_RES_SIT, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.66
+ */
+static void
+bssmap_change_cct(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_CAUSE].value, BSSAP_PDU_TYPE_BSSMAP, BE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.67
+ */
+static void
+bssmap_change_cct_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(gsm_bssmap_elem_strings[BE_CIC].value, BSSAP_PDU_TYPE_BSSMAP, BE_CIC, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.69
+ */
+static void
+bssmap_lsa_info(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_LSA_INFO].value, BSSAP_PDU_TYPE_BSSMAP, BE_LSA_INFO, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [2] 3.2.1.70
+ */
+static void
+bssmap_conn_oriented(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TLV(gsm_bssmap_elem_strings[BE_APDU].value, BSSAP_PDU_TYPE_BSSMAP, BE_APDU, "");
+
+ ELEM_OPT_TLV(gsm_bssmap_elem_strings[BE_SEG].value, BSSAP_PDU_TYPE_BSSMAP, BE_SEG, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+#define NUM_GSM_BSSMAP_MSG (sizeof(gsm_bssmap_msg_strings)/sizeof(value_string))
+static gint ett_gsm_bssmap_msg[NUM_GSM_BSSMAP_MSG];
+static void (*bssmap_msg_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ bssmap_ass_req, /* Assignment Request */
+ bssmap_ass_complete, /* Assignment Complete */
+ bssmap_ass_failure, /* Assignment Failure */
+ bssmap_ho_req, /* Handover Request */
+ bssmap_ho_reqd, /* Handover Required */
+ bssmap_ho_req_ack, /* Handover Request Acknowledge */
+ bssmap_ho_cmd, /* Handover Command */
+ bssmap_ho_complete, /* Handover Complete */
+ NULL /* no associated data */, /* Handover Succeeded */
+ bssmap_ho_failure, /* Handover Failure */
+ bssmap_ho_performed, /* Handover Performed */
+ bssmap_ho_cand_enq, /* Handover Candidate Enquire */
+ bssmap_ho_cand_resp, /* Handover Candidate Response */
+ bssmap_ho_reqd_rej, /* Handover Required Reject */
+ NULL /* no associated data */, /* Handover Detect */
+ bssmap_clear_cmd, /* Clear Command */
+ NULL /* no associated data */, /* Clear Complete */
+ bssmap_clear_req, /* Clear Request */
+ NULL, /* Reserved */
+ NULL, /* Reserved */
+ bssmap_sapi_rej, /* SAPI 'n' Reject */
+ bssmap_confusion, /* Confusion */
+ NULL, /* Suspend */
+ NULL, /* Resume */
+ bssmap_conn_oriented, /* Connection Oriented Information */
+ NULL, /* Perform Location Request */
+ bssmap_lsa_info, /* LSA Information */
+ NULL, /* Perform Location Response */
+ NULL, /* Perform Location Abort */
+ bssmap_reset, /* Reset */
+ NULL /* no associated data */, /* Reset Acknowledge */
+ bssmap_overload, /* Overload */
+ NULL, /* Reserved */
+ bssmap_reset_cct, /* Reset Circuit */
+ bssmap_reset_cct_ack, /* Reset Circuit Acknowledge */
+ NULL, /* MSC Invoke Trace */
+ NULL, /* BSS Invoke Trace */
+ NULL, /* Connectionless Information */
+ bssmap_block, /* Block */
+ bssmap_block_ack, /* Blocking Acknowledge */
+ bssmap_unblock, /* Unblock */
+ bssmap_unblock_ack, /* Unblocking Acknowledge */
+ bssmap_cct_group_block, /* Circuit Group Block */
+ bssmap_cct_group_block_ack, /* Circuit Group Blocking Acknowledge */
+ bssmap_cct_group_unblock, /* Circuit Group Unblock */
+ bssmap_cct_group_unblock_ack, /* Circuit Group Unblocking Acknowledge */
+ bssmap_unequipped_cct, /* Unequipped Circuit */
+ bssmap_change_cct, /* Change Circuit */
+ bssmap_change_cct_ack, /* Change Circuit Acknowledge */
+ NULL, /* Resource Request */
+ NULL, /* Resource Indication */
+ bssmap_paging, /* Paging */
+ bssmap_ciph_mode_cmd, /* Cipher Mode Command */
+ bssmap_cm_upd, /* Classmark Update */
+ bssmap_ciph_mode_complete, /* Cipher Mode Complete */
+ NULL /* no associated data */, /* Queuing Indication */
+ bssmap_cl3_info, /* Complete Layer 3 Information */
+ NULL /* no associated data */, /* Classmark Request */
+ bssmap_ciph_mode_rej, /* Cipher Mode Reject */
+ bssmap_load_ind, /* Load Indication */
+ NULL, /* VGCS/VBS Setup */
+ NULL, /* VGCS/VBS Setup Ack */
+ NULL, /* VGCS/VBS Setup Refuse */
+ NULL, /* VGCS/VBS Assignment Request */
+ NULL, /* VGCS/VBS Assignment Result */
+ NULL, /* VGCS/VBS Assignment Failure */
+ NULL, /* VGCS/VBS Queuing Indication */
+ NULL, /* Uplink Request */
+ NULL, /* Uplink Request Acknowledge */
+ NULL, /* Uplink Request Confirmation */
+ NULL, /* Uplink Release Indication */
+ NULL, /* Uplink Reject Command */
+ NULL, /* Uplink Release Command */
+ NULL, /* Uplink Seized Command */
+ NULL, /* NONE */
+};
+
+/*
+ * [4] 9.2.2
+ */
+static void
+dtap_mm_auth_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+ guint8 oct;
+ proto_tree *subtree;
+ proto_item *item;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ /*
+ * special dissection for Cipher Key Sequence Number
+ */
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CIPH_KEY_SEQ_NUM].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CIPH_KEY_SEQ_NUM]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+
+ switch (oct & 0x07)
+ {
+ case 0x07:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: No key is available",
+ a_bigbuf);
+ break;
+
+ default:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: %d",
+ a_bigbuf,
+ oct & 0x07);
+ break;
+ }
+
+ curr_offset++;
+ curr_len--;
+
+ if (curr_len <= 0) return;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_AUTH_PARAM_RAND);
+
+ ELEM_OPT_TLV(0x20, BSSAP_PDU_TYPE_DTAP, DE_AUTH_PARAM_AUTN, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.2.3
+ */
+static void
+dtap_mm_auth_resp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_AUTH_RESP_PARAM);
+
+ ELEM_OPT_TLV(0x21, BSSAP_PDU_TYPE_DTAP, DE_AUTH_RESP_PARAM_EXT, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.2.3a
+ */
+static void
+dtap_mm_auth_fail(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_REJ_CAUSE);
+
+ ELEM_OPT_TLV(0x22, BSSAP_PDU_TYPE_DTAP, DE_AUTH_FAIL_PARAM, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.4
+ */
+static void
+dtap_mm_cm_reestab_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+ guint8 oct;
+ proto_tree *subtree;
+ proto_item *item;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ /*
+ * special dissection for Cipher Key Sequence Number
+ */
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CIPH_KEY_SEQ_NUM].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CIPH_KEY_SEQ_NUM]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+
+ switch (oct & 0x07)
+ {
+ case 0x07:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: No key is available",
+ a_bigbuf);
+ break;
+
+ default:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: %d",
+ a_bigbuf,
+ oct & 0x07);
+ break;
+ }
+
+ curr_offset++;
+ curr_len--;
+
+ if (curr_len <= 0) return;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MS_CM_2, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ ELEM_OPT_TV(0x13, BSSAP_PDU_TYPE_DTAP, DE_LAI, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.5a
+ */
+static void
+dtap_mm_cm_srvc_prompt(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_PD_SAPI);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.2.6
+ */
+static void
+dtap_mm_cm_srvc_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_REJ_CAUSE);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.2.8
+ */
+static void
+dtap_mm_abort(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_REJ_CAUSE);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.9
+ */
+static void
+dtap_mm_cm_srvc_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+ guint8 oct;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ /*
+ * special dissection for CM Service Type
+ */
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CIPH_KEY_SEQ_NUM].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CIPH_KEY_SEQ_NUM]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+
+ switch ((oct & 0x70) >> 4)
+ {
+ case 0x07:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: No key is available",
+ a_bigbuf);
+ break;
+
+ default:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: %d",
+ a_bigbuf,
+ (oct & 0x70) >> 4);
+ break;
+ }
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CM_SRVC_TYPE].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CM_SRVC_TYPE]);
+
+ switch (oct & 0x0f)
+ {
+ case 0x01: str = "Mobile originating call establishment or packet mode connection establishment"; break;
+ case 0x02: str = "Emergency call establishment"; break;
+ case 0x04: str = "Short message service"; break;
+ case 0x08: str = "Supplementary service activation"; break;
+ case 0x09: str = "Voice group call establishment"; break;
+ case 0x0a: str = "Voice broadcast call establishment"; break;
+ case 0x0b: str = "Location Services"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Service Type: (%d) %s",
+ a_bigbuf,
+ oct & 0x0f,
+ str);
+
+ curr_offset++;
+ curr_len--;
+
+ if (curr_len <= 0) return;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MS_CM_2, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ ELEM_OPT_TV_SHORT(0x80, BSSAP_PDU_TYPE_DTAP, DE_PRIO, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.10
+ */
+static void
+dtap_mm_id_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint8 oct;
+ guint32 curr_offset;
+ guint curr_len;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ /*
+ * special dissection for Identity Type
+ */
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_ID_TYPE].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_ID_TYPE]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x07)
+ {
+ case 1: str = "IMSI"; break;
+ case 2: str = "IMEI"; break;
+ case 3: str = "IMEISV"; break;
+ case 4: str = "TMSI"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Type of identity: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+ curr_len--;
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.11
+ */
+static void
+dtap_mm_id_resp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.12
+ */
+static void
+dtap_mm_imsi_det_ind(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_MS_CM_1);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.13
+ */
+static void
+dtap_mm_loc_upd_acc(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_LAI);
+
+ ELEM_OPT_TLV(0x17, BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ ELEM_OPT_T(0xa1, BSSAP_PDU_TYPE_DTAP, DE_FOP, "");
+
+ ELEM_OPT_T(0xa2, BSSAP_PDU_TYPE_DTAP, DE_CTS_PERM, "");
+
+ ELEM_OPT_TLV(0x4a, BSSAP_PDU_TYPE_DTAP, DE_PLMN_LIST, " Equivalent");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.14
+ */
+static void
+dtap_mm_loc_upd_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_REJ_CAUSE);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.15
+ */
+static void
+dtap_mm_loc_upd_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+ guint8 oct;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ /*
+ * special dissection for Location Updating Type
+ */
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CIPH_KEY_SEQ_NUM].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CIPH_KEY_SEQ_NUM]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x70, 8);
+
+ switch ((oct & 0x70) >> 4)
+ {
+ case 0x07:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: No key is available",
+ a_bigbuf);
+ break;
+
+ default:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: %d",
+ a_bigbuf,
+ (oct & 0x70) >> 4);
+ break;
+ }
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_LOC_UPD_TYPE].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_LOC_UPD_TYPE]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Follow-On Request (FOR): %s",
+ a_bigbuf,
+ (oct & 0x08) ? "Follow-on request pending" : "No follow-on request pending");
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x04, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ switch (oct & 0x03)
+ {
+ case 0: str = "Normal"; break;
+ case 1: str = "Periodic"; break;
+ case 2: str = "IMSI attach"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x03, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Updating Type: %s",
+ a_bigbuf,
+ str);
+
+ proto_item_append_text(item, " - %s", str);
+
+ curr_offset++;
+ curr_len--;
+
+ if (curr_len <= 0) return;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_LAI);
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_MS_CM_1);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ ELEM_OPT_TLV(0x33, BSSAP_PDU_TYPE_DTAP, DE_MS_CM_2, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.1.15a
+ */
+static void
+dtap_mm_mm_info(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TLV(0x43, BSSAP_PDU_TYPE_DTAP, DE_NETWORK_NAME, " - Full Name");
+
+ ELEM_OPT_TLV(0x45, BSSAP_PDU_TYPE_DTAP, DE_NETWORK_NAME, " - Short Name");
+
+ ELEM_OPT_TV(0x46, BSSAP_PDU_TYPE_DTAP, DE_TIME_ZONE, " - Local");
+
+ ELEM_OPT_TV(0x47, BSSAP_PDU_TYPE_DTAP, DE_TIME_ZONE_TIME, " - Universal Time and Local Time Zone");
+
+ ELEM_OPT_TLV(0x48, BSSAP_PDU_TYPE_DTAP, DE_LSA_ID, "");
+
+ ELEM_OPT_TLV(0x49, BSSAP_PDU_TYPE_DTAP, DE_DAY_SAVING_TIME, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.1.16
+ */
+static void
+dtap_mm_mm_status(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_REJ_CAUSE);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [3] 9.2.17
+ */
+static void
+dtap_mm_tmsi_realloc_cmd(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_LAI);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.1.25
+ */
+static void
+dtap_rr_paging_resp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+ guint8 oct;
+ proto_tree *subtree;
+ proto_item *item;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ /*
+ * special dissection for Cipher Key Sequence Number
+ */
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CIPH_KEY_SEQ_NUM].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CIPH_KEY_SEQ_NUM]);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x08, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x07, 8);
+
+ switch (oct & 0x07)
+ {
+ case 0x07:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: No key is available",
+ a_bigbuf);
+ break;
+
+ default:
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Ciphering Key Sequence Number: %d",
+ a_bigbuf,
+ oct & 0x07);
+ break;
+ }
+
+ curr_offset++;
+ curr_len--;
+
+ if (curr_len <= 0) return;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MS_CM_2, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.1.29
+ */
+static void
+dtap_rr_rr_status(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CAUSE);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.1
+ */
+static void
+dtap_cc_alerting(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x1e, BSSAP_PDU_TYPE_DTAP, DE_PROG_IND, "");
+
+ ELEM_OPT_TLV(0x7e, BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ /* uplink only */
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.2
+ */
+static void
+dtap_cc_call_conf(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TV_SHORT(0xd0, BSSAP_PDU_TYPE_DTAP, DE_REPEAT_IND, " BC repeat indicator");
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 1");
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 2");
+
+ ELEM_OPT_TLV(0x08, BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ ELEM_OPT_TLV(0x15, BSSAP_PDU_TYPE_DTAP, DE_CC_CAP, "");
+
+ ELEM_OPT_TLV(0x2d, BSSAP_PDU_TYPE_DTAP, DE_SI, "");
+
+ ELEM_OPT_TLV(0x40, BSSAP_PDU_TYPE_DTAP, DE_SUP_CODEC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.3
+ */
+static void
+dtap_cc_call_proceed(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_OPT_TV_SHORT(0xd0, BSSAP_PDU_TYPE_DTAP, DE_REPEAT_IND, " BC repeat indicator");
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 1");
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 2");
+
+ ELEM_OPT_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x1e, BSSAP_PDU_TYPE_DTAP, DE_PROG_IND, "");
+
+ ELEM_OPT_TV_SHORT(0x80, BSSAP_PDU_TYPE_DTAP, DE_PRIO, "");
+
+ ELEM_OPT_TLV(0x2f, BSSAP_PDU_TYPE_DTAP, DE_NET_CC_CAP, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.4
+ */
+static void
+dtap_cc_congestion_control(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+ guint8 oct;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ /*
+ * special dissection for Congestion Level
+ */
+ oct = tvb_get_guint8(tvb, curr_offset);
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ "%s : Spare",
+ a_bigbuf);
+
+ item =
+ proto_tree_add_text(tree,
+ tvb, curr_offset, 1,
+ gsm_dtap_elem_strings[DE_CONGESTION].strptr);
+
+ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CONGESTION]);
+
+ switch (oct & 0x0f)
+ {
+ case 0: str = "Receiver ready"; break;
+ case 15: str = "Receiver not ready"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(subtree,
+ tvb, curr_offset, 1,
+ "%s : Congestion level: %s",
+ a_bigbuf,
+ str);
+
+ curr_offset++;
+ curr_len--;
+
+ if (curr_len <= 0) return;
+
+ ELEM_OPT_TLV(0x08, BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.5
+ */
+static void
+dtap_cc_connect(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x1e, BSSAP_PDU_TYPE_DTAP, DE_PROG_IND, "");
+
+ ELEM_OPT_TLV(0x4c, BSSAP_PDU_TYPE_DTAP, DE_CONN_NUM, "");
+
+ ELEM_OPT_TLV(0x4d, BSSAP_PDU_TYPE_DTAP, DE_CONN_SUB_ADDR, "");
+
+ ELEM_OPT_TLV(0x7e, BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ /* uplink only */
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ ELEM_OPT_TLV(0x2d, BSSAP_PDU_TYPE_DTAP, DE_SI, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.7
+ */
+static void
+dtap_cc_disconnect(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ ELEM_OPT_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x1e, BSSAP_PDU_TYPE_DTAP, DE_PROG_IND, "");
+
+ ELEM_OPT_TLV(0x7e, BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ ELEM_OPT_TLV(0x7b, BSSAP_PDU_TYPE_DTAP, DE_ALLOWED_ACTIONS, "");
+
+ /* uplink only */
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.8
+ */
+static void
+dtap_cc_emerg_setup(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, "");
+
+ ELEM_OPT_TLV(0x2d, BSSAP_PDU_TYPE_DTAP, DE_SI, "");
+
+ ELEM_OPT_TLV(0x40, BSSAP_PDU_TYPE_DTAP, DE_SUP_CODEC_LIST, "");
+
+ ELEM_OPT_TLV(0x2e, BSSAP_PDU_TYPE_DTAP, DE_SRVC_CAT, " Emergency");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.9
+ */
+static void
+dtap_cc_facility(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ /* uplink only */
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.12
+ */
+static void
+dtap_cc_hold_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.13
+ */
+static void
+dtap_cc_modify(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, "");
+
+ ELEM_OPT_TLV(0x7c, BSSAP_PDU_TYPE_DTAP, DE_LLC, "");
+
+ ELEM_OPT_TLV(0x7d, BSSAP_PDU_TYPE_DTAP, DE_HLC, "");
+
+ ELEM_OPT_T(0xa3, BSSAP_PDU_TYPE_DTAP, DE_REV_CALL_SETUP_DIR, "");
+
+ ELEM_OPT_T(0xa4, BSSAP_PDU_TYPE_DTAP, DE_IMM_MOD_IND, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.14
+ */
+static void
+dtap_cc_modify_complete(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, "");
+
+ ELEM_OPT_TLV(0x7c, BSSAP_PDU_TYPE_DTAP, DE_LLC, "");
+
+ ELEM_OPT_TLV(0x7d, BSSAP_PDU_TYPE_DTAP, DE_HLC, "");
+
+ ELEM_OPT_T(0xa3, BSSAP_PDU_TYPE_DTAP, DE_REV_CALL_SETUP_DIR, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.15
+ */
+static void
+dtap_cc_modify_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ ELEM_OPT_TLV(0x7c, BSSAP_PDU_TYPE_DTAP, DE_LLC, "");
+
+ ELEM_OPT_TLV(0x7d, BSSAP_PDU_TYPE_DTAP, DE_HLC, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.16
+ */
+static void
+dtap_cc_notify(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_NOT_IND);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.17
+ */
+static void
+dtap_cc_progress(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_PROG_IND, "");
+
+ ELEM_OPT_TLV(0x7e, BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.17a
+ */
+static void
+dtap_cc_cc_est(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_SETUP_CONTAINER, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.17b
+ */
+static void
+dtap_cc_cc_est_conf(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TV_SHORT(0xd0, BSSAP_PDU_TYPE_DTAP, DE_REPEAT_IND, " Repeat indicator");
+
+ ELEM_MAND_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 1");
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 2");
+
+ ELEM_OPT_TLV(0x08, BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ ELEM_OPT_TLV(0x40, BSSAP_PDU_TYPE_DTAP, DE_SUP_CODEC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.18
+ */
+static void
+dtap_cc_release(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TLV(0x08, BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ ELEM_OPT_TLV(0x08, BSSAP_PDU_TYPE_DTAP, DE_CAUSE, " 2");
+
+ ELEM_OPT_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x7e, BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ /* uplink only */
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.18a
+ */
+static void
+dtap_cc_recall(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RECALL_TYPE);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.19
+ */
+static void
+dtap_cc_release_complete(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_OPT_TLV(0x08, BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ ELEM_OPT_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x7e, BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ /* uplink only */
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.22
+ */
+static void
+dtap_cc_retrieve_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.23
+ */
+static void
+dtap_cc_setup(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_OPT_TV_SHORT(0xd0, BSSAP_PDU_TYPE_DTAP, DE_REPEAT_IND, " BC repeat indicator");
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 1");
+
+ ELEM_OPT_TLV(0x04, BSSAP_PDU_TYPE_DTAP, DE_BEARER_CAP, " 2");
+
+ ELEM_OPT_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x1e, BSSAP_PDU_TYPE_DTAP, DE_PROG_IND, "");
+
+ ELEM_OPT_TV(0x34, BSSAP_PDU_TYPE_DTAP, DE_SIGNAL, "");
+
+ ELEM_OPT_TLV(0x5c, BSSAP_PDU_TYPE_DTAP, DE_CLG_PARTY_BCD_NUM, "");
+
+ ELEM_OPT_TLV(0x5d, BSSAP_PDU_TYPE_DTAP, DE_CLG_PARTY_SUB_ADDR, "");
+
+ ELEM_OPT_TLV(0x5e, BSSAP_PDU_TYPE_DTAP, DE_CLD_PARTY_BCD_NUM, "");
+
+ ELEM_OPT_TLV(0x6d, BSSAP_PDU_TYPE_DTAP, DE_CLD_PARTY_SUB_ADDR, "");
+
+ ELEM_OPT_TLV(0x74, BSSAP_PDU_TYPE_DTAP, DE_RED_PARTY_BCD_NUM, "");
+
+ ELEM_OPT_TLV(0x75, BSSAP_PDU_TYPE_DTAP, DE_RED_PARTY_SUB_ADDR, "");
+
+ ELEM_OPT_TV_SHORT(0xd0, BSSAP_PDU_TYPE_DTAP, DE_REPEAT_IND, " LLC repeat indicator");
+
+ ELEM_OPT_TLV(0x7c, BSSAP_PDU_TYPE_DTAP, DE_LLC, " 1");
+
+ ELEM_OPT_TLV(0x7c, BSSAP_PDU_TYPE_DTAP, DE_LLC, " 2");
+
+ ELEM_OPT_TV_SHORT(0xd0, BSSAP_PDU_TYPE_DTAP, DE_REPEAT_IND, " HLC repeat indicator");
+
+ ELEM_OPT_TLV(0x7d, BSSAP_PDU_TYPE_DTAP, DE_HLC, " 1");
+
+ ELEM_OPT_TLV(0x7d, BSSAP_PDU_TYPE_DTAP, DE_HLC, " 2");
+
+ ELEM_OPT_TLV(0x7e, BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ /* downlink only */
+
+ ELEM_OPT_TV_SHORT(0x80, BSSAP_PDU_TYPE_DTAP, DE_PRIO, "");
+
+ ELEM_OPT_TLV(0x19, BSSAP_PDU_TYPE_DTAP, DE_ALERT_PATTERN, "");
+
+ ELEM_OPT_TLV(0x2f, BSSAP_PDU_TYPE_DTAP, DE_NET_CC_CAP, "");
+
+ ELEM_OPT_TLV(0x3a, BSSAP_PDU_TYPE_DTAP, DE_CAUSE_NO_CLI, "");
+
+ /* uplink only */
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ ELEM_OPT_T(0xa1, BSSAP_PDU_TYPE_DTAP, DE_FOP, "");
+
+ ELEM_OPT_T(0xa2, BSSAP_PDU_TYPE_DTAP, DE_CTS_PERM, "");
+
+ ELEM_OPT_TLV(0x15, BSSAP_PDU_TYPE_DTAP, DE_CC_CAP, "");
+
+ ELEM_OPT_TLV(0x1d, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, " $(CCBS)$ (advanced recall alignment)");
+
+ ELEM_OPT_TLV(0x1b, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, " (recall alignment Not essential) $(CCBS)$");
+
+ ELEM_OPT_TLV(0x2d, BSSAP_PDU_TYPE_DTAP, DE_SI, "");
+
+ ELEM_OPT_TLV(0x40, BSSAP_PDU_TYPE_DTAP, DE_SUP_CODEC_LIST, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.23a
+ */
+static void
+dtap_cc_start_cc(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_OPT_TLV(0x15, BSSAP_PDU_TYPE_DTAP, DE_CC_CAP, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.24
+ */
+static void
+dtap_cc_start_dtmf(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TV(0x2c, BSSAP_PDU_TYPE_DTAP, DE_KEYPAD_FACILITY, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.25
+ */
+static void
+dtap_cc_start_dtmf_ack(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_TV(0x2c, BSSAP_PDU_TYPE_DTAP, DE_KEYPAD_FACILITY, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.26
+ */
+static void
+dtap_cc_start_dtmf_rej(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.27
+ */
+static void
+dtap_cc_status(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_CAUSE, "");
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_CALL_STATE);
+
+ ELEM_OPT_TLV(0x24, BSSAP_PDU_TYPE_DTAP, DE_AUX_STATES, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [4] 9.3.31
+ */
+static void
+dtap_cc_user_info(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_USER_USER, "");
+
+ ELEM_OPT_T(0xa0, BSSAP_PDU_TYPE_DTAP, DE_MORE_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [6] 2.4.2
+ */
+static void
+dtap_ss_register(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_TLV(0x1c, BSSAP_PDU_TYPE_DTAP, DE_FACILITY, "");
+
+ ELEM_OPT_TLV(0x7f, BSSAP_PDU_TYPE_DTAP, DE_SS_VER_IND, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.2.1
+ */
+static void
+dtap_sms_cp_data(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_CP_USER_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.2.3
+ */
+static void
+dtap_sms_cp_error(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_CP_CAUSE);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.3.1.1
+ */
+static void
+rp_data_n_ms(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+ g_pinfo->p2p_dir = P2P_DIR_SENT;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RP_MESSAGE_REF);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_ORIG_ADDR, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_DEST_ADDR, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_USER_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.3.1.2
+ */
+static void
+rp_data_ms_n(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+ g_pinfo->p2p_dir = P2P_DIR_RECV;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RP_MESSAGE_REF);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_ORIG_ADDR, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_DEST_ADDR, "");
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_USER_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.3.2
+ */
+static void
+rp_smma(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RP_MESSAGE_REF);
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.3.3
+ */
+static void
+rp_ack_n_ms(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+ g_pinfo->p2p_dir = P2P_DIR_SENT;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RP_MESSAGE_REF);
+
+ ELEM_OPT_TLV(0x41, BSSAP_PDU_TYPE_DTAP, DE_RP_USER_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.3.3
+ */
+static void
+rp_ack_ms_n(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+ g_pinfo->p2p_dir = P2P_DIR_RECV;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RP_MESSAGE_REF);
+
+ ELEM_OPT_TLV(0x41, BSSAP_PDU_TYPE_DTAP, DE_RP_USER_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.3.4
+ */
+static void
+rp_error_n_ms(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_FALSE;
+ g_pinfo->p2p_dir = P2P_DIR_SENT;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RP_MESSAGE_REF);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_CAUSE, "");
+
+ ELEM_OPT_TLV(0x41, BSSAP_PDU_TYPE_DTAP, DE_RP_USER_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+/*
+ * [5] 7.3.4
+ */
+static void
+rp_error_ms_n(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len)
+{
+ guint32 curr_offset;
+ guint32 consumed;
+ guint curr_len;
+
+ curr_offset = offset;
+ curr_len = len;
+
+ is_uplink = IS_UPLINK_TRUE;
+ g_pinfo->p2p_dir = P2P_DIR_RECV;
+
+ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RP_MESSAGE_REF);
+
+ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RP_CAUSE, "");
+
+ ELEM_OPT_TLV(0x41, BSSAP_PDU_TYPE_DTAP, DE_RP_USER_DATA, "");
+
+ EXTRANEOUS_DATA_CHECK(curr_len, 0);
+}
+
+#define NUM_GSM_DTAP_MSG_MM (sizeof(gsm_dtap_msg_mm_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_msg_mm[NUM_GSM_DTAP_MSG_MM];
+static void (*dtap_msg_mm_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ dtap_mm_imsi_det_ind, /* IMSI Detach Indication */
+ dtap_mm_loc_upd_acc, /* Location Updating Accept */
+ dtap_mm_loc_upd_rej, /* Location Updating Reject */
+ dtap_mm_loc_upd_req, /* Location Updating Request */
+ NULL /* no associated data */, /* Authentication Reject */
+ dtap_mm_auth_req, /* Authentication Request */
+ dtap_mm_auth_resp, /* Authentication Response */
+ dtap_mm_auth_fail, /* Authentication Failure */
+ dtap_mm_id_req, /* Identity Request */
+ dtap_mm_id_resp, /* Identity Response */
+ dtap_mm_tmsi_realloc_cmd, /* TMSI Reallocation Command */
+ NULL /* no associated data */, /* TMSI Reallocation Complete */
+ NULL /* no associated data */, /* CM Service Accept */
+ dtap_mm_cm_srvc_rej, /* CM Service Reject */
+ NULL /* no associated data */, /* CM Service Abort */
+ dtap_mm_cm_srvc_req, /* CM Service Request */
+ dtap_mm_cm_srvc_prompt, /* CM Service Prompt */
+ NULL, /* Reserved: was allocated in earlier phases of the protocol */
+ dtap_mm_cm_reestab_req, /* CM Re-establishment Request */
+ dtap_mm_abort, /* Abort */
+ NULL /* no associated data */, /* MM Null */
+ dtap_mm_mm_status, /* MM Status */
+ dtap_mm_mm_info, /* MM Information */
+ NULL, /* NONE */
+};
+
+#define NUM_GSM_DTAP_MSG_RR (sizeof(gsm_dtap_msg_rr_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_msg_rr[NUM_GSM_DTAP_MSG_RR];
+static void (*dtap_msg_rr_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ NULL, /* RR Initialisation Request */
+ NULL, /* Additional Assignment */
+ NULL, /* Immediate Assignment */
+ NULL, /* Immediate Assignment Extended */
+ NULL, /* Immediate Assignment Reject */
+
+ NULL, /* DTM Assignment Failure */
+ NULL, /* DTM Reject */
+ NULL, /* DTM Request */
+ NULL, /* Main DCCH Assignment Command */
+ NULL, /* Packet Assignment Command */
+
+ NULL, /* Ciphering Mode Command */
+ NULL, /* Ciphering Mode Complete */
+
+ NULL, /* Configuration Change Command */
+ NULL, /* Configuration Change Ack. */
+ NULL, /* Configuration Change Reject */
+
+ NULL, /* Assignment Command */
+ NULL, /* Assignment Complete */
+ NULL, /* Assignment Failure */
+ NULL, /* Handover Command */
+ NULL, /* Handover Complete */
+ NULL, /* Handover Failure */
+ NULL, /* Physical Information */
+ NULL, /* DTM Assignment Command */
+
+ NULL, /* RR-cell Change Order */
+ NULL, /* PDCH Assignment Command */
+
+ NULL, /* Channel Release */
+ NULL, /* Partial Release */
+ NULL, /* Partial Release Complete */
+
+ NULL, /* Paging Request Type 1 */
+ NULL, /* Paging Request Type 2 */
+ NULL, /* Paging Request Type 3 */
+ dtap_rr_paging_resp, /* Paging Response */
+ NULL, /* Notification/NCH */
+ NULL, /* Reserved */
+ NULL, /* Notification/Response */
+
+ NULL, /* Reserved */
+
+/* NULL, * Utran Classmark Change * CONFLICTS WITH Handover To UTRAN Command */
+ NULL, /* UE RAB Preconfiguration */
+ NULL, /* cdma2000 Classmark Change */
+
+ NULL, /* System Information Type 8 */
+ NULL, /* System Information Type 1 */
+ NULL, /* System Information Type 2 */
+ NULL, /* System Information Type 3 */
+ NULL, /* System Information Type 4 */
+ NULL, /* System Information Type 5 */
+ NULL, /* System Information Type 6 */
+ NULL, /* System Information Type 7 */
+
+ NULL, /* System Information Type 2bis */
+ NULL, /* System Information Type 2ter */
+ NULL, /* System Information Type 2quater */
+ NULL, /* System Information Type 5bis */
+ NULL, /* System Information Type 5ter */
+ NULL, /* System Information Type 9 */
+ NULL, /* System Information Type 13 */
+
+ NULL, /* System Information Type 16 */
+ NULL, /* System Information Type 17 */
+
+ NULL, /* System Information Type 18 */
+ NULL, /* System Information Type 19 */
+ NULL, /* System Information Type 20 */
+
+ NULL, /* Channel Mode Modify */
+ dtap_rr_rr_status, /* RR Status */
+ NULL, /* Channel Mode Modify Acknowledge */
+ NULL, /* Frequency Redefinition */
+ NULL, /* Measurement Report */
+ NULL, /* Classmark Change */
+ NULL, /* Classmark Enquiry */
+ NULL, /* Extended Measurement Report */
+ NULL, /* Extended Measurement Order */
+ NULL, /* GPRS Suspension Request */
+
+ NULL, /* VGCS Uplink Grant */
+ NULL, /* Uplink Release */
+ NULL, /* Reserved */
+ NULL, /* Uplink Busy */
+ NULL, /* Talker Indication */
+
+ NULL, /* UTRAN Classmark Change/Handover To UTRAN Command */ /* spec conflict */
+
+ NULL, /* Application Information */
+
+ NULL, /* NONE */
+};
+
+#define NUM_GSM_DTAP_MSG_CC (sizeof(gsm_dtap_msg_cc_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_msg_cc[NUM_GSM_DTAP_MSG_CC];
+static void (*dtap_msg_cc_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ dtap_cc_alerting, /* Alerting */
+ dtap_cc_call_conf, /* Call Confirmed */
+ dtap_cc_call_proceed, /* Call Proceeding */
+ dtap_cc_connect, /* Connect */
+ NULL /* no associated data */, /* Connect Acknowledge */
+ dtap_cc_emerg_setup, /* Emergency Setup */
+ dtap_cc_progress, /* Progress */
+ dtap_cc_cc_est, /* CC-Establishment */
+ dtap_cc_cc_est_conf, /* CC-Establishment Confirmed */
+ dtap_cc_recall, /* Recall */
+ dtap_cc_start_cc, /* Start CC */
+ dtap_cc_setup, /* Setup */
+ dtap_cc_modify, /* Modify */
+ dtap_cc_modify_complete, /* Modify Complete */
+ dtap_cc_modify_rej, /* Modify Reject */
+ dtap_cc_user_info, /* User Information */
+ NULL /* no associated data */, /* Hold */
+ NULL /* no associated data */, /* Hold Acknowledge */
+ dtap_cc_hold_rej, /* Hold Reject */
+ NULL /* no associated data */, /* Retrieve */
+ NULL /* no associated data */, /* Retrieve Acknowledge */
+ dtap_cc_retrieve_rej, /* Retrieve Reject */
+ dtap_cc_disconnect, /* Disconnect */
+ dtap_cc_release, /* Release */
+ dtap_cc_release_complete, /* Release Complete */
+ dtap_cc_congestion_control, /* Congestion Control */
+ dtap_cc_notify, /* Notify */
+ dtap_cc_status, /* Status */
+ NULL /* no associated data */, /* Status Enquiry */
+ dtap_cc_start_dtmf, /* Start DTMF */
+ NULL /* no associated data */, /* Stop DTMF */
+ NULL /* no associated data */, /* Stop DTMF Acknowledge */
+ dtap_cc_start_dtmf_ack, /* Start DTMF Acknowledge */
+ dtap_cc_start_dtmf_rej, /* Start DTMF Reject */
+ dtap_cc_facility, /* Facility */
+ NULL, /* NONE */
+};
+
+#define NUM_GSM_DTAP_MSG_GMM (sizeof(gsm_dtap_msg_gmm_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_msg_gmm[NUM_GSM_DTAP_MSG_GMM];
+static void (*dtap_msg_gmm_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ NULL, /* Attach Request */
+ NULL, /* Attach Accept */
+ NULL, /* Attach Complete */
+ NULL, /* Attach Reject */
+ NULL, /* Detach Request */
+ NULL, /* Detach Accept */
+ NULL, /* Routing Area Update Request */
+ NULL, /* Routing Area Update Accept */
+ NULL, /* Routing Area Update Complete */
+ NULL, /* Routing Area Update Reject */
+ NULL, /* Service Request */
+ NULL, /* Service Accept */
+ NULL, /* Service Reject */
+ NULL, /* P-TMSI Reallocation Command */
+ NULL, /* P-TMSI Reallocation Complete */
+ NULL, /* Authentication and Ciphering Req */
+ NULL, /* Authentication and Ciphering Resp */
+ NULL, /* Authentication and Ciphering Rej */
+ NULL, /* Authentication and Ciphering Failure */
+ NULL, /* Identity Request */
+ NULL, /* Identity Response */
+ NULL, /* GMM Status */
+ NULL, /* GMM Information */
+ NULL, /* NONE */
+};
+
+#define NUM_GSM_DTAP_MSG_SMS (sizeof(gsm_dtap_msg_sms_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_msg_sms[NUM_GSM_DTAP_MSG_SMS];
+static void (*dtap_msg_sms_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ dtap_sms_cp_data, /* CP-DATA */
+ NULL /* no associated data */, /* CP-ACK */
+ dtap_sms_cp_error, /* CP-ERROR */
+ NULL, /* NONE */
+};
+
+#define NUM_GSM_DTAP_MSG_SM (sizeof(gsm_dtap_msg_sm_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_msg_sm[NUM_GSM_DTAP_MSG_SM];
+static void (*dtap_msg_sm_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ NULL, /* Activate PDP Context Request */
+ NULL, /* Activate PDP Context Accept */
+ NULL, /* Activate PDP Context Reject */
+ NULL, /* Request PDP Context Activation */
+ NULL, /* Request PDP Context Activation rej. */
+ NULL, /* Deactivate PDP Context Request */
+ NULL, /* Deactivate PDP Context Accept */
+ NULL, /* Modify PDP Context Request(Network to MS direction) */
+ NULL, /* Modify PDP Context Accept (MS to network direction) */
+ NULL, /* Modify PDP Context Request(MS to network direction) */
+ NULL, /* Modify PDP Context Accept (Network to MS direction) */
+ NULL, /* Modify PDP Context Reject */
+ NULL, /* Activate Secondary PDP Context Request */
+ NULL, /* Activate Secondary PDP Context Accept */
+ NULL, /* Activate Secondary PDP Context Reject */
+ NULL, /* Reserved: was allocated in earlier phases of the protocol */
+ NULL, /* Reserved: was allocated in earlier phases of the protocol */
+ NULL, /* Reserved: was allocated in earlier phases of the protocol */
+ NULL, /* Reserved: was allocated in earlier phases of the protocol */
+ NULL, /* Reserved: was allocated in earlier phases of the protocol */
+ NULL, /* SM Status */
+ NULL, /* NONE */
+};
+
+#define NUM_GSM_DTAP_MSG_SS (sizeof(gsm_dtap_msg_ss_strings)/sizeof(value_string))
+static gint ett_gsm_dtap_msg_ss[NUM_GSM_DTAP_MSG_SS];
+static void (*dtap_msg_ss_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ dtap_cc_release_complete, /* Release Complete */
+ dtap_cc_facility, /* Facility */
+ dtap_ss_register, /* Register */
+ NULL, /* NONE */
+};
+
+#define NUM_GSM_RP_MSG (sizeof(gsm_rp_msg_strings)/sizeof(value_string))
+static gint ett_gsm_rp_msg[NUM_GSM_RP_MSG];
+static void (*rp_msg_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = {
+ rp_data_ms_n, /* RP-DATA (MS to Network) */
+ rp_data_n_ms, /* RP-DATA (Network to MS */
+ rp_ack_ms_n, /* RP-ACK (MS to Network) */
+ rp_ack_n_ms, /* RP-ACK (Network to MS) */
+ rp_error_ms_n, /* RP-ERROR (MS to Network) */
+ rp_error_n_ms, /* RP-ERROR (Network to MS) */
+ rp_smma, /* RP-SMMA (MS to Network) */
+ NULL, /* NONE */
+};
+
+/* GENERIC DISSECTOR FUNCTIONS */
+
+static void
+dissect_rp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 oct;
+ guint32 offset, saved_offset;
+ guint32 len;
+ gint idx;
+ proto_item *rp_item = NULL;
+ proto_tree *rp_tree = NULL;
+ gchar *str;
+
+
+ if (!proto_is_protocol_enabled(proto_a_rp))
+ {
+ call_dissector(data_handle, tvb, pinfo, tree);
+ return;
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_str(pinfo->cinfo, COL_INFO, "(RP) ");
+ }
+
+ /*
+ * In the interest of speed, if "tree" is NULL, don't do any work
+ * not necessary to generate protocol tree items.
+ */
+ if (!tree)
+ {
+ return;
+ }
+
+ offset = 0;
+ saved_offset = offset;
+
+ g_pinfo = pinfo;
+ g_tree = tree;
+
+ len = tvb_length(tvb);
+
+ /*
+ * add RP message name
+ */
+ oct = tvb_get_guint8(tvb, offset++);
+
+ str = my_match_strval((guint32) oct, gsm_rp_msg_strings, &idx);
+
+ /*
+ * create the protocol tree
+ */
+ if (str == NULL)
+ {
+ rp_item =
+ proto_tree_add_protocol_format(tree, proto_a_rp, tvb, 0, len,
+ "GSM A-I/F RP - Unknown RP Message Type (0x%02x)",
+ oct);
+
+ rp_tree = proto_item_add_subtree(rp_item, ett_rp_msg);
+ }
+ else
+ {
+ gsm_a_rp_type = oct;
+
+ rp_item =
+ proto_tree_add_protocol_format(tree, proto_a_rp, tvb, 0, -1,
+ "GSM A-I/F RP - %s",
+ str);
+
+ rp_tree = proto_item_add_subtree(rp_item, ett_gsm_rp_msg[idx]);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", str);
+ }
+ }
+
+ /*
+ * add RP message name
+ */
+ proto_tree_add_uint_format(rp_tree, hf_gsm_a_rp_msg_type,
+ tvb, saved_offset, 1, oct, "Message Type");
+
+ if (str == NULL) return;
+
+ if ((len - offset) <= 0) return;
+
+ /*
+ * decode elements
+ */
+ if (rp_msg_fcn[idx] == NULL)
+ {
+ proto_tree_add_text(rp_tree,
+ tvb, offset, len - offset,
+ "Message Elements");
+ }
+ else
+ {
+ (*rp_msg_fcn[idx])(tvb, rp_tree, offset, len - offset);
+ }
+}
+
+
+static void
+dissect_bssmap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 oct;
+ guint32 offset, saved_offset;
+ guint32 len;
+ gint idx;
+ proto_item *bssmap_item = NULL;
+ proto_tree *bssmap_tree = NULL;
+ gchar *str;
+
+
+ if (!proto_is_protocol_enabled(proto_a_bssmap))
+ {
+ call_dissector(data_handle, tvb, pinfo, tree);
+ return;
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_str(pinfo->cinfo, COL_INFO, "(BSSMAP) ");
+ }
+
+ /*
+ * In the interest of speed, if "tree" is NULL, don't do any work
+ * not necessary to generate protocol tree items.
+ */
+ if (!tree)
+ {
+ return;
+ }
+
+ offset = 0;
+ saved_offset = offset;
+
+ g_pinfo = pinfo;
+ g_tree = tree;
+
+ len = tvb_length(tvb);
+
+ /*
+ * add BSSMAP message name
+ */
+ oct = tvb_get_guint8(tvb, offset++);
+
+ str = my_match_strval((guint32) oct, gsm_bssmap_msg_strings, &idx);
+
+ /*
+ * create the protocol tree
+ */
+ if (str == NULL)
+ {
+ bssmap_item =
+ proto_tree_add_protocol_format(tree, proto_a_bssmap, tvb, 0, len,
+ "GSM A-I/F BSSMAP - Unknown BSSMAP Message Type (0x%02x)",
+ oct);
+
+ bssmap_tree = proto_item_add_subtree(bssmap_item, ett_bssmap_msg);
+ }
+ else
+ {
+ bssmap_item =
+ proto_tree_add_protocol_format(tree, proto_a_bssmap, tvb, 0, -1,
+ "GSM A-I/F BSSMAP - %s",
+ str);
+
+ bssmap_tree = proto_item_add_subtree(bssmap_item, ett_gsm_bssmap_msg[idx]);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", str);
+ }
+ }
+
+ /*
+ * add BSSMAP message name
+ */
+ proto_tree_add_uint_format(bssmap_tree, hf_gsm_a_bssmap_msg_type,
+ tvb, saved_offset, 1, oct, "Message Type");
+
+ if (str == NULL) return;
+
+ if ((len - offset) <= 0) return;
+
+ /*
+ * decode elements
+ */
+ if (bssmap_msg_fcn[idx] == NULL)
+ {
+ proto_tree_add_text(bssmap_tree,
+ tvb, offset, len - offset,
+ "Message Elements");
+ }
+ else
+ {
+ (*bssmap_msg_fcn[idx])(tvb, bssmap_tree, offset, len - offset);
+ }
+}
+
+
+static void
+dissect_dtap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ void (*msg_fcn)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len);
+ guint8 oct;
+ guint8 pd;
+ guint32 offset;
+ guint32 len;
+ guint32 oct_1, oct_2;
+ gint idx;
+ proto_item *dtap_item = NULL;
+ proto_tree *dtap_tree = NULL;
+ proto_item *oct_1_item = NULL;
+ proto_tree *pd_tree = NULL;
+ gchar *msg_str;
+ const gchar *str;
+ gint ett_tree;
+ gint ti;
+ int hf_idx;
+
+
+ if (!proto_is_protocol_enabled(proto_a_dtap))
+ {
+ call_dissector(data_handle, tvb, pinfo, tree);
+ return;
+ }
+
+ len = tvb_length(tvb);
+
+ if (len < 2)
+ {
+ /*
+ * too short to be DTAP
+ */
+ call_dissector(data_handle, tvb, pinfo, tree);
+ return;
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_str(pinfo->cinfo, COL_INFO, "(DTAP) ");
+ }
+
+ /*
+ * In the interest of speed, if "tree" is NULL, don't do any work
+ * not necessary to generate protocol tree items.
+ */
+ if (!tree)
+ {
+ return;
+ }
+
+ offset = 0;
+ oct_2 = 0;
+
+ g_pinfo = pinfo;
+ g_tree = tree;
+
+ /*
+ * get protocol discriminator
+ */
+ oct_1 = tvb_get_guint8(tvb, offset++);
+
+ if ((((oct_1 & DTAP_TI_MASK) >> 4) & DTAP_TIE_PRES_MASK) == DTAP_TIE_PRES_MASK)
+ {
+ /*
+ * eventhough we don't know if a TI should be in the message yet
+ * we rely on the TI/SKIP indicator to be 0 to avoid taking this
+ * octet
+ */
+ oct_2 = tvb_get_guint8(tvb, offset++);
+ }
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ pd = oct_1 & DTAP_PD_MASK;
+ ti = -1;
+ msg_str = NULL;
+ ett_tree = -1;
+ hf_idx = -1;
+ msg_fcn = NULL;
+
+ /*
+ * octet 1
+ */
+ switch (pd)
+ {
+ case 3:
+ str = pd_str[pd];
+ msg_str = my_match_strval((guint32) (oct & DTAP_CC_IEI_MASK), gsm_dtap_msg_cc_strings, &idx);
+ ett_tree = ett_gsm_dtap_msg_cc[idx];
+ hf_idx = hf_gsm_a_dtap_msg_cc_type;
+ msg_fcn = dtap_msg_cc_fcn[idx];
+ ti = (oct_1 & DTAP_TI_MASK) >> 4;
+ break;
+
+ case 5:
+ str = pd_str[pd];
+ msg_str = my_match_strval((guint32) (oct & DTAP_MM_IEI_MASK), gsm_dtap_msg_mm_strings, &idx);
+ ett_tree = ett_gsm_dtap_msg_mm[idx];
+ hf_idx = hf_gsm_a_dtap_msg_mm_type;
+ msg_fcn = dtap_msg_mm_fcn[idx];
+ break;
+
+ case 6:
+ str = pd_str[pd];
+ msg_str = my_match_strval((guint32) (oct & DTAP_RR_IEI_MASK), gsm_dtap_msg_rr_strings, &idx);
+ ett_tree = ett_gsm_dtap_msg_rr[idx];
+ hf_idx = hf_gsm_a_dtap_msg_rr_type;
+ msg_fcn = dtap_msg_rr_fcn[idx];
+ break;
+
+ case 8:
+ str = pd_str[pd];
+ msg_str = my_match_strval((guint32) (oct & DTAP_GMM_IEI_MASK), gsm_dtap_msg_gmm_strings, &idx);
+ ett_tree = ett_gsm_dtap_msg_gmm[idx];
+ hf_idx = hf_gsm_a_dtap_msg_gmm_type;
+ msg_fcn = dtap_msg_gmm_fcn[idx];
+ break;
+
+ case 9:
+ str = pd_str[pd];
+ msg_str = my_match_strval((guint32) (oct & DTAP_SMS_IEI_MASK), gsm_dtap_msg_sms_strings, &idx);
+ ett_tree = ett_gsm_dtap_msg_sms[idx];
+ hf_idx = hf_gsm_a_dtap_msg_sms_type;
+ msg_fcn = dtap_msg_sms_fcn[idx];
+ ti = (oct_1 & DTAP_TI_MASK) >> 4;
+ break;
+
+ case 10:
+ str = pd_str[pd];
+ msg_str = my_match_strval((guint32) (oct & DTAP_SM_IEI_MASK), gsm_dtap_msg_sm_strings, &idx);
+ ett_tree = ett_gsm_dtap_msg_sm[idx];
+ hf_idx = hf_gsm_a_dtap_msg_sm_type;
+ msg_fcn = dtap_msg_sm_fcn[idx];
+ ti = (oct_1 & DTAP_TI_MASK) >> 4;
+ break;
+
+ case 11:
+ str = pd_str[pd];
+ msg_str = my_match_strval((guint32) (oct & DTAP_SS_IEI_MASK), gsm_dtap_msg_ss_strings, &idx);
+ ett_tree = ett_gsm_dtap_msg_ss[idx];
+ hf_idx = hf_gsm_a_dtap_msg_ss_type;
+ msg_fcn = dtap_msg_ss_fcn[idx];
+ ti = (oct_1 & DTAP_TI_MASK) >> 4;
+ break;
+
+ default:
+ str = pd_str[pd];
+ break;
+ }
+
+ /*
+ * create the protocol tree
+ */
+ if (msg_str == NULL)
+ {
+ dtap_item =
+ proto_tree_add_protocol_format(tree, proto_a_dtap, tvb, 0, len,
+ "GSM A-I/F DTAP - Unknown DTAP Message Type (0x%02x)",
+ oct);
+
+ dtap_tree = proto_item_add_subtree(dtap_item, ett_dtap_msg);
+ }
+ else
+ {
+ dtap_item =
+ proto_tree_add_protocol_format(tree, proto_a_dtap, tvb, 0, -1,
+ "GSM A-I/F DTAP - %s",
+ msg_str);
+
+ dtap_tree = proto_item_add_subtree(dtap_item, ett_tree);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", msg_str);
+ }
+ }
+
+ oct_1_item =
+ proto_tree_add_text(dtap_tree,
+ tvb, 0, 1,
+ "Protocol Discriminator: %s",
+ str);
+
+ pd_tree = proto_item_add_subtree(oct_1_item, ett_dtap_oct_1);
+
+ if (ti == -1)
+ {
+ my_decode_bitfield_value(a_bigbuf, oct_1, 0xf0, 8);
+ proto_tree_add_text(pd_tree,
+ tvb, 0, 1,
+ "%s : Skip Indicator",
+ a_bigbuf);
+ }
+ else
+ {
+ my_decode_bitfield_value(a_bigbuf, oct_1, 0x80, 8);
+ proto_tree_add_text(pd_tree,
+ tvb, 0, 1,
+ "%s : TI flag: %s",
+ a_bigbuf,
+ ((oct_1 & 0x80) ? "allocated by receiver" : "allocated by sender"));
+
+ if ((ti & DTAP_TIE_PRES_MASK) == DTAP_TIE_PRES_MASK)
+ {
+ /* ti is extended to next octet */
+
+ my_decode_bitfield_value(a_bigbuf, oct_1, 0x70, 8);
+ proto_tree_add_text(pd_tree,
+ tvb, 0, 1,
+ "%s : TIO: The TI value is given by the TIE in octet 2",
+ a_bigbuf);
+ }
+ else
+ {
+ my_decode_bitfield_value(a_bigbuf, oct_1, 0x70, 8);
+ proto_tree_add_text(pd_tree,
+ tvb, 0, 1,
+ "%s : TIO: %d",
+ a_bigbuf,
+ ti & DTAP_TIE_PRES_MASK);
+ }
+ }
+
+ my_decode_bitfield_value(a_bigbuf, oct_1, DTAP_PD_MASK, 8);
+ proto_tree_add_text(pd_tree,
+ tvb, 0, 1,
+ "%s : Protocol Discriminator: %d",
+ a_bigbuf,
+ pd);
+
+ if ((ti != -1) &&
+ (ti & DTAP_TIE_PRES_MASK) == DTAP_TIE_PRES_MASK)
+ {
+ my_decode_bitfield_value(a_bigbuf, oct_2, 0x80, 8);
+ proto_tree_add_text(pd_tree,
+ tvb, 1, 1,
+ "%s : Extension",
+ a_bigbuf);
+
+ my_decode_bitfield_value(a_bigbuf, oct_2, DTAP_TIE_MASK, 8);
+ proto_tree_add_text(pd_tree,
+ tvb, 1, 1,
+ "%s : TIE: %d",
+ a_bigbuf,
+ oct_2 & DTAP_TIE_MASK);
+ }
+
+ /*
+ * XXX
+ * N(SD)
+ */
+
+ /*
+ * add DTAP message name
+ */
+ proto_tree_add_uint_format(dtap_tree, hf_idx,
+ tvb, offset, 1, oct,
+ "Message Type");
+
+ offset++;
+
+ if (msg_str == NULL) return;
+
+ if ((len - offset) <= 0) return;
+
+ /*
+ * decode elements
+ */
+ if (msg_fcn == NULL)
+ {
+ proto_tree_add_text(dtap_tree,
+ tvb, offset, len - offset,
+ "Message Elements");
+ }
+ else
+ {
+ (*msg_fcn)(tvb, dtap_tree, offset, len - offset);
+ }
+}
+
+
+/* Register the protocol with Ethereal */
+void
+proto_register_gsm_a(void)
+{
+ guint i;
+ guint last_offset;
+
+ /* Setup list of header fields */
+
+ static hf_register_info hf[] =
+ {
+ { &hf_gsm_a_bssmap_msg_type,
+ { "BSSMAP Message Type", "gsm_a.bssmap_msgtype",
+ FT_UINT8, BASE_HEX, VALS(gsm_bssmap_msg_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_msg_mm_type,
+ { "DTAP Mobility Management Message Type", "gsm_a.dtap_msg_mm_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_dtap_msg_mm_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_msg_rr_type,
+ { "DTAP Radio Resources Management Message Type", "gsm_a.dtap_msg_rr_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_dtap_msg_rr_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_msg_cc_type,
+ { "DTAP Call Control Message Type", "gsm_a.dtap_msg_cc_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_dtap_msg_cc_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_msg_gmm_type,
+ { "DTAP GPRS Mobility Management Message Type", "gsm_a.dtap_msg_gmm_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_dtap_msg_gmm_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_msg_sms_type,
+ { "DTAP Short Message Service Message Type", "gsm_a.dtap_msg_sms_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_dtap_msg_sms_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_msg_sm_type,
+ { "DTAP GPRS Session Management Message Type", "gsm_a.dtap_msg_sm_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_dtap_msg_sm_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_msg_ss_type,
+ { "DTAP Non call Supplementary Service Message Type", "gsm_a.dtap_msg_ss_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_dtap_msg_ss_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_rp_msg_type,
+ { "RP Message Type", "gsm_a.rp_msg_type",
+ FT_UINT8, BASE_HEX, VALS(gsm_rp_msg_strings), 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_bssmap_elem_id,
+ { "Element ID", "gsm_a_bssmap.elem_id",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dtap_elem_id,
+ { "Element ID", "gsm_a_dtap.elem_id",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_length,
+ { "Length", "gsm_a.len",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_none,
+ { "Sub tree", "gsm_a.none",
+ FT_NONE, 0, 0, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_imsi,
+ { "IMSI", "gsm_a.imsi",
+ FT_STRING, BASE_DEC, 0, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_tmsi,
+ { "TMSI/P-TMSI", "gsm_a.tmsi",
+ FT_UINT32, BASE_HEX, 0, 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_imei,
+ { "IMEI", "gsm_a.imei",
+ FT_STRING, BASE_DEC, 0, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_imeisv,
+ { "IMEISV", "gsm_a.imeisv",
+ FT_STRING, BASE_DEC, 0, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_cld_party_bcd_num,
+ { "Called Party BCD Number", "gsm_a.cld_party_bcd_num",
+ FT_STRING, BASE_DEC, 0, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_clg_party_bcd_num,
+ { "Calling Party BCD Number", "gsm_a.clg_party_bcd_num",
+ FT_STRING, BASE_DEC, 0, 0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_cell_ci,
+ { "Cell CI", "gsm_a.cell_ci",
+ FT_UINT16, BASE_HEX, 0, 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_cell_lac,
+ { "Cell LAC", "gsm_a.cell_lac",
+ FT_UINT16, BASE_HEX, 0, 0x0,
+ "", HFILL }
+ },
+ { &hf_gsm_a_dlci_cc,
+ { "Control Channel", "bssap.dlci.cc",
+ FT_UINT8, BASE_HEX, VALS(bssap_cc_values), 0xc0,
+ "", HFILL}},
+ { &hf_gsm_a_dlci_spare,
+ { "Spare", "bssap.dlci.spare",
+ FT_UINT8, BASE_HEX, NULL, 0x38,
+ "", HFILL}},
+ { &hf_gsm_a_dlci_sapi,
+ { "SAPI", "bssap.dlci.sapi",
+ FT_UINT8, BASE_HEX, VALS(bssap_sapi_values), 0x07,
+ "", HFILL}},
+ };
+
+ /* Setup protocol subtree array */
+#define NUM_INDIVIDUAL_ELEMS 10
+ static gint *ett[NUM_INDIVIDUAL_ELEMS + NUM_GSM_BSSMAP_MSG +
+ NUM_GSM_DTAP_MSG_MM + NUM_GSM_DTAP_MSG_RR + NUM_GSM_DTAP_MSG_CC +
+ NUM_GSM_DTAP_MSG_GMM + NUM_GSM_DTAP_MSG_SMS +
+ NUM_GSM_DTAP_MSG_SM + NUM_GSM_DTAP_MSG_SS + NUM_GSM_RP_MSG +
+ NUM_GSM_BSSMAP_ELEM + NUM_GSM_DTAP_ELEM];
+
+ memset((void *) ett, -1, sizeof(ett));
+
+ ett[0] = &ett_bssmap_msg;
+ ett[1] = &ett_dtap_msg;
+ ett[2] = &ett_rp_msg;
+ ett[3] = &ett_elems;
+ ett[4] = &ett_elem;
+ ett[5] = &ett_dtap_oct_1;
+ ett[6] = &ett_cm_srvc_type;
+ ett[7] = &ett_gsm_enc_info;
+ ett[8] = &ett_cell_list;
+ ett[9] = &ett_dlci;
+
+ last_offset = NUM_INDIVIDUAL_ELEMS;
+
+ for (i=0; i < NUM_GSM_BSSMAP_MSG; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_bssmap_msg[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_MSG_MM; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_msg_mm[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_MSG_RR; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_msg_rr[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_MSG_CC; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_msg_cc[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_MSG_GMM; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_msg_gmm[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_MSG_SMS; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_msg_sms[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_MSG_SM; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_msg_sm[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_MSG_SS; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_msg_ss[i];
+ }
+
+ for (i=0; i < NUM_GSM_RP_MSG; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_rp_msg[i];
+ }
+
+ for (i=0; i < NUM_GSM_BSSMAP_ELEM; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_bssmap_elem[i];
+ }
+
+ for (i=0; i < NUM_GSM_DTAP_ELEM; i++, last_offset++)
+ {
+ ett[last_offset] = &ett_gsm_dtap_elem[i];
+ }
+
+ /* Register the protocol name and description */
+
+ proto_a_bssmap =
+ proto_register_protocol("GSM A-I/F BSSMAP", "GSM BSSMAP", "gsm_a_bssmap");
+
+ proto_register_field_array(proto_a_bssmap, hf, array_length(hf));
+
+ proto_a_dtap =
+ proto_register_protocol("GSM A-I/F DTAP", "GSM DTAP", "gsm_a_dtap");
+
+ proto_a_rp =
+ proto_register_protocol("GSM A-I/F RP", "GSM RP", "gsm_a_rp");
+
+ sms_dissector_table =
+ register_dissector_table("gsm_a.sms_tpdu", "GSM SMS TPDU",
+ FT_UINT8, BASE_DEC);
+
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+
+void
+proto_reg_handoff_gsm_a(void)
+{
+
+ bssmap_handle = create_dissector_handle(dissect_bssmap, proto_a_bssmap);
+ dtap_handle = create_dissector_handle(dissect_dtap, proto_a_dtap);
+ rp_handle = create_dissector_handle(dissect_rp, proto_a_rp);
+
+ dissector_add("bssap.pdu_type", BSSAP_PDU_TYPE_BSSMAP, bssmap_handle);
+ dissector_add("bssap.pdu_type", BSSAP_PDU_TYPE_DTAP, dtap_handle);
+
+ data_handle = find_dissector("data");
+}