2 * Routines for UMTS Node B Application Part(RANAP) packet dissection
3 * Copyright 2005 - 2010, Anders Broman <anders.broman[AT]ericsson.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
11 * References: 3GPP TS 25.413 version 10.4.0 Release 10
16 #include <epan/packet.h>
18 #include <epan/strutil.h>
19 #include <epan/asn1.h>
20 #include <epan/prefs.h>
21 #include <epan/proto_data.h>
22 #include <wsutil/array.h>
24 #include "packet-ber.h"
25 #include "packet-per.h"
26 #include "packet-gsm_map.h"
27 #include "packet-ranap.h"
28 #include "packet-e212.h"
29 #include "packet-sccp.h"
30 #include "packet-gsm_a_common.h"
31 #include "packet-isup.h"
32 #include "packet-s1ap.h"
33 #include "packet-rtp.h"
36 /* disable: "warning C4146: unary minus operator applied to unsigned type, result still unsigned" */
37 #pragma warning(disable:4146)
40 #define SCCP_SSN_RANAP 142
42 #define PNAME "Radio Access Network Application Part"
43 #define PSNAME "RANAP"
44 #define PFNAME "ranap"
46 /* Highest Ranap_ProcedureCode_value, use in heuristics */
47 #define RANAP_MAX_PC 49 /* id_RerouteNASRequest = 49 */
49 #include "packet-ranap-val.h"
51 void proto_register_ranap(void);
52 void proto_reg_handoff_ranap(void);
54 /* Initialize the protocol and registered fields */
55 static int proto_ranap
;
57 /* initialise sub-dissector handles */
58 static dissector_handle_t rrc_s_to_trnc_handle
;
59 static dissector_handle_t rrc_t_to_srnc_handle
;
60 static dissector_handle_t rrc_ho_to_utran_cmd
;
61 static dissector_handle_t bssgp_handle
;
63 static int hf_ranap_transportLayerAddress_ipv4
;
64 static int hf_ranap_transportLayerAddress_ipv6
;
65 static int hf_ranap_transportLayerAddress_nsap
;
67 #include "packet-ranap-hf.c"
69 /* Initialize the subtree pointers */
71 static int ett_ranap_transportLayerAddress
;
72 static int ett_ranap_transportLayerAddress_nsap
;
74 #include "packet-ranap-ett.c"
76 /*****************************************************************************/
77 /* Packet private data */
78 /* For this dissector, all access to actx->private_data should be made */
79 /* through this API, which ensures that they will not overwrite each other!! */
80 /*****************************************************************************/
83 typedef struct ranap_private_data_t
85 uint32_t transportLayerAddress_ipv4
;
86 uint16_t binding_id_port
;
87 e212_number_type_t number_type
;
88 } ranap_private_data_t
;
91 /* Helper function to get or create the private data struct */
92 static ranap_private_data_t
* ranap_get_private_data(asn1_ctx_t
*actx
)
94 packet_info
*pinfo
= actx
->pinfo
;
95 ranap_private_data_t
*private_data
= (ranap_private_data_t
*)p_get_proto_data(pinfo
->pool
, pinfo
, proto_ranap
, 0);
96 if(private_data
== NULL
) {
97 private_data
= wmem_new0(pinfo
->pool
, ranap_private_data_t
);
98 p_add_proto_data(pinfo
->pool
, pinfo
, proto_ranap
, 0, private_data
);
103 /* Helper function to reset the private data struct */
104 static void ranap_reset_private_data(packet_info
*pinfo
)
106 p_remove_proto_data(pinfo
->pool
, pinfo
, proto_ranap
, 0);
109 static uint32_t private_data_get_transportLayerAddress_ipv4(asn1_ctx_t
*actx
)
111 ranap_private_data_t
*private_data
= (ranap_private_data_t
*)ranap_get_private_data(actx
);
112 return private_data
->transportLayerAddress_ipv4
;
115 static void private_data_set_transportLayerAddress_ipv4(asn1_ctx_t
*actx
, uint32_t transportLayerAddress_ipv4
)
117 ranap_private_data_t
*private_data
= (ranap_private_data_t
*)ranap_get_private_data(actx
);
118 private_data
->transportLayerAddress_ipv4
= transportLayerAddress_ipv4
;
121 static uint16_t private_data_get_binding_id_port(asn1_ctx_t
*actx
)
123 ranap_private_data_t
*private_data
= (ranap_private_data_t
*)ranap_get_private_data(actx
);
124 return private_data
->binding_id_port
;
127 static void private_data_set_binding_id_port(asn1_ctx_t
*actx
, uint16_t binding_id_port
)
129 ranap_private_data_t
*private_data
= (ranap_private_data_t
*)ranap_get_private_data(actx
);
130 private_data
->binding_id_port
= binding_id_port
;
133 /*****************************************************************************/
136 /* Global variables */
137 static uint32_t ProcedureCode
;
138 static uint32_t ProtocolIE_ID
;
139 static uint32_t ProtocolExtensionID
;
140 static bool glbl_dissect_container
;
142 static dissector_handle_t ranap_handle
;
144 /* Some IE:s identities uses the same value for different IE:s
145 * depending on PDU type:
148 * UnsuccessfulOutcome
150 * As a workarond a value is added to the IE:id in the .cnf file.
152 * ResetResourceList N rnsap.ies IMSG||id-IuSigConIdList # no spaces are allowed in value as a space is delimiter
153 * PDU type is stored in a global variable and can is used in the IE decoding section.
156 * &InitiatingMessage ,
157 * &SuccessfulOutcome OPTIONAL,
158 * &UnsuccessfulOutcome OPTIONAL,
161 * Only these two needed currently
163 #define IMSG (1U<<16)
164 #define SOUT (2U<<16)
165 #define SPECIAL (4U<<16)
167 int pdu_type
; /* 0 means wildcard */
169 /* Dissector tables */
170 static dissector_table_t ranap_ies_dissector_table
;
171 static dissector_table_t ranap_ies_p1_dissector_table
;
172 static dissector_table_t ranap_ies_p2_dissector_table
;
173 static dissector_table_t ranap_extension_dissector_table
;
174 static dissector_table_t ranap_proc_imsg_dissector_table
;
175 static dissector_table_t ranap_proc_sout_dissector_table
;
176 static dissector_table_t ranap_proc_uout_dissector_table
;
177 static dissector_table_t ranap_proc_out_dissector_table
;
178 static dissector_table_t nas_pdu_dissector_table
;
180 static int dissect_ProtocolIEFieldValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
181 static int dissect_ProtocolIEFieldPairFirstValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
182 static int dissect_ProtocolIEFieldPairSecondValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
183 static int dissect_ProtocolExtensionFieldExtensionValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
184 static int dissect_InitiatingMessageValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
185 static int dissect_SuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
186 static int dissect_UnsuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
187 static int dissect_OutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
189 static int dissect_ranap_SourceRNC_ToTargetRNC_TransparentContainer(tvbuff_t
*tvb
, int offset
, asn1_ctx_t
*actx
, proto_tree
*tree
, int hf_index
);
190 static int dissect_ranap_TargetRNC_ToSourceRNC_TransparentContainer(tvbuff_t
*tvb
, int offset
, asn1_ctx_t
*actx
, proto_tree
*tree
, int hf_index
);
193 #include "packet-ranap-fn.c"
196 dissect_ProtocolIEFieldValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
202 /* Special handling, same ID used for different IE's depending on signal */
203 switch(ProcedureCode
){
204 case id_RelocationPreparation
:
205 if((ProtocolIE_ID
== id_Source_ToTarget_TransparentContainer
)||(ProtocolIE_ID
== id_Target_ToSource_TransparentContainer
)){
206 key
= SPECIAL
| ProtocolIE_ID
;
207 ret
= (dissector_try_uint_with_data(ranap_ies_dissector_table
, key
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
212 /* no special handling */
213 ret
= (dissector_try_uint_with_data(ranap_ies_dissector_table
, ProtocolIE_ID
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
215 key
= pdu_type
| ProtocolIE_ID
;
216 ret
= (dissector_try_uint_with_data(ranap_ies_dissector_table
, key
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
224 dissect_ProtocolIEFieldPairFirstValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
226 return (dissector_try_uint_with_data(ranap_ies_p1_dissector_table
, ProtocolIE_ID
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
230 dissect_ProtocolIEFieldPairSecondValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
232 return (dissector_try_uint_with_data(ranap_ies_p2_dissector_table
, ProtocolIE_ID
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
236 dissect_ProtocolExtensionFieldExtensionValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
238 return (dissector_try_uint_with_data(ranap_extension_dissector_table
, ProtocolExtensionID
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
242 dissect_InitiatingMessageValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
247 ret
= dissector_try_uint_with_data(ranap_proc_imsg_dissector_table
, ProcedureCode
, tvb
, pinfo
, tree
, false, NULL
);
249 return ret
? tvb_captured_length(tvb
) : 0;
253 dissect_SuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
258 ret
= dissector_try_uint_with_data(ranap_proc_sout_dissector_table
, ProcedureCode
, tvb
, pinfo
, tree
, false, NULL
);
260 return ret
? tvb_captured_length(tvb
) : 0;
264 dissect_UnsuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
266 return (dissector_try_uint_with_data(ranap_proc_uout_dissector_table
, ProcedureCode
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
270 dissect_OutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
272 return (dissector_try_uint_with_data(ranap_proc_out_dissector_table
, ProcedureCode
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
276 dissect_ranap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
278 proto_item
*ranap_item
= NULL
;
279 proto_tree
*ranap_tree
= NULL
;
280 sccp_msg_info_t
*sccp_msg_lcl
= (sccp_msg_info_t
*)data
;
285 /* make entry in the Protocol column on summary display */
286 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RANAP");
288 /* create the ranap protocol tree */
289 ranap_item
= proto_tree_add_item(tree
, proto_ranap
, tvb
, 0, -1, ENC_NA
);
290 ranap_tree
= proto_item_add_subtree(ranap_item
, ett_ranap
);
292 /* Save the sccp_msg_info_t data (if present) because it can't be passed
293 through function calls */
294 p_add_proto_data(pinfo
->pool
, pinfo
, proto_ranap
, pinfo
->curr_layer_num
, data
);
296 /* Clearing any old 'private data' stored */
297 ranap_reset_private_data(pinfo
);
299 dissect_RANAP_PDU_PDU(tvb
, pinfo
, ranap_tree
, NULL
);
302 if (sccp_msg_lcl
->data
.co
.assoc
)
303 sccp_msg_lcl
->data
.co
.assoc
->payload
= SCCP_PLOAD_RANAP
;
305 if (! sccp_msg_lcl
->data
.co
.label
&& ProcedureCode
!= 0xFFFFFFFF) {
306 const char* str
= val_to_str_const(ProcedureCode
, ranap_ProcedureCode_vals
, "Unknown RANAP");
307 sccp_msg_lcl
->data
.co
.label
= wmem_strdup(wmem_file_scope(), str
);
311 return tvb_reported_length(tvb
);
314 #define RANAP_MSG_MIN_LENGTH 7
316 dissect_sccp_ranap_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
323 /* Is it a ranap packet?
325 * 4th octet should be the length of the rest of the message.
326 * 3th octed is the Criticality field
327 * 2nd octet is the message-type e Z[0, 28]
328 * 1st octet is the PDU type (with the extension bit)
329 * (obviously there must be at least four octets)
331 * If all of them hold true we'll assume it's RANAP
334 #define LENGTH_OFFSET 3
335 #define CRIT_OFFSET 2
336 #define MSG_TYPE_OFFSET 1
337 #define PDU_TYPE_OFFSET 0
338 if (tvb_captured_length(tvb
) < RANAP_MSG_MIN_LENGTH
) { return false; }
340 temp
= tvb_get_uint8(tvb
, PDU_TYPE_OFFSET
);
342 /* PDU Type byte is not 0x00 (initiatingMessage), 0x20 (succesfulOutcome),
343 0x40 (unsuccesfulOutcome) or 0x60 (outcome), ignore extension bit (0x80) */
347 temp
= tvb_get_uint8(tvb
, CRIT_OFFSET
);
348 if (temp
== 0xC0 || temp
& 0x3F) {
349 /* Criticality byte is not 0x00 (reject), 0x40 (ignore) or 0x80 (notify) */
353 /* compute aligned PER length determinant without calling dissect_per_length_determinant()
354 to avoid exceptions and info added to tree, info column and expert info */
355 offset
= LENGTH_OFFSET
;
356 length
= tvb_get_uint8(tvb
, offset
);
358 if ((length
& 0x80) == 0x80) {
359 if ((length
& 0xc0) == 0x80) {
362 length
+= tvb_get_uint8(tvb
, offset
);
368 if (length
!= (tvb_reported_length(tvb
) - offset
)){
372 temp
= tvb_get_uint8(tvb
, MSG_TYPE_OFFSET
);
373 if (temp
> RANAP_MAX_PC
) { return false; }
375 /* Try to strengthen the heuristic further, by checking the byte following the length and the bitfield indicating extensions etc
376 * which usually is a sequence-of length
378 word
= tvb_get_ntohs(tvb
, offset
+ 1);
382 dissect_ranap(tvb
, pinfo
, tree
, data
);
387 /*--- proto_register_ranap -------------------------------------------*/
388 void proto_register_ranap(void) {
389 module_t
*ranap_module
;
393 static hf_register_info hf
[] = {
394 { &hf_ranap_transportLayerAddress_ipv4
,
395 { "transportLayerAddress IPv4", "ranap.transportLayerAddress_ipv4",
396 FT_IPv4
, BASE_NONE
, NULL
, 0,
398 { &hf_ranap_transportLayerAddress_ipv6
,
399 { "transportLayerAddress IPv6", "ranap.transportLayerAddress_ipv6",
400 FT_IPv6
, BASE_NONE
, NULL
, 0,
402 { &hf_ranap_transportLayerAddress_nsap
,
403 { "transportLayerAddress NSAP", "ranap.transportLayerAddress_NSAP",
404 FT_BYTES
, BASE_NONE
, NULL
, 0,
408 #include "packet-ranap-hfarr.c"
411 /* List of subtrees */
412 static int *ett
[] = {
414 &ett_ranap_transportLayerAddress
,
415 &ett_ranap_transportLayerAddress_nsap
,
416 #include "packet-ranap-ettarr.c"
420 /* Register protocol */
421 proto_ranap
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
422 /* Register fields and subtrees */
423 proto_register_field_array(proto_ranap
, hf
, array_length(hf
));
424 proto_register_subtree_array(ett
, array_length(ett
));
426 /* Register dissector */
427 ranap_handle
= register_dissector("ranap", dissect_ranap
, proto_ranap
);
429 /* Register dissector tables */
430 ranap_ies_dissector_table
= register_dissector_table("ranap.ies", "RANAP-PROTOCOL-IES", proto_ranap
, FT_UINT32
, BASE_DEC
);
431 ranap_ies_p1_dissector_table
= register_dissector_table("ranap.ies.pair.first", "RANAP-PROTOCOL-IES-PAIR FirstValue", proto_ranap
, FT_UINT32
, BASE_DEC
);
432 ranap_ies_p2_dissector_table
= register_dissector_table("ranap.ies.pair.second", "RANAP-PROTOCOL-IES-PAIR SecondValue", proto_ranap
, FT_UINT32
, BASE_DEC
);
433 ranap_extension_dissector_table
= register_dissector_table("ranap.extension", "RANAP-PROTOCOL-EXTENSION", proto_ranap
, FT_UINT32
, BASE_DEC
);
434 ranap_proc_imsg_dissector_table
= register_dissector_table("ranap.proc.imsg", "RANAP-ELEMENTARY-PROCEDURE InitiatingMessage", proto_ranap
, FT_UINT32
, BASE_DEC
);
435 ranap_proc_sout_dissector_table
= register_dissector_table("ranap.proc.sout", "RANAP-ELEMENTARY-PROCEDURE SuccessfulOutcome", proto_ranap
, FT_UINT32
, BASE_DEC
);
436 ranap_proc_uout_dissector_table
= register_dissector_table("ranap.proc.uout", "RANAP-ELEMENTARY-PROCEDURE UnsuccessfulOutcome", proto_ranap
, FT_UINT32
, BASE_DEC
);
437 ranap_proc_out_dissector_table
= register_dissector_table("ranap.proc.out", "RANAP-ELEMENTARY-PROCEDURE Outcome", proto_ranap
, FT_UINT32
, BASE_DEC
);
439 nas_pdu_dissector_table
= register_dissector_table("ranap.nas_pdu", "RANAP NAS PDU", proto_ranap
, FT_UINT8
, BASE_DEC
);
441 ranap_module
= prefs_register_protocol(proto_ranap
, NULL
);
442 prefs_register_bool_preference(ranap_module
, "dissect_rrc_container",
443 "Attempt to dissect RRC-Container",
444 "Attempt to dissect RRC message embedded in RRC-Container IE",
445 &glbl_dissect_container
);
449 /*--- proto_reg_handoff_ranap ---------------------------------------*/
451 proto_reg_handoff_ranap(void)
453 rrc_s_to_trnc_handle
= find_dissector_add_dependency("rrc.s_to_trnc_cont", proto_ranap
);
454 rrc_t_to_srnc_handle
= find_dissector_add_dependency("rrc.t_to_srnc_cont", proto_ranap
);
455 rrc_ho_to_utran_cmd
= find_dissector_add_dependency("rrc.irat.ho_to_utran_cmd", proto_ranap
);
456 bssgp_handle
= find_dissector("bssgp");
457 heur_dissector_add("sccp", dissect_sccp_ranap_heur
, "RANAP over SCCP", "ranap_sccp", proto_ranap
, HEURISTIC_ENABLE
);
458 heur_dissector_add("sua", dissect_sccp_ranap_heur
, "RANAP over SUA", "ranap_sua", proto_ranap
, HEURISTIC_ENABLE
);
459 dissector_add_uint_with_preference("sccp.ssn", SCCP_SSN_RANAP
, ranap_handle
);
460 #include "packet-ranap-dis-tab.c"
470 * indent-tabs-mode: nil
473 * ex: set shiftwidth=2 tabstop=8 expandtab:
474 * :indentSize=2:tabSize=8:noTabs=true: