2 * Routines for E2APApplication Protocol (e2ap) packet dissection
3 * Copyright 2021, Martin Mathieson
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: ORAN-WG3.E2AP-v03.00, ORAN-WG3.E2SM-KPM-v03.00, ORAN-WG3.E2SM-RC.03.00
16 #include <epan/packet.h>
17 #include <epan/strutil.h>
18 #include <epan/asn1.h>
19 #include <epan/prefs.h>
20 #include <epan/sctpppids.h>
21 #include <epan/expert.h>
22 #include <epan/proto_data.h>
23 #include <epan/conversation.h>
24 #include <epan/to_str.h>
25 #include <epan/oids.h>
27 #include <epan/stats_tree.h>
28 #include <wsutil/array.h>
30 #include "packet-e2ap.h"
31 #include "packet-per.h"
32 #include "packet-ntp.h"
34 #define PNAME "E2 Application Protocol"
38 /* Dissector will use SCTP PPID 70, 71 or 72 or SCTP port 37464. */
39 #define SCTP_PORT_E2AP 37464
41 /* RC Version (can't infer from OIDs..) */
42 enum manual_rc_version_choice
{
46 /* Default to later available version */
47 static int e2ap_rc_version_pref_choice
= (int)RC_Version_3
;
49 void proto_register_e2ap(void);
50 void proto_reg_handoff_e2ap(void);
52 static dissector_handle_t e2ap_handle
;
54 #include "packet-e2ap-val.h"
56 /* Initialize the protocol and registered fields */
57 static int proto_e2ap
;
58 #include "packet-e2ap-hf.c"
60 static int hf_e2ap_unmapped_ran_function_id
;
61 static int hf_e2ap_ran_function_name_not_recognised
;
62 static int hf_e2ap_ran_function_setup_frame
;
63 /* TODO: for each RAN Function, also link forward to where setup is referenced (if at all?). Maybe just first usage? */
65 static int hf_e2ap_dissector_version
;
66 static int hf_e2ap_frame_version
;
68 static int hf_e2ap_timestamp_string
;
71 /* Initialize the subtree pointers */
74 static expert_field ei_e2ap_ran_function_names_no_match
;
75 static expert_field ei_e2ap_ran_function_id_not_mapped
;
76 static expert_field ei_e2ap_ran_function_dissector_mismatch
;
77 static expert_field ei_e2ap_ran_function_max_dissectors_registered
;
79 #include "packet-e2ap-ett.c"
82 /* Forward declarations */
83 static int dissect_e2ap_RANfunction_Name(tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
);
86 static int dissect_E2SM_KPM_EventTriggerDefinition_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
87 static int dissect_E2SM_KPM_ActionDefinition_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
88 static int dissect_E2SM_KPM_IndicationHeader_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
89 static int dissect_E2SM_KPM_IndicationMessage_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
90 static int dissect_E2SM_KPM_RANfunction_Description_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
92 static int dissect_E2SM_RC_EventTrigger_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
93 static int dissect_E2SM_RC_ActionDefinition_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
94 static int dissect_E2SM_RC_RANFunctionDefinition_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
95 static int dissect_E2SM_RC_IndicationMessage_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
96 static int dissect_E2SM_RC_IndicationHeader_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
97 static int dissect_E2SM_RC_CallProcessID_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
98 static int dissect_E2SM_RC_ControlHeader_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
99 static int dissect_E2SM_RC_ControlMessage_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
100 static int dissect_E2SM_RC_ControlOutcome_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
102 static int dissect_E2SM_NI_EventTriggerDefinition_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
103 static int dissect_E2SM_NI_ActionDefinition_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
104 static int dissect_E2SM_NI_RANfunction_Description_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
105 static int dissect_E2SM_NI_IndicationMessage_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
106 static int dissect_E2SM_NI_IndicationHeader_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
107 static int dissect_E2SM_NI_CallProcessID_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
108 static int dissect_E2SM_NI_ControlHeader_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
109 static int dissect_E2SM_NI_ControlMessage_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
110 static int dissect_E2SM_NI_ControlOutcome_PDU(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
);
119 /* E2AP stats - Tap interface */
121 static void set_stats_message_type(packet_info
*pinfo
, int type
);
123 static const uint8_t *st_str_packets
= "Total Packets";
124 static const uint8_t *st_str_packet_types
= "E2AP Packet Types";
126 static int st_node_packets
= -1;
127 static int st_node_packet_types
= -1;
134 #define MTYPE_E2_CONNECTION_UPDATE 1
135 #define MTYPE_E2_CONNECTION_UPDATE_ACK 2
136 #define MTYPE_E2_CONNECTION_UPDATE_FAIL 3
137 #define MTYPE_E2_CONFIGURATION_UPDATE 4
138 #define MTYPE_E2_CONFIGURATION_UPDATE_ACK 5
139 #define MTYPE_E2_CONFIGURATION_UPDATE_FAIL 6
140 #define MTYPE_E2_SETUP_FAIL 7
141 #define MTYPE_E2_SETUP_REQUEST 8
142 #define MTYPE_E2_SETUP_RESPONSE 9
143 #define MTYPE_ERROR_INDICATION 10
144 #define MTYPE_RESET_REQUEST 11
145 #define MTYPE_RESET_RESPONSE 12
146 #define MTYPE_RIC_CONTROL_ACK 13
147 #define MTYPE_RIC_CONTROL_FAIL 14
148 #define MTYPE_RIC_CONTROL_REQUEST 15
149 #define MTYPE_RIC_IND 16
150 #define MTYPE_RIC_SERVICE_QUERY 17
151 #define MTYPE_RIC_SERVICE_UPDATE 18
152 #define MTYPE_RIC_SERVICE_UPDATE_ACK 19
153 #define MTYPE_RIC_SERVICE_UPDATE_FAIL 20
154 #define MTYPE_RIC_SUBSCRIPTION_FAIL 21
155 #define MTYPE_RIC_SUBSCRIPTION_REQUEST 22
156 #define MTYPE_RIC_SUBSCRIPTION_RESPONSE 23
157 #define MTYPE_RIC_SUBSCRIPTION_DELETE_FAIL 24
158 #define MTYPE_RIC_SUBSCRIPTION_DELETE_REQUEST 25
159 #define MTYPE_RIC_SUBSCRIPTION_DELETE_RESPONSE 26
160 #define MTYPE_RIC_SUBSCRIPTION_DELETE_REQUIRED 27
161 #define MTYPE_RIC_QUERY_REQUEST 28
162 #define MTYPE_RIC_QUERY_RESPONSE 29
163 #define MTYPE_RIC_QUERY_FAILURE 30
165 /* Value Strings. TODO: ext? */
166 static const value_string mtype_names
[] = {
167 { MTYPE_E2_CONNECTION_UPDATE
, "E2connectionUpdate"},
168 { MTYPE_E2_CONNECTION_UPDATE_ACK
, "E2connectionUpdateAcknowledge"},
169 { MTYPE_E2_CONNECTION_UPDATE_FAIL
, "E2connectionUpdateFailure"},
170 { MTYPE_E2_CONFIGURATION_UPDATE
, "E2nodeConfigurationUpdate"},
171 { MTYPE_E2_CONFIGURATION_UPDATE_ACK
, "E2nodeConfigurationUpdateAcknowledge"},
172 { MTYPE_E2_CONFIGURATION_UPDATE_FAIL
, "E2nodeConfigurationUpdateFailure"},
173 { MTYPE_E2_SETUP_FAIL
, "E2setupFailure"},
174 { MTYPE_E2_SETUP_REQUEST
, "E2setupRequest"},
175 { MTYPE_E2_SETUP_RESPONSE
, "E2setupResponse"},
176 { MTYPE_ERROR_INDICATION
, "ErrorIndication"},
177 { MTYPE_RESET_REQUEST
, "ResetRequest"},
178 { MTYPE_RESET_RESPONSE
, "ResetResponse"},
179 { MTYPE_RIC_CONTROL_ACK
, "RICcontrolAcknowledge"},
180 { MTYPE_RIC_CONTROL_FAIL
, "RICcontrolFailure"},
181 { MTYPE_RIC_CONTROL_REQUEST
, "RICcontrolRequest"},
182 { MTYPE_RIC_IND
, "RICindication"},
183 { MTYPE_RIC_SERVICE_QUERY
, "RICserviceQuery"},
184 { MTYPE_RIC_SERVICE_UPDATE
, "RICserviceUpdate"},
185 { MTYPE_RIC_SERVICE_UPDATE_ACK
, "RICserviceUpdateAcknowledge"},
186 { MTYPE_RIC_SERVICE_UPDATE_FAIL
, "RICserviceUpdateFailure"},
187 { MTYPE_RIC_SUBSCRIPTION_FAIL
, "RICsubscriptionFailure"},
188 { MTYPE_RIC_SUBSCRIPTION_REQUEST
, "RICsubscriptionRequest"},
189 { MTYPE_RIC_SUBSCRIPTION_RESPONSE
, "RICsubscriptionResponse"},
190 { MTYPE_RIC_SUBSCRIPTION_DELETE_FAIL
, "RICsubscriptionDeleteFailure"},
191 { MTYPE_RIC_SUBSCRIPTION_DELETE_REQUEST
, "RICsubscriptionDeleteRequest"},
192 { MTYPE_RIC_SUBSCRIPTION_DELETE_RESPONSE
, "RICsubscriptionDeleteResponse"},
193 { MTYPE_RIC_SUBSCRIPTION_DELETE_REQUIRED
, "RICsubscriptionDeleteRequired"},
194 { MTYPE_RIC_QUERY_REQUEST
, "RICQueryRequest"},
195 { MTYPE_RIC_QUERY_RESPONSE
, "RICQueryResponse"},
196 { MTYPE_RIC_QUERY_FAILURE
, "RICQueryFailure"},
200 static proto_tree
*top_tree
;
202 static void set_message_label(asn1_ctx_t
*actx
, int type
)
204 const char *label
= val_to_str_const(type
, mtype_names
, "Unknown");
205 col_append_sep_str(actx
->pinfo
->cinfo
, COL_INFO
, NULL
, label
);
206 proto_item_append_text(top_tree
, " (%s)", label
);
212 /* Temporary private info to remember while dissecting frame */
213 struct e2ap_private_data
{
214 uint32_t procedure_code
;
215 uint32_t protocol_ie_id
;
216 uint32_t message_type
;
218 uint32_t ran_function_id
;
220 #define MAX_GNB_ID_BYTES 6
221 uint8_t gnb_id_bytes
[MAX_GNB_ID_BYTES
];
222 dissector_handle_t component_configuration_dissector
;
223 struct e2ap_tap_t
*stats_tap
;
226 /* Lookup temporary private info */
227 static struct e2ap_private_data
*
228 e2ap_get_private_data(packet_info
*pinfo
)
230 struct e2ap_private_data
*e2ap_data
= (struct e2ap_private_data
*)p_get_proto_data(pinfo
->pool
, pinfo
, proto_e2ap
, 0);
232 e2ap_data
= wmem_new0(pinfo
->pool
, struct e2ap_private_data
);
233 p_add_proto_data(pinfo
->pool
, pinfo
, proto_e2ap
, 0, e2ap_data
);
238 /****************************************************************************************************************/
239 /* These are the strings that we look for at the beginning of RAN Function Description to identify RAN Function */
240 /* Static table mapping from string -> ran_function */
241 static const char* g_ran_function_name_table
[MAX_RANFUNCTIONS
] =
246 "{" /* For now, CCC is the only JSON-based RAN Function, so just match opening */
251 /* Per-conversation mapping: ranFunctionId -> ran_function+dissector */
253 uint32_t setup_frame
;
254 uint32_t ran_function_id
;
255 ran_function_t ran_function
;
256 char oid
[MAX_OID_LEN
]; // i.e., OID from setupRequest
257 ran_function_dissector_t
*dissector
;
258 } ran_function_id_mapping_t
;
261 #define MAX_RANFUNCTION_ENTRIES 8
262 uint32_t num_entries
;
263 ran_function_id_mapping_t entries
[MAX_RANFUNCTION_ENTRIES
];
264 } ran_functionid_table_t
;
266 static const char *ran_function_to_str(ran_function_t ran_function
)
268 switch (ran_function
) {
269 case KPM_RANFUNCTIONS
:
271 case RC_RANFUNCTIONS
:
273 case NI_RANFUNCTIONS
:
275 case CCC_RANFUNCTIONS
:
283 /* Table of RAN Function tables, indexed by gnbId (bytes) */
288 uint8_t id_value
[MAX_GNB_ID_BYTES
];
290 ran_functionid_table_t
*ran_function_table
;
292 } gnb_ran_functions_t
;
294 static gnb_ran_functions_t s_gnb_ran_functions_table
;
297 /* Table of available dissectors for each RAN function */
299 uint32_t num_available_dissectors
;
300 #define MAX_DISSECTORS_PER_RAN_FUNCTION 8
301 ran_function_dissector_t
* ran_function_dissectors
[MAX_DISSECTORS_PER_RAN_FUNCTION
];
302 } ran_function_available_dissectors_t
;
304 /* Available dissectors should be set here */
305 static ran_function_available_dissectors_t g_ran_functions_available_dissectors
[MAX_RANFUNCTIONS
];
307 /* Will be called from outside this file by separate dissectors */
308 void register_e2ap_ran_function_dissector(ran_function_t ran_function
, ran_function_dissector_t
*dissector
)
310 if ((ran_function
>= MIN_RANFUNCTIONS
) && (ran_function
< MAX_RANFUNCTIONS
)) {
311 ran_function_available_dissectors_t
*available_dissectors
= &g_ran_functions_available_dissectors
[ran_function
];
312 if (available_dissectors
->num_available_dissectors
< MAX_DISSECTORS_PER_RAN_FUNCTION
) {
313 available_dissectors
->ran_function_dissectors
[available_dissectors
->num_available_dissectors
++] = dissector
;
319 /* Get RANfunctionID table from conversation data - create new if necessary */
320 static ran_functionid_table_t
* get_ran_functionid_table(packet_info
*pinfo
)
322 conversation_t
*p_conv
;
323 ran_functionid_table_t
*p_conv_data
= NULL
;
325 /* Lookup conversation */
326 p_conv
= find_conversation(pinfo
->num
, &pinfo
->net_dst
, &pinfo
->net_src
,
327 conversation_pt_to_endpoint_type(pinfo
->ptype
),
328 pinfo
->destport
, pinfo
->srcport
, 0);
330 /* None, so create new data and set */
331 p_conv
= conversation_new(pinfo
->num
, &pinfo
->net_dst
, &pinfo
->net_src
,
332 conversation_pt_to_endpoint_type(pinfo
->ptype
),
333 pinfo
->destport
, pinfo
->srcport
, 0);
334 p_conv_data
= (ran_functionid_table_t
*)wmem_new0(wmem_file_scope(), ran_functionid_table_t
);
335 conversation_add_proto_data(p_conv
, proto_e2ap
, p_conv_data
);
338 /* Will return existing conversation data */
339 p_conv_data
= (ran_functionid_table_t
*)conversation_get_proto_data(p_conv
, proto_e2ap
);
346 /* Store new RANfunctionID -> Service Model mapping in table */
347 void e2ap_store_ran_function_mapping(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
, const char *name
)
349 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
350 ran_functionid_table_t
*table
= get_ran_functionid_table(pinfo
);
352 /* Need these pointers not to be NULL */
353 if (!name
|| !table
) {
357 /* Stop if already reached table limit */
358 if (table
->num_entries
== MAX_RANFUNCTION_ENTRIES
) {
359 proto_tree_add_expert_format(tree
, pinfo
, &ei_e2ap_ran_function_max_dissectors_registered
,
361 "Dissector wants to register for %s, but max (%u) already reached",
362 name
, MAX_RANFUNCTION_ENTRIES
);
366 uint32_t ran_function_id
= e2ap_data
->ran_function_id
;
368 ran_function_t ran_function
= MAX_RANFUNCTIONS
; /* i.e. invalid */
369 ran_function_dissector_t
*ran_function_dissector
= NULL
;
371 /* Check known RAN function names */
372 for (int n
=MIN_RANFUNCTIONS
; n
< MAX_RANFUNCTIONS
; n
++) {
373 if (strcmp(name
, g_ran_function_name_table
[n
]) == 0) {
376 /* Don't know OID yet, so for now, just choose first/only one */
377 /* TODO: is latest one likely to be more compatible? First fields (at least) come from E2SM.. */
378 if (g_ran_functions_available_dissectors
[table
->entries
[n
].ran_function
].num_available_dissectors
) {
379 ran_function_dissector
= g_ran_functions_available_dissectors
[table
->entries
[n
].ran_function
].ran_function_dissectors
[0];
385 /* Nothing to do if no matches */
386 if (ran_function
== MAX_RANFUNCTIONS
) {
390 /* If ID already mapped, can stop here */
391 for (unsigned n
=0; n
< table
->num_entries
; n
++) {
392 if (table
->entries
[n
].ran_function_id
== ran_function_id
) {
397 /* OK, store this new entry */
398 unsigned idx
= table
->num_entries
++;
399 table
->entries
[idx
].setup_frame
= pinfo
->num
;
400 table
->entries
[idx
].ran_function_id
= ran_function_id
;
401 table
->entries
[idx
].ran_function
= ran_function
;
402 table
->entries
[idx
].dissector
= ran_function_dissector
;
404 /* When add first entry, also want to set up table from gnbId -> table */
406 unsigned id_len
= e2ap_data
->gnb_id_len
;
407 uint8_t *id_value
= &e2ap_data
->gnb_id_bytes
[0];
410 for (unsigned n
=0; n
<s_gnb_ran_functions_table
.num_gnbs
; n
++) {
411 if ((s_gnb_ran_functions_table
.gnb
[n
].id_len
= id_len
) &&
412 (memcmp(s_gnb_ran_functions_table
.gnb
[n
].id_value
, id_value
, id_len
) == 0)) {
413 /* Already have an entry for this gnb. */
420 /* Add entry (if room for 1 more) */
421 uint32_t new_idx
= s_gnb_ran_functions_table
.num_gnbs
;
422 if (new_idx
< MAX_GNBS
-1) {
423 s_gnb_ran_functions_table
.gnb
[new_idx
].id_len
= id_len
;
424 memcpy(s_gnb_ran_functions_table
.gnb
[new_idx
].id_value
, id_value
, id_len
);
425 s_gnb_ran_functions_table
.gnb
[new_idx
].ran_function_table
= table
;
427 s_gnb_ran_functions_table
.num_gnbs
++;
433 /* Look for Service Model function pointers, based on current RANFunctionID from frame */
434 static ran_function_dissector_t
* lookup_ranfunction_dissector(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
)
436 /* Get ranFunctionID from this frame */
437 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
438 unsigned ran_function_id
= e2ap_data
->ran_function_id
;
440 /* Get ranFunction table corresponding to this frame's conversation */
441 ran_functionid_table_t
*table
= get_ran_functionid_table(pinfo
);
443 /* There is no ran function table associated with this frame's conversation info */
447 /* Find the entry in this table corresponding to ran_function_id */
448 for (unsigned n
=0; n
< table
->num_entries
; n
++) {
449 if (ran_function_id
== table
->entries
[n
].ran_function_id
) {
451 /* Point back at the setup frame where this ranfunction was mapped */
452 proto_item
*ti
= proto_tree_add_uint(tree
, hf_e2ap_ran_function_setup_frame
,
453 tvb
, 0, 0, table
->entries
[n
].setup_frame
);
454 /* Show that mapping */
455 proto_item_append_text(ti
, " (%u -> %s)", table
->entries
[n
].ran_function_id
, ran_function_to_str(table
->entries
[n
].ran_function
));
456 proto_item_set_generated(ti
);
458 /* Also take the chance to compare signalled and available dissector */
459 char *frame_version
= oid_resolved_from_string(pinfo
->pool
, table
->entries
[n
].oid
);
460 ti
= proto_tree_add_string(tree
, hf_e2ap_frame_version
, tvb
, 0, 0, frame_version
);
461 proto_item_set_generated(ti
);
463 /* N.B. in case of RC, this won't work! Would also be nice to include minor_version, but string wouldn't match */
464 char dissector_version
[16];
465 snprintf(dissector_version
, 16, "%s v%u",
466 ran_function_to_str(table
->entries
[n
].ran_function
),
467 table
->entries
[n
].dissector
->major_version
);
468 ti
= proto_tree_add_string(tree
, hf_e2ap_dissector_version
, tvb
, 0, 0, dissector_version
);
469 proto_item_set_generated(ti
);
471 if ((table
->entries
[n
].ran_function
!= RC_RANFUNCTIONS
) && (strcmp(frame_version
, dissector_version
) != 0)) {
472 /* Expert info for version mismatch! Have given up on RC though... */
473 expert_add_info_format(pinfo
, ti
, &ei_e2ap_ran_function_dissector_mismatch
,
474 "Dissector version mismatch - frame is %s but dissector is %s",
475 frame_version
, dissector_version
);
479 /* Return the dissector */
480 return table
->entries
[n
].dissector
;
485 /* No match found.. */
486 proto_item
*ti
= proto_tree_add_item(tree
, hf_e2ap_unmapped_ran_function_id
, tvb
, 0, 0, ENC_NA
);
487 expert_add_info_format(pinfo
, ti
, &ei_e2ap_ran_function_id_not_mapped
,
488 "Service Model not mapped for FunctionID %u", ran_function_id
);
494 /* Return the oid associated with this frame's conversation */
495 static char* lookup_ranfunction_oid(packet_info
*pinfo
)
497 /* Get ranFunctionID from this frame */
498 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
499 unsigned ran_function_id
= e2ap_data
->ran_function_id
;
501 /* Get ranFunction table corresponding to this frame's conversation */
502 ran_functionid_table_t
*table
= get_ran_functionid_table(pinfo
);
504 /* There is no ran function table associated with this frame's conversation info */
508 /* Find the entry in this table corresponding to ran_function_id */
509 for (unsigned n
=0; n
< table
->num_entries
; n
++) {
510 if (ran_function_id
== table
->entries
[n
].ran_function_id
) {
511 return (char*)(table
->entries
[n
].oid
);
520 /* We now know the OID - can we set a dissector that is an exact match from what has been signalled? */
521 static void update_dissector_using_oid(packet_info
*pinfo
, ran_function_t ran_function
)
523 char *frame_oid
= lookup_ranfunction_oid(pinfo
);
524 if (frame_oid
== NULL
) {
531 /* Look at available dissectors for this RAN function */
532 ran_function_available_dissectors_t
*available
= &g_ran_functions_available_dissectors
[ran_function
];
533 if (!available
->num_available_dissectors
) {
534 /* Oops - none available at all! */
538 /* Get mapping in use */
539 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
540 unsigned ran_function_id
= e2ap_data
->ran_function_id
;
541 ran_function_id_mapping_t
*mapping
= NULL
;
542 ran_functionid_table_t
*table
= get_ran_functionid_table(pinfo
);
547 /* Find the entry in this table corresponding to ran_function_id */
548 for (unsigned n
=0; n
< table
->num_entries
; n
++) {
549 if (ran_function_id
== table
->entries
[n
].ran_function_id
) {
550 mapping
= &(table
->entries
[n
]);
558 /* Set dissector pointer in ran_function_id_mapping_t */
559 if (ran_function
!= RC_RANFUNCTIONS
) {
560 for (uint32_t n
=0; n
< available
->num_available_dissectors
; n
++) {
561 /* If exact match, set it */
562 if (strcmp(frame_oid
, available
->ran_function_dissectors
[n
]->oid
) == 0) {
563 mapping
->dissector
= available
->ran_function_dissectors
[n
];
570 /* Special case for RC, which doesn't differentiate versions by OID. Lookup preference instead */
571 for (uint32_t n
=0; n
< available
->num_available_dissectors
; n
++) {
572 if (available
->ran_function_dissectors
[n
]->major_version
== e2ap_rc_version_pref_choice
) {
573 mapping
->dissector
= available
->ran_function_dissectors
[n
];
581 /* If not exact match, just set to first one available (TODO: closest above better?) */
583 mapping
->dissector
= available
->ran_function_dissectors
[0];
588 /* Update RANfunctionID -> Service Model mapping in table (now that we know OID) */
589 void e2ap_update_ran_function_mapping(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
, const char *oid
)
591 /* Copy OID into table entry (so may be used to choose and be compared with chosen available dissector */
592 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
593 ran_functionid_table_t
*table
= get_ran_functionid_table(pinfo
);
594 /* Make sure we have private and table data to compare */
595 if (!e2ap_data
|| !table
) {
598 ran_function_t ran_function
= MAX_RANFUNCTIONS
;
599 for (unsigned n
=0; n
< table
->num_entries
; n
++) {
600 if (e2ap_data
->ran_function_id
== table
->entries
[n
].ran_function_id
) {
601 ran_function
= table
->entries
[n
].ran_function
;
602 g_strlcpy(table
->entries
[n
].oid
, oid
, MAX_OID_LEN
);
606 /* Look up version from oid and show as generated field */
607 char *version
= oid_resolved_from_string(pinfo
->pool
, oid
);
608 proto_item
*ti
= proto_tree_add_string(tree
, hf_e2ap_frame_version
, tvb
, 0, 0, version
);
609 proto_item_set_generated(ti
);
611 /* Can now pick most appropriate dissector for this RAN Function name, based upon this OID and the available dissectors */
612 if (ran_function
< MAX_RANFUNCTIONS
) {
613 if (pinfo
->fd
->visited
) {
614 update_dissector_using_oid(pinfo
, ran_function
);
619 /* This will get used for E2nodeConfigurationUpdate, where we have a gnb-id but haven't seen E2setupRequest */
620 static void update_conversation_from_gnb_id(asn1_ctx_t
*actx
)
622 packet_info
*pinfo
= actx
->pinfo
;
623 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
625 /* Look for conversation data */
626 conversation_t
*p_conv
;
627 ran_functionid_table_t
*p_conv_data
= NULL
;
629 /* Lookup conversation */
630 p_conv
= find_conversation(pinfo
->num
, &pinfo
->net_dst
, &pinfo
->net_src
,
631 conversation_pt_to_endpoint_type(pinfo
->ptype
),
632 pinfo
->destport
, pinfo
->srcport
, 0);
635 /* None, so create new data and set */
636 p_conv
= conversation_new(pinfo
->num
, &pinfo
->net_dst
, &pinfo
->net_src
,
637 conversation_pt_to_endpoint_type(pinfo
->ptype
),
638 pinfo
->destport
, pinfo
->srcport
, 0);
639 p_conv_data
= (ran_functionid_table_t
*)wmem_new0(wmem_file_scope(), ran_functionid_table_t
);
640 conversation_add_proto_data(p_conv
, proto_e2ap
, p_conv_data
);
642 /* Look to see if we already know about the mappings in effect on this gNB */
643 unsigned id_len
= e2ap_data
->gnb_id_len
;
644 uint8_t *id_value
= &e2ap_data
->gnb_id_bytes
[0];
646 for (unsigned n
=0; n
<s_gnb_ran_functions_table
.num_gnbs
; n
++) {
647 if ((s_gnb_ran_functions_table
.gnb
[n
].id_len
= id_len
) &&
648 (memcmp(s_gnb_ran_functions_table
.gnb
[n
].id_value
, id_value
, id_len
) == 0)) {
650 /* Have an entry for this gnb. Set direct pointer to existing data (used by original conversation). */
651 /* N.B. This means that no further updates for the gNB are expected on different conversations.. */
652 p_conv_data
= s_gnb_ran_functions_table
.gnb
[n
].ran_function_table
;
653 conversation_add_proto_data(p_conv
, proto_e2ap
, p_conv_data
);
655 /* TODO: may want to try to add a generated field to pass back to E2setupRequest where RAN function mappings were first seen? */
662 static dissector_handle_t json_handle
;
664 static int dissect_E2SM_NI_JSON_PDU(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
666 /* Send to JSON dissector */
667 return call_dissector_only(json_handle
, tvb
, pinfo
, tree
, NULL
);
671 /* Dissector tables */
672 static dissector_table_t e2ap_ies_dissector_table
;
674 static dissector_table_t e2ap_extension_dissector_table
;
675 static dissector_table_t e2ap_proc_imsg_dissector_table
;
676 static dissector_table_t e2ap_proc_sout_dissector_table
;
677 static dissector_table_t e2ap_proc_uout_dissector_table
;
678 static dissector_table_t e2ap_n2_ie_type_dissector_table
;
680 static int dissect_ProtocolIEFieldValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
682 /* Currently not used
683 static int dissect_ProtocolIEFieldPairFirstValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
684 static int dissect_ProtocolIEFieldPairSecondValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
688 static int dissect_InitiatingMessageValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
689 static int dissect_SuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
690 static int dissect_UnsuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *);
693 #include "packet-e2ap-fn.c"
695 static int dissect_ProtocolIEFieldValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
697 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
698 return (dissector_try_uint_with_data(e2ap_ies_dissector_table
, e2ap_data
->protocol_ie_id
, tvb
, pinfo
, tree
, false, NULL
)) ? tvb_captured_length(tvb
) : 0;
703 /* Currently not used
704 static int dissect_ProtocolIEFieldPairFirstValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
706 struct e2ap_private_data *e2ap_data = e2ap_get_private_data(pinfo);
708 return (dissector_try_uint(e2ap_ies_p1_dissector_table, e2ap_data->protocol_ie_id, tvb, pinfo, tree)) ? tvb_captured_length(tvb) : 0;
711 static int dissect_ProtocolIEFieldPairSecondValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
713 struct e2ap_private_data *e2ap_data = e2ap_get_private_data(pinfo);
715 return (dissector_try_uint(e2ap_ies_p2_dissector_table, e2ap_data->protocol_ie_id, tvb, pinfo, tree)) ? tvb_captured_length(tvb) : 0;
720 static int dissect_InitiatingMessageValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
722 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
724 return (dissector_try_uint_with_data(e2ap_proc_imsg_dissector_table
, e2ap_data
->procedure_code
, tvb
, pinfo
, tree
, true, data
)) ? tvb_captured_length(tvb
) : 0;
727 static int dissect_SuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
729 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
731 return (dissector_try_uint_with_data(e2ap_proc_sout_dissector_table
, e2ap_data
->procedure_code
, tvb
, pinfo
, tree
, true, data
)) ? tvb_captured_length(tvb
) : 0;
734 static int dissect_UnsuccessfulOutcomeValue(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
736 struct e2ap_private_data
*e2ap_data
= e2ap_get_private_data(pinfo
);
738 return (dissector_try_uint_with_data(e2ap_proc_uout_dissector_table
, e2ap_data
->procedure_code
, tvb
, pinfo
, tree
, true, data
)) ? tvb_captured_length(tvb
) : 0;
742 static void set_stats_message_type(packet_info
*pinfo
, int type
)
744 struct e2ap_private_data
* priv_data
= e2ap_get_private_data(pinfo
);
745 priv_data
->stats_tap
->e2ap_mtype
= type
;
749 e2ap_stats_tree_init(stats_tree
*st
)
751 st_node_packets
= stats_tree_create_node(st
, st_str_packets
, 0, STAT_DT_INT
, true);
752 st_node_packet_types
= stats_tree_create_pivot(st
, st_str_packet_types
, st_node_packets
);
755 static tap_packet_status
756 e2ap_stats_tree_packet(stats_tree
* st
, packet_info
* pinfo _U_
,
757 epan_dissect_t
* edt _U_
, const void* p
, tap_flags_t flags _U_
)
759 const struct e2ap_tap_t
*pi
= (const struct e2ap_tap_t
*)p
;
761 tick_stat_node(st
, st_str_packets
, 0, false);
762 stats_tree_tick_pivot(st
, st_node_packet_types
,
763 val_to_str(pi
->e2ap_mtype
, mtype_names
,
764 "Unknown packet type (%d)"));
765 return TAP_PACKET_REDRAW
;
769 /* Main dissection function */
771 dissect_e2ap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
773 proto_item
*e2ap_item
= NULL
;
774 proto_tree
*e2ap_tree
= NULL
;
776 struct e2ap_tap_t
*tap_info
;
778 /* make entry in the Protocol column on summary display */
779 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "E2AP");
780 col_clear(pinfo
->cinfo
, COL_INFO
);
782 tap_info
= wmem_new(pinfo
->pool
, struct e2ap_tap_t
);
783 tap_info
->e2ap_mtype
= 0; /* unknown/invalid */
785 /* Add stats tap to private struct */
786 struct e2ap_private_data
*priv_data
= e2ap_get_private_data(pinfo
);
787 priv_data
->stats_tap
= tap_info
;
789 /* Store top-level tree */
790 top_tree
= e2ap_tree
;
792 /* create the e2ap protocol tree */
793 e2ap_item
= proto_tree_add_item(tree
, proto_e2ap
, tvb
, 0, -1, ENC_NA
);
794 e2ap_tree
= proto_item_add_subtree(e2ap_item
, ett_e2ap
);
796 dissect_E2AP_PDU_PDU(tvb
, pinfo
, e2ap_tree
, NULL
);
798 tap_queue_packet(e2ap_tap
, pinfo
, tap_info
);
799 return tvb_captured_length(tvb
);
803 static void e2ap_init_protocol(void)
805 s_gnb_ran_functions_table
.num_gnbs
= 0;
809 /*--- proto_reg_handoff_e2ap ---------------------------------------*/
811 proto_reg_handoff_e2ap(void)
813 dissector_add_uint_with_preference("sctp.port", SCTP_PORT_E2AP
, e2ap_handle
);
814 dissector_add_uint("sctp.ppi", E2_CP_PROTOCOL_ID
, e2ap_handle
);
815 dissector_add_uint("sctp.ppi", E2_UP_PROTOCOL_ID
, e2ap_handle
);
816 dissector_add_uint("sctp.ppi", E2_DU_PROTOCOL_ID
, e2ap_handle
);
818 #include "packet-e2ap-dis-tab.c"
820 /********************************/
821 /* Known OIDs for RAN providers */
822 /* N.B. These appear in the RAN Function ASN.1 definitions (except for CCC, which is based on JSON).
823 * There is a registry of known OIDs though in the E2SM specification
827 oid_add_from_string("KPM v1", "1.3.6.1.4.1.53148.1.1.2.2");
828 oid_add_from_string("KPM v2", "1.3.6.1.4.1.53148.1.2.2.2");
829 oid_add_from_string("KPM v3", "1.3.6.1.4.1.53148.1.3.2.2");
830 oid_add_from_string("KPM v4", "1.3.6.1.4.1.53148.1.4.2.2");
831 oid_add_from_string("KPM v5", "1.3.6.1.4.1.53148.1.5.2.2");
832 oid_add_from_string("KPM v6", "1.3.6.1.4.1.53148.1.6.2.2");
836 // TODO: appears to be the same??? Asking for clarification from ORAN..
837 oid_add_from_string("RC v1", "1.3.6.1.4.1.53148.1.1.2.3");
838 //oid_add_from_string("RC v3", "1.3.6.1.4.1.53148.1.1.2.3");
839 //oid_add_from_string("RC v4", "1.3.6.1.4.1.53148.1.1.2.3");
842 oid_add_from_string("NI v1", "1.3.6.1.4.1.53148.1.1.2.1");
843 oid_add_from_string("NI v2", "1.3.6.1.4.1.53148.1.2.2.1");
844 oid_add_from_string("NI v3", "1.3.6.1.4.1.53148.1.3.2.1");
845 oid_add_from_string("NI v4", "1.3.6.1.4.1.53148.1.4.2.1");
846 oid_add_from_string("NI v5", "1.3.6.1.4.1.53148.1.5.2.1");
847 oid_add_from_string("NI v6", "1.3.6.1.4.1.53148.1.6.2.1");
851 oid_add_from_string("CCC v1", "1.3.6.1.4.1.53148.1.1.2.4");
852 oid_add_from_string("CCC v2", "1.3.6.1.4.1.53148.1.2.2.4");
853 oid_add_from_string("CCC v3", "1.3.6.1.4.1.53148.1.3.2.4");
854 oid_add_from_string("CCC v4", "1.3.6.1.4.1.53148.1.4.2.4");
855 oid_add_from_string("CCC v5", "1.3.6.1.4.1.53148.1.5.2.4");
856 oid_add_from_string("CCC v6", "1.3.6.1.4.1.53148.1.6.2.4");
859 /*********************************************************/
860 /* Register 'built-in' dissectors (i.e., from asn1/e2ap) */
862 static ran_function_dissector_t kpm_v3
=
863 { "ORAN-E2SM-KPM", "1.3.6.1.4.1.53148.1.3.2.2", 3, 0,
864 { dissect_E2SM_KPM_RANfunction_Description_PDU
,
873 dissect_E2SM_KPM_ActionDefinition_PDU
,
874 dissect_E2SM_KPM_IndicationMessage_PDU
,
875 dissect_E2SM_KPM_IndicationHeader_PDU
,
876 NULL
, /* no dissect_E2SM_KPM_CallProcessID_PDU */
877 dissect_E2SM_KPM_EventTriggerDefinition_PDU
881 static ran_function_dissector_t rc_v1
=
882 { "ORAN-E2SM-RC", "1.3.6.1.4.1.53148.1.1.2.3", 1, 3,
883 { dissect_E2SM_RC_RANFunctionDefinition_PDU
,
885 dissect_E2SM_RC_ControlHeader_PDU
,
886 dissect_E2SM_RC_ControlMessage_PDU
,
887 dissect_E2SM_RC_ControlOutcome_PDU
,
893 dissect_E2SM_RC_ActionDefinition_PDU
,
894 dissect_E2SM_RC_IndicationMessage_PDU
,
895 dissect_E2SM_RC_IndicationHeader_PDU
,
896 dissect_E2SM_RC_CallProcessID_PDU
,
897 dissect_E2SM_RC_EventTrigger_PDU
901 static ran_function_dissector_t ni_v1
=
902 { "ORAN-E2SM-NI", "1.3.6.1.4.1.53148.1.1.2.1", 1, 0,
903 { dissect_E2SM_NI_RANfunction_Description_PDU
,
905 dissect_E2SM_NI_ControlHeader_PDU
,
906 dissect_E2SM_NI_ControlMessage_PDU
,
907 dissect_E2SM_NI_ControlOutcome_PDU
,
912 dissect_E2SM_NI_ActionDefinition_PDU
,
913 dissect_E2SM_NI_IndicationMessage_PDU
,
914 dissect_E2SM_NI_IndicationHeader_PDU
,
915 dissect_E2SM_NI_CallProcessID_PDU
,
916 dissect_E2SM_NI_EventTriggerDefinition_PDU
920 static ran_function_dissector_t ccc_v1
=
921 { "{", /*"ORAN-E2SM-CCC",*/ "1.3.6.1.4.1.53148.1.1.2.4", 1, 0,
923 { dissect_E2SM_NI_JSON_PDU
,
925 dissect_E2SM_NI_JSON_PDU
,
926 dissect_E2SM_NI_JSON_PDU
,
927 dissect_E2SM_NI_JSON_PDU
,
932 dissect_E2SM_NI_JSON_PDU
,
933 dissect_E2SM_NI_JSON_PDU
,
934 dissect_E2SM_NI_JSON_PDU
,
935 dissect_E2SM_NI_JSON_PDU
,
936 dissect_E2SM_NI_JSON_PDU
940 static ran_function_dissector_t ccc_v2
=
941 { "{", /*"ORAN-E2SM-CCC",*/ "1.3.6.1.4.1.53148.1.2.2.4", 2, 0,
943 { dissect_E2SM_NI_JSON_PDU
,
945 dissect_E2SM_NI_JSON_PDU
,
946 dissect_E2SM_NI_JSON_PDU
,
947 dissect_E2SM_NI_JSON_PDU
,
952 dissect_E2SM_NI_JSON_PDU
,
953 dissect_E2SM_NI_JSON_PDU
,
954 dissect_E2SM_NI_JSON_PDU
,
955 dissect_E2SM_NI_JSON_PDU
,
956 dissect_E2SM_NI_JSON_PDU
960 static ran_function_dissector_t ccc_v3
=
961 { "{", /*"ORAN-E2SM-CCC",*/ "1.3.6.1.4.1.53148.1.3.2.4", 3, 0,
963 { dissect_E2SM_NI_JSON_PDU
,
965 dissect_E2SM_NI_JSON_PDU
,
966 dissect_E2SM_NI_JSON_PDU
,
967 dissect_E2SM_NI_JSON_PDU
,
972 dissect_E2SM_NI_JSON_PDU
,
973 dissect_E2SM_NI_JSON_PDU
,
974 dissect_E2SM_NI_JSON_PDU
,
975 dissect_E2SM_NI_JSON_PDU
,
976 dissect_E2SM_NI_JSON_PDU
980 static ran_function_dissector_t ccc_v4
=
981 { "{", /*"ORAN-E2SM-CCC",*/ "1.3.6.1.4.1.53148.1.4.2.4", 4, 0,
983 { dissect_E2SM_NI_JSON_PDU
,
985 dissect_E2SM_NI_JSON_PDU
,
986 dissect_E2SM_NI_JSON_PDU
,
987 dissect_E2SM_NI_JSON_PDU
,
992 dissect_E2SM_NI_JSON_PDU
,
993 dissect_E2SM_NI_JSON_PDU
,
994 dissect_E2SM_NI_JSON_PDU
,
995 dissect_E2SM_NI_JSON_PDU
,
996 dissect_E2SM_NI_JSON_PDU
1000 static ran_function_dissector_t ccc_v5
=
1001 { "{", /*"ORAN-E2SM-CCC",*/ "1.3.6.1.4.1.53148.1.5.2.4", 5, 0,
1003 { dissect_E2SM_NI_JSON_PDU
,
1005 dissect_E2SM_NI_JSON_PDU
,
1006 dissect_E2SM_NI_JSON_PDU
,
1007 dissect_E2SM_NI_JSON_PDU
,
1012 dissect_E2SM_NI_JSON_PDU
,
1013 dissect_E2SM_NI_JSON_PDU
,
1014 dissect_E2SM_NI_JSON_PDU
,
1015 dissect_E2SM_NI_JSON_PDU
,
1016 dissect_E2SM_NI_JSON_PDU
1021 /* Register available dissectors.
1022 * Registering one version of each RAN Function here - others will need to be
1023 * registered in sepparate dissectors (e.g. kpm_v2) */
1024 register_e2ap_ran_function_dissector(KPM_RANFUNCTIONS
, &kpm_v3
);
1025 register_e2ap_ran_function_dissector(RC_RANFUNCTIONS
, &rc_v1
);
1026 register_e2ap_ran_function_dissector(NI_RANFUNCTIONS
, &ni_v1
);
1028 register_e2ap_ran_function_dissector(CCC_RANFUNCTIONS
, &ccc_v1
);
1029 register_e2ap_ran_function_dissector(CCC_RANFUNCTIONS
, &ccc_v2
);
1030 register_e2ap_ran_function_dissector(CCC_RANFUNCTIONS
, &ccc_v3
);
1031 register_e2ap_ran_function_dissector(CCC_RANFUNCTIONS
, &ccc_v4
);
1032 register_e2ap_ran_function_dissector(CCC_RANFUNCTIONS
, &ccc_v5
);
1035 /* Cache JSON dissector */
1036 json_handle
= find_dissector("json");
1038 stats_tree_register("e2ap", "e2ap", "E2AP", 0,
1039 e2ap_stats_tree_packet
, e2ap_stats_tree_init
, NULL
);
1045 /*--- proto_register_e2ap -------------------------------------------*/
1046 void proto_register_e2ap(void) {
1048 /* List of fields */
1050 static hf_register_info hf
[] = {
1051 #include "packet-e2ap-hfarr.c"
1052 { &hf_e2ap_unmapped_ran_function_id
,
1053 { "Unmapped RANfunctionID", "e2ap.unmapped-ran-function-id",
1054 FT_NONE
, BASE_NONE
, NULL
, 0x0,
1056 { &hf_e2ap_ran_function_name_not_recognised
,
1057 { "RANfunction name not recognised", "e2ap.ran-function-name-not-recognised",
1058 FT_NONE
, BASE_NONE
, NULL
, 0x0,
1060 { &hf_e2ap_ran_function_setup_frame
,
1061 { "RANfunction setup frame", "e2ap.setup-frame",
1062 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1065 { &hf_e2ap_dissector_version
,
1066 { "Version (dissector)", "e2ap.version.dissector",
1067 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1069 { &hf_e2ap_frame_version
,
1070 { "Version (frame)", "e2ap.version.frame",
1071 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1074 { &hf_e2ap_timestamp_string
,
1075 { "Timestamp string", "e2ap.timestamp-string",
1076 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1080 /* List of subtrees */
1081 static int *ett
[] = {
1083 #include "packet-e2ap-ettarr.c"
1086 static ei_register_info ei
[] = {
1087 { &ei_e2ap_ran_function_names_no_match
, { "e2ap.ran-function-names-no-match", PI_PROTOCOL
, PI_WARN
, "RAN Function name doesn't match known service models", EXPFILL
}},
1088 { &ei_e2ap_ran_function_id_not_mapped
, { "e2ap.ran-function-id-not-known", PI_PROTOCOL
, PI_WARN
, "Service Model not known for RANFunctionID", EXPFILL
}},
1089 { &ei_e2ap_ran_function_dissector_mismatch
, { "e2ap.ran-function-dissector-version-mismatch", PI_PROTOCOL
, PI_WARN
, "Available dissector does not match signalled", EXPFILL
}},
1090 { &ei_e2ap_ran_function_max_dissectors_registered
, { "e2ap.ran-function-max-dissectors-registered", PI_PROTOCOL
, PI_WARN
, "Max dissectors already registered in table", EXPFILL
}},
1094 expert_module_t
* expert_e2ap
;
1096 /* Register protocol */
1097 proto_e2ap
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
1098 /* Register fields and subtrees */
1099 proto_register_field_array(proto_e2ap
, hf
, array_length(hf
));
1100 proto_register_subtree_array(ett
, array_length(ett
));
1103 /* Register dissector */
1104 e2ap_handle
= register_dissector("e2ap", dissect_e2ap
, proto_e2ap
);
1106 module_t
*e2ap_module
;
1107 expert_e2ap
= expert_register_protocol(proto_e2ap
);
1108 expert_register_field_array(expert_e2ap
, ei
, array_length(ei
));
1110 /* Register dissector tables */
1111 e2ap_ies_dissector_table
= register_dissector_table("e2ap.ies", "E2AP-PROTOCOL-IES", proto_e2ap
, FT_UINT32
, BASE_DEC
);
1113 // e2ap_ies_p1_dissector_table = register_dissector_table("e2ap.ies.pair.first", "E2AP-PROTOCOL-IES-PAIR FirstValue", proto_e2ap, FT_UINT32, BASE_DEC);
1114 // e2ap_ies_p2_dissector_table = register_dissector_table("e2ap.ies.pair.second", "E2AP-PROTOCOL-IES-PAIR SecondValue", proto_e2ap, FT_UINT32, BASE_DEC);
1115 e2ap_extension_dissector_table
= register_dissector_table("e2ap.extension", "E2AP-PROTOCOL-EXTENSION", proto_e2ap
, FT_UINT32
, BASE_DEC
);
1116 e2ap_proc_imsg_dissector_table
= register_dissector_table("e2ap.proc.imsg", "E2AP-ELEMENTARY-PROCEDURE InitiatingMessage", proto_e2ap
, FT_UINT32
, BASE_DEC
);
1117 e2ap_proc_sout_dissector_table
= register_dissector_table("e2ap.proc.sout", "E2AP-ELEMENTARY-PROCEDURE SuccessfulOutcome", proto_e2ap
, FT_UINT32
, BASE_DEC
);
1118 e2ap_proc_uout_dissector_table
= register_dissector_table("e2ap.proc.uout", "E2AP-ELEMENTARY-PROCEDURE UnsuccessfulOutcome", proto_e2ap
, FT_UINT32
, BASE_DEC
);
1119 e2ap_n2_ie_type_dissector_table
= register_dissector_table("e2ap.n2_ie_type", "E2AP N2 IE Type", proto_e2ap
, FT_STRING
, STRING_CASE_SENSITIVE
);
1121 /* Preference settings */
1122 e2ap_module
= prefs_register_protocol(proto_e2ap
, NULL
);
1124 static const enum_val_t rc_version_vals
[] = {
1125 {"version-1", "Version-1", RC_Version_1
},
1126 {"version-3", "Version-3", RC_Version_3
},
1130 prefs_register_enum_preference(e2ap_module
, "rc_manual_version_choice",
1131 "Manual choice of RC dissector version to call",
1132 "Set version of RC dissector to use for that RANFunction. Unfortunately, so far all "
1133 "OIDs say they are version 1..",
1134 &e2ap_rc_version_pref_choice
, rc_version_vals
, true);
1136 register_init_routine(&e2ap_init_protocol
);
1138 e2ap_tap
= register_tap("e2ap");
1147 * indent-tabs-mode: nil
1150 * ex: set shiftwidth=2 tabstop=8 expandtab:
1151 * :indentSize=2:tabSize=8:noTabs=true: