epan/dissectors/pidl/ C99 drsuapi
[wireshark-sm.git] / epan / dissectors / asn1 / e2ap / packet-e2ap-template.c
bloba6e01d2e7fabf3bc096d9db318fce042ea56675e
1 /* packet-e2ap.c
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
14 #include "config.h"
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>
26 #include <epan/tap.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"
35 #define PSNAME "E2AP"
36 #define PFNAME "e2ap"
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 {
43 RC_Version_1=1,
44 RC_Version_3=3
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 */
72 static int ett_e2ap;
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_);
112 enum {
113 INITIATING_MESSAGE,
114 SUCCESSFUL_OUTCOME,
115 UNSUCCESSFUL_OUTCOME
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;
128 static int e2ap_tap;
130 struct e2ap_tap_t {
131 int e2ap_mtype;
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"},
197 { 0, NULL }
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;
219 uint32_t gnb_id_len;
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);
231 if (!e2ap_data) {
232 e2ap_data = wmem_new0(pinfo->pool, struct e2ap_private_data);
233 p_add_proto_data(pinfo->pool, pinfo, proto_e2ap, 0, e2ap_data);
235 return 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] =
243 "ORAN-E2SM-KPM",
244 "ORAN-E2SM-RC",
245 "ORAN-E2SM-NI",
246 "{" /* For now, CCC is the only JSON-based RAN Function, so just match opening */
251 /* Per-conversation mapping: ranFunctionId -> ran_function+dissector */
252 typedef struct {
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;
260 typedef struct {
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:
270 return "KPM";
271 case RC_RANFUNCTIONS:
272 return "RC";
273 case NI_RANFUNCTIONS:
274 return "NI";
275 case CCC_RANFUNCTIONS:
276 return "CCC";
278 default:
279 return "Unknown";
283 /* Table of RAN Function tables, indexed by gnbId (bytes) */
284 typedef struct {
285 #define MAX_GNBS 6
286 uint32_t num_gnbs;
287 struct {
288 uint8_t id_value[MAX_GNB_ID_BYTES];
289 uint32_t id_len;
290 ran_functionid_table_t *ran_function_table;
291 } gnb[MAX_GNBS];
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 */
298 typedef struct {
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);
329 if (!p_conv) {
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);
337 else {
338 /* Will return existing conversation data */
339 p_conv_data = (ran_functionid_table_t*)conversation_get_proto_data(p_conv, proto_e2ap);
342 return p_conv_data;
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) {
354 return;
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,
360 tvb, 0, 0,
361 "Dissector wants to register for %s, but max (%u) already reached",
362 name, MAX_RANFUNCTION_ENTRIES);
363 return;
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) {
374 ran_function = n;
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];
381 break;
385 /* Nothing to do if no matches */
386 if (ran_function == MAX_RANFUNCTIONS) {
387 return;
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) {
393 return;
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 */
405 if (idx == 0) {
406 unsigned id_len = e2ap_data->gnb_id_len;
407 uint8_t *id_value = &e2ap_data->gnb_id_bytes[0];
409 bool found = false;
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. */
414 found = true;
415 break;
419 if (!found) {
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);
442 if (!table) {
443 /* There is no ran function table associated with this frame's conversation info */
444 return NULL;
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) {
450 if (tree) {
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;
484 if (tree) {
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);
491 return NULL;
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);
503 if (!table) {
504 /* There is no ran function table associated with this frame's conversation info */
505 return NULL;
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);
515 /* Not found */
516 return NULL;
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) {
525 /* TODO: error? */
526 return;
529 bool found = false;
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! */
535 return;
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);
543 if (!table) {
544 return;
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]);
554 if (!mapping) {
555 return;
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];
564 found = true;
565 break;
569 else {
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];
574 found = true;
575 break;
581 /* If not exact match, just set to first one available (TODO: closest above better?) */
582 if (!found) {
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) {
596 return;
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);
634 if (!p_conv) {
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? */
656 break;
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;
748 static void
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 */
770 static int
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 ---------------------------------------*/
810 void
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
826 /* KPM */
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");
835 /* RC */
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");
841 /* NI */
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");
850 /* CCC */
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,
866 NULL,
867 NULL,
868 NULL,
869 NULL,
870 NULL,
871 NULL,
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,
888 /* new for v3 */
889 NULL,
890 NULL,
891 NULL,
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,
908 NULL,
909 NULL,
910 NULL,
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,
922 /* See table 5.1 */
923 { dissect_E2SM_NI_JSON_PDU,
925 dissect_E2SM_NI_JSON_PDU,
926 dissect_E2SM_NI_JSON_PDU,
927 dissect_E2SM_NI_JSON_PDU,
928 NULL,
929 NULL,
930 NULL,
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,
942 /* See table 5.1 */
943 { dissect_E2SM_NI_JSON_PDU,
945 dissect_E2SM_NI_JSON_PDU,
946 dissect_E2SM_NI_JSON_PDU,
947 dissect_E2SM_NI_JSON_PDU,
948 NULL,
949 NULL,
950 NULL,
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,
962 /* See table 5.1 */
963 { dissect_E2SM_NI_JSON_PDU,
965 dissect_E2SM_NI_JSON_PDU,
966 dissect_E2SM_NI_JSON_PDU,
967 dissect_E2SM_NI_JSON_PDU,
968 NULL,
969 NULL,
970 NULL,
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,
982 /* See table 5.1 */
983 { dissect_E2SM_NI_JSON_PDU,
985 dissect_E2SM_NI_JSON_PDU,
986 dissect_E2SM_NI_JSON_PDU,
987 dissect_E2SM_NI_JSON_PDU,
988 NULL,
989 NULL,
990 NULL,
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,
1002 /* See table 5.1 */
1003 { dissect_E2SM_NI_JSON_PDU,
1005 dissect_E2SM_NI_JSON_PDU,
1006 dissect_E2SM_NI_JSON_PDU,
1007 dissect_E2SM_NI_JSON_PDU,
1008 NULL,
1009 NULL,
1010 NULL,
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,
1055 NULL, HFILL }},
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,
1059 NULL, HFILL }},
1060 { &hf_e2ap_ran_function_setup_frame,
1061 { "RANfunction setup frame", "e2ap.setup-frame",
1062 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1063 NULL, HFILL }},
1065 { &hf_e2ap_dissector_version,
1066 { "Version (dissector)", "e2ap.version.dissector",
1067 FT_STRING, BASE_NONE, NULL, 0x0,
1068 NULL, HFILL }},
1069 { &hf_e2ap_frame_version,
1070 { "Version (frame)", "e2ap.version.frame",
1071 FT_STRING, BASE_NONE, NULL, 0x0,
1072 NULL, HFILL }},
1074 { &hf_e2ap_timestamp_string,
1075 { "Timestamp string", "e2ap.timestamp-string",
1076 FT_STRING, BASE_NONE, NULL, 0x0,
1077 NULL, HFILL }},
1080 /* List of subtrees */
1081 static int *ett[] = {
1082 &ett_e2ap,
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},
1127 {NULL, NULL, -1}
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");
1142 * Editor modelines
1144 * Local Variables:
1145 * c-basic-offset: 2
1146 * tab-width: 8
1147 * indent-tabs-mode: nil
1148 * End:
1150 * ex: set shiftwidth=2 tabstop=8 expandtab:
1151 * :indentSize=2:tabSize=8:noTabs=true: