diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-oran.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-oran.c')
-rw-r--r-- | epan/dissectors/packet-oran.c | 4335 |
1 files changed, 4335 insertions, 0 deletions
diff --git a/epan/dissectors/packet-oran.c b/epan/dissectors/packet-oran.c new file mode 100644 index 00000000..e495a55e --- /dev/null +++ b/epan/dissectors/packet-oran.c @@ -0,0 +1,4335 @@ +/* packet-oran.c + * Routines for O-RAN fronthaul UC-plane dissection + * Copyright 2020, Jan Schiefer, Keysight Technologies, Inc. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + /* + * Dissector for the O-RAN Fronthaul CUS protocol specification. + * The current implementation is based on the + * ORAN-WG4.CUS.0-v01.00 specification, dated 2019/01/31. + * N.B. by now, descriptions have been taken from a variety of versions, so some section number references + * referring to earlier specs are now out of date. + */ +#include <config.h> + +#include <epan/packet.h> +#include <epan/expert.h> +#include <epan/prefs.h> + +/* TODO: + * - sequence analysis based on sequence Id. N.B. separate counts per antenna for spatial stream (eAxC Id), plane, direction + * - tap stats by flow? + * - for U-Plane, track back to last C-Plane frame for that eAxC + * - use upCompHdr values from C-Plane if not overridden by U-Plane? + * N.B. this matching is tricky see 7.8.1 Coupling of C-Plane and U-Plane + * - Radio transport layer (eCPRI) fragmentation / reassembly + * - Detect/indicate signs of application layer fragmentation? + * - Not handling M-plane setting for "little endian byte order" as applied to IQ samples and beam weights + * - Really long long text in some items will not be displayed. Try to summarise/truncate + * - Register for UDP port(s) + * - for section extensions, check constraints (section type, which other extension types appear with them, order) + * - when section extensions are present, some section header fields are effectively ignored + */ + +/* Prototypes */ +void proto_reg_handoff_oran(void); +void proto_register_oran(void); + +/* Initialize the protocol and registered fields */ +static int proto_oran = -1; + +static int hf_oran_du_port_id = -1; +static int hf_oran_bandsector_id = -1; +static int hf_oran_cc_id = -1; +static int hf_oran_ru_port_id = -1; +static int hf_oran_sequence_id = -1; +static int hf_oran_e_bit = -1; +static int hf_oran_subsequence_id = -1; + +static int hf_oran_data_direction = -1; +static int hf_oran_payload_version = -1; +static int hf_oran_filter_index = -1; +static int hf_oran_frame_id = -1; +static int hf_oran_subframe_id = -1; +static int hf_oran_slot_id = -1; +static int hf_oran_slot_within_frame = -1; +static int hf_oran_start_symbol_id = -1; +static int hf_oran_numberOfSections = -1; +static int hf_oran_sectionType = -1; + +static int hf_oran_udCompHdr = -1; +static int hf_oran_udCompHdrIqWidth = -1; +static int hf_oran_udCompHdrIqWidth_pref = -1; +static int hf_oran_udCompHdrMeth = -1; +static int hf_oran_udCompHdrMeth_pref = -1; +static int hf_oran_numberOfUEs = -1; +static int hf_oran_timeOffset = -1; +static int hf_oran_frameStructure_fft = -1; +static int hf_oran_frameStructure_subcarrier_spacing = -1; +static int hf_oran_cpLength = -1; +static int hf_oran_section_id = -1; +static int hf_oran_rb = -1; +static int hf_oran_symInc = -1; +static int hf_oran_startPrbc = -1; +static int hf_oran_reMask = -1; +static int hf_oran_numPrbc = -1; +static int hf_oran_numSymbol = -1; +static int hf_oran_ef = -1; +static int hf_oran_beamId = -1; + +static int hf_oran_extension = -1; +static int hf_oran_exttype = -1; +static int hf_oran_extlen = -1; + +static int hf_oran_bfw_bundle = -1; +static int hf_oran_bfw_bundle_id = -1; +static int hf_oran_bfw = -1; +static int hf_oran_bfw_i = -1; +static int hf_oran_bfw_q = -1; + +static int hf_oran_ueId = -1; +static int hf_oran_freqOffset = -1; +static int hf_oran_regularizationFactor = -1; +static int hf_oran_laaMsgType = -1; +static int hf_oran_laaMsgLen = -1; +static int hf_oran_lbtHandle = -1; +static int hf_oran_lbtDeferFactor = -1; +static int hf_oran_lbtBackoffCounter = -1; +static int hf_oran_lbtOffset = -1; +static int hf_oran_MCOT = -1; +static int hf_oran_lbtMode = -1; +static int hf_oran_sfnSfEnd = -1; +static int hf_oran_lbtPdschRes = -1; +static int hf_oran_sfStatus = -1; +static int hf_oran_initialPartialSF = -1; +static int hf_oran_lbtDrsRes = -1; +static int hf_oran_lbtBufErr = -1; +static int hf_oran_lbtTrafficClass = -1; +static int hf_oran_lbtCWConfig_H = -1; +static int hf_oran_lbtCWConfig_T = -1; +static int hf_oran_lbtCWR_Rst = -1; + +static int hf_oran_reserved = -1; +static int hf_oran_reserved_1bit = -1; +static int hf_oran_reserved_2bits = -1; +static int hf_oran_reserved_4bits = -1; +static int hf_oran_reserved_6bits = -1; + +static int hf_oran_ext11_reserved = -1; + +static int hf_oran_bfwCompHdr = -1; +static int hf_oran_bfwCompHdr_iqWidth = -1; +static int hf_oran_bfwCompHdr_compMeth = -1; +static int hf_oran_symbolId = -1; +static int hf_oran_startPrbu = -1; +static int hf_oran_numPrbu = -1; +/* static int hf_oran_udCompParam = -1; */ + +static int hf_oran_bfwCompParam = -1; + +static int hf_oran_iSample = -1; +static int hf_oran_qSample = -1; + +static int hf_oran_blockScaler = -1; +static int hf_oran_compBitWidth = -1; +static int hf_oran_compShift = -1; + +static int hf_oran_repetition = -1; +static int hf_oran_rbgSize = -1; +static int hf_oran_rbgMask = -1; +static int hf_oran_noncontig_priority = -1; +static int hf_oran_symbolMask = -1; + +static int hf_oran_rsvd8 = -1; +static int hf_oran_rsvd16 = -1; +static int hf_oran_exponent = -1; +static int hf_oran_iq_user_data = -1; + +static int hf_oran_disable_bfws = -1; +static int hf_oran_rad = -1; +static int hf_oran_num_bund_prbs = -1; +static int hf_oran_beam_id = -1; +static int hf_oran_num_weights_per_bundle = -1; + +static int hf_oran_ack_nack_req_id = -1; + +static int hf_oran_off_start_prb_num_prb_pair = -1; +static int hf_oran_off_start_prb = -1; +static int hf_oran_num_prb = -1; + +static int hf_oran_samples_prb = -1; +static int hf_oran_ciSample = -1; +static int hf_oran_ciIsample = -1; +static int hf_oran_ciQsample = -1; + +static int hf_oran_beamGroupType = -1; +static int hf_oran_numPortc = -1; + +static int hf_oran_csf = -1; +static int hf_oran_modcompscaler = -1; + +static int hf_oran_modcomp_param_set = -1; +static int hf_oran_mc_scale_re_mask = -1; +static int hf_oran_mc_scale_offset = -1; + +static int hf_oran_eAxC_mask = -1; +static int hf_oran_technology = -1; +static int hf_oran_nullLayerInd = -1; + +static int hf_oran_portReMask = -1; +static int hf_oran_portSymbolMask = -1; + +static int hf_oran_ext19_port = -1; + +static int hf_oran_prb_allocation = -1; +static int hf_oran_nextSymbolId = -1; +static int hf_oran_nextStartPrbc = -1; + +static int hf_oran_puncPattern = -1; +static int hf_oran_numPuncPatterns = -1; +static int hf_oran_symbolMask_ext20 = -1; +static int hf_oran_startPuncPrb = -1; +static int hf_oran_numPuncPrb = -1; +static int hf_oran_puncReMask = -1; +static int hf_oran_RbgIncl = -1; + +static int hf_oran_ci_prb_group_size = -1; + +static int hf_oran_num_ueid = -1; + +static int hf_oran_antMask = -1; + +static int hf_oran_transmissionWindowOffset = -1; +static int hf_oran_transmissionWindowSize = -1; +static int hf_oran_toT = -1; + +static int hf_oran_bfaCompHdr = -1; +static int hf_oran_bfAzPtWidth = -1; +static int hf_oran_bfZePtWidth = -1; +static int hf_oran_bfAz3ddWidth = -1; +static int hf_oran_bfZe3ddWidth = -1; +static int hf_oran_bfAzPt = -1; +static int hf_oran_bfZePt = -1; +static int hf_oran_bfAz3dd = -1; +static int hf_oran_bfZe3dd = -1; +static int hf_oran_bfAzSl = -1; +static int hf_oran_bfZeSl = -1; + + +/* Computed fields */ +static int hf_oran_c_eAxC_ID = -1; +static int hf_oran_refa = -1; + +/* Initialize the subtree pointers */ +static gint ett_oran = -1; +static gint ett_oran_ecpri_rtcid = -1; +static gint ett_oran_ecpri_pcid = -1; +static gint ett_oran_ecpri_seqid = -1; +static gint ett_oran_section = -1; +static gint ett_oran_section_type = -1; +static gint ett_oran_u_timing = -1; +static gint ett_oran_u_section = -1; +static gint ett_oran_u_prb = -1; +static gint ett_oran_iq = -1; +static gint ett_oran_c_section_extension = -1; +static gint ett_oran_bfw_bundle = -1; +static gint ett_oran_bfw = -1; +static gint ett_oran_offset_start_prb_num_prb = -1; +static gint ett_oran_prb_cisamples = -1; +static gint ett_oran_cisample = -1; +static gint ett_oran_udcomphdr = -1; +static gint ett_oran_bfwcomphdr = -1; +static gint ett_oran_bfwcompparam = -1; +static gint ett_oran_ext19_port = -1; +static gint ett_oran_prb_allocation = -1; +static gint ett_oran_punc_pattern = -1; +static gint ett_oran_bfacomphdr = -1; +static gint ett_oran_modcomp_param_set = -1; + + +/* Expert info */ +static expert_field ei_oran_unsupported_bfw_compression_method = EI_INIT; +static expert_field ei_oran_invalid_sample_bit_width = EI_INIT; +static expert_field ei_oran_reserved_numBundPrb = EI_INIT; +static expert_field ei_oran_extlen_wrong = EI_INIT; +static expert_field ei_oran_invalid_eaxc_bit_width = EI_INIT; +static expert_field ei_oran_extlen_zero = EI_INIT; +static expert_field ei_oran_rbg_size_reserved = EI_INIT; +static expert_field ei_oran_frame_length = EI_INIT; + + +/* These are the message types handled by this dissector */ +#define ECPRI_MT_IQ_DATA 0 +#define ECPRI_MT_RT_CTRL_DATA 2 + + +/* Preference settings. */ +static guint pref_du_port_id_bits = 2; +static guint pref_bandsector_id_bits = 6; +static guint pref_cc_id_bits = 4; +static guint pref_ru_port_id_bits = 4; + +static guint pref_sample_bit_width_uplink = 14; +static guint pref_sample_bit_width_downlink = 14; + +/* Compression schemes */ +#define COMP_NONE 0 +#define COMP_BLOCK_FP 1 +#define COMP_BLOCK_SCALE 2 +#define COMP_U_LAW 3 +#define COMP_MODULATION 4 +#define BFP_AND_SELECTIVE_RE 5 +#define MOD_COMPR_AND_SELECTIVE_RE 6 + +static gint pref_iqCompressionUplink = COMP_BLOCK_FP; +static gint pref_iqCompressionDownlink = COMP_BLOCK_FP; +static gboolean pref_includeUdCompHeaderUplink = FALSE; +static gboolean pref_includeUdCompHeaderDownlink = FALSE; + +static guint pref_data_plane_section_total_rbs = 273; +static guint pref_num_weights_per_bundle = 32; +static guint pref_num_bf_antennas = 32; +static gboolean pref_showIQSampleValues = TRUE; + + +static const enum_val_t compression_options[] = { + { "COMP_NONE", "No Compression", COMP_NONE }, + { "COMP_BLOCK_FP", "Block Floating Point Compression", COMP_BLOCK_FP }, + { "COMP_BLOCK_SCALE", "Block Scaling Compression", COMP_BLOCK_SCALE }, + { "COMP_U_LAW", "u-Law Compression", COMP_U_LAW }, + { "COMP_MODULATION", "Modulation Compression", COMP_MODULATION }, + { "BFP_AND_SELECTIVE_RE", "BFP + selective RE sending", BFP_AND_SELECTIVE_RE }, + { "MOD_COMPR_AND_SELECTIVE_RE", "mod-compr + selective RE sending", MOD_COMPR_AND_SELECTIVE_RE }, + { NULL, NULL, 0 } +}; + +static const value_string e_bit[] = { + { 0, "More fragments follow" }, + { 1, "Last fragment" }, + { 0, NULL} +}; + +#define DIR_UPLINK 0 +#define DIR_DOWNLINK 1 + +static const value_string data_direction_vals[] = { + { DIR_UPLINK, "Uplink" }, + { DIR_DOWNLINK, "Downlink" }, + { 0, NULL} +}; + +static const value_string rb_vals[] = { + { 0, "Every RB used" }, + { 1, "Every other RB used" }, + { 0, NULL} +}; + +static const value_string sym_inc_vals[] = { + { 0, "Use the current symbol number" }, + { 1, "Increment the current symbol number" }, + { 0, NULL} +}; + +static const value_string lbtMode_vals[] = { + { 0, "Full LBT (regular LBT, sending reservation signal until the beginning of the SF/slot)" }, + { 1, "Partial LBT (looking back 25 usec prior to transmission" }, + { 2, "Partial LBT (looking back 34 usec prior to transmission" }, + { 3, "Full LBT and stop (regular LBT, without sending reservation signal" }, + { 0, NULL} +}; + +static const range_string filter_indices[] = { + {0, 0, "standard channel filter"}, + {1, 1, "UL filter for PRACH preamble formats 0, 1, 2; min. passband 839 x 1.25kHz = 1048.75 kHz"}, + {2, 2, "UL filter for PRACH preamble format 3, min. passband 839 x 5 kHz = 4195 kHz"}, + {3, 3, "UL filter for PRACH preamble formats A1, A2, A3, B1, B2, B3, B4, C0, C2; min. passband 139 x \u0394fRA"}, + {4, 4, "UL filter for NPRACH 0, 1; min. passband 48 x 3.75KHz = 180 KHz"}, + {5, 5, "UL filter for PRACH preamble formats"}, + {6, 15, "Reserved"}, + {0, 0, NULL} +}; + +/* Section types from Table 7.3.1-1 */ +enum section_c_types { + SEC_C_UNUSED_RB = 0, + SEC_C_NORMAL = 1, + SEC_C_RSVD2 = 2, + SEC_C_PRACH = 3, + SEC_C_RSVD4 = 4, + SEC_C_UE_SCHED = 5, + SEC_C_CH_INFO = 6, + SEC_C_LAA = 7, + SEC_C_ACK_NACK_FEEDBACK = 8 +}; + +static const range_string section_types[] = { + {SEC_C_UNUSED_RB, SEC_C_UNUSED_RB, "Unused Resource Blocks or symbols in Downlink or Uplink"}, + {SEC_C_NORMAL, SEC_C_NORMAL, "Most DL/UL radio channels"}, + {SEC_C_RSVD2, SEC_C_RSVD2, "Reserved for future use"}, + {SEC_C_PRACH, SEC_C_PRACH, "PRACH and mixed-numerology channels"}, + {SEC_C_RSVD4, SEC_C_RSVD4, "Reserved for future use"}, + {SEC_C_UE_SCHED, SEC_C_UE_SCHED, "UE scheduling information (UE-ID assignment to section)"}, + {SEC_C_CH_INFO, SEC_C_CH_INFO, "Channel information"}, + {SEC_C_LAA, SEC_C_LAA, "LAA"}, + {SEC_C_ACK_NACK_FEEDBACK, SEC_C_ACK_NACK_FEEDBACK, "ACK/NACK Feedback"}, + {9, 255, "Reserved for future use"}, + {0, 0, NULL} }; + +static const range_string section_types_short[] = { + { SEC_C_UNUSED_RB, SEC_C_UNUSED_RB, "(Unused RBs)" }, + { SEC_C_NORMAL, SEC_C_NORMAL, "(Most channels)" }, + { SEC_C_RSVD2, SEC_C_RSVD2, "(reserved)" }, + { SEC_C_PRACH, SEC_C_PRACH, "(PRACH/mixed-\u03bc)" }, + { SEC_C_RSVD4, SEC_C_RSVD4, "(reserved)" }, + { SEC_C_UE_SCHED, SEC_C_UE_SCHED, "(UE scheduling info)" }, + { SEC_C_CH_INFO, SEC_C_CH_INFO, "(Channel info)" }, + { SEC_C_LAA, SEC_C_LAA, "(LAA)" }, + { SEC_C_ACK_NACK_FEEDBACK, SEC_C_ACK_NACK_FEEDBACK, "(ACK/NACK)"}, + { 9, 255, "Reserved for future use" }, + { 0, 0, NULL } +}; + +static const range_string ud_comp_header_width[] = { + {0, 0, "I and Q are each 16 bits wide"}, + {1, 15, "Bit width of I and Q"}, + {0, 0, NULL} }; + +static const range_string ud_comp_header_meth[] = { + {COMP_NONE, COMP_NONE, "No compression" }, + {COMP_BLOCK_FP, COMP_BLOCK_FP, "Block floating point compression" }, + {COMP_BLOCK_SCALE, COMP_BLOCK_SCALE, "Block scaling" }, + {COMP_U_LAW, COMP_U_LAW, "Mu - law" }, + {COMP_MODULATION, COMP_MODULATION, "Modulation compression" }, + {BFP_AND_SELECTIVE_RE, BFP_AND_SELECTIVE_RE, "BFP + selective RE sending" }, + {MOD_COMPR_AND_SELECTIVE_RE, MOD_COMPR_AND_SELECTIVE_RE, "mod-compr + selective RE sending" }, + {7, 15, "Reserved"}, + {0, 0, NULL} +}; + +static const range_string frame_structure_fft[] = { + {0, 0, "Reserved (no FFT / iFFT processing)"}, + {1, 6, "Reserved"}, + {7, 7, "FFT size 128"}, + {8, 8, "FFT size 256"}, + {9, 9, "FFT size 512"}, + {10, 10, "FFT size 1024"}, + {11, 11, "FFT size 2048"}, + {12, 12, "FFT size 4096"}, + {13, 13, "FFT size 1536"}, + {14, 14, "FFT size 3072"}, + {15, 15, "Reserved"}, + {0, 0, NULL} +}; + +static const range_string subcarrier_spacings[] = { + { 0, 0, "SCS 15 kHz, 1 slot/subframe, slot length 1 ms" }, + { 1, 1, "SCS 30 kHz, 2 slots/subframe, slot length 500 \u03bcs" }, + { 2, 2, "SCS 60 kHz, 4 slots/subframe, slot length 250 \u03bcs" }, + { 3, 3, "SCS 120 kHz, 8 slots/subframe, slot length 125 \u03bcs" }, + { 4, 4, "SCS 240 kHz, 16 slots/subframe, slot length 62.5 \u03bcs" }, + { 5, 5, "SCS 480 kHz, 32 slots/subframe, slot length 31.25 \u03bcs" }, + { 6, 11, "Reserved" }, + { 12, 12, "SCS 1.25 kHz, 1 slot/subframe, slot length 1 ms" }, + { 13, 13, "SCS 3.75 kHz(LTE - specific), 1 slot/subframe, slot length 1 ms" }, + { 14, 14, "SCS 5 kHz, 1 slot/subframe, slot length 1 ms" }, + { 15, 15, "SCS 7.5 kHz(LTE - specific), 1 slot/subframe, slot length 1 ms" }, + { 0, 0, NULL } +}; + +static const range_string laaMsgTypes[] = { + {0, 0, "LBT_PDSCH_REQ - lls - O-DU to O-RU request to obtain a PDSCH channel"}, + {1, 1, "LBT_DRS_REQ - lls - O-DU to O-RU request to obtain the channel and send DRS"}, + {2, 2, "LBT_PDSCH_RSP - O-RU to O-DU response, channel acq success or failure"}, + {3, 3, "LBT_DRS_RSP - O-RU to O-DU response, DRS sending success or failure"}, + {4, 4, "LBT_Buffer_Error - O-RU to O-DU response, reporting buffer overflow"}, + {5, 5, "LBT_CWCONFIG_REQ - O-DU to O-RU request, congestion window configuration"}, + {6, 6, "LBT_CWCONFIG_REQ - O-RU to O-DU request, congestion window config"}, + {8, 15, "reserved for future methods"}, + {0, 0, NULL} +}; + + +static const value_string exttype_vals[] = { + {0, "Reserved"}, + {1, "Beamforming weights"}, + {2, "Beamforming attributes"}, + {3, "DL Precoding configuration parameters and indications"}, + {4, "Modulation compr. params"}, + {5, "Modulation compression additional scaling parameters"}, + {6, "Non-contiguous PRB allocation"}, + {7, "Multiple-eAxC designation"}, + {8, "Regularization factor"}, + {9, "Dynamic Spectrum Sharing parameters"}, + {10, "Multiple ports grouping"}, + {11, "Flexible BF weights"}, + {12, "Non-Contiguous PRB Allocation with Frequency Ranges"}, + {13, "PRB Allocation with Frequency Hopping"}, + {14, "Nulling-layer Info. for ueId-based beamforming"}, + {15, "Mixed-numerology Info. for ueId-based beamforming"}, + {16, "Section description for antenna mapping in UE channel information based UL beamforming"}, + {17, "Section description for indication of user port group"}, + {18, "Section description for Uplink Transmission Management"}, + {19, "Compact beamforming information for multiple port"}, + {20, "Puncturing extension"}, + {21, "Variable PRB group size for channel information"}, + {22, "ACK/NACK request"}, + {0, NULL} +}; + +static const value_string bfw_comp_headers_iq_width[] = { + {0, "I and Q are 16 bits wide"}, + {1, "I and Q are 1 bit wide"}, + {2, "I and Q are 2 bits wide"}, + {3, "I and Q are 3 bits wide"}, + {4, "I and Q are 4 bits wide"}, + {5, "I and Q are 5 bits wide"}, + {6, "I and Q are 6 bits wide"}, + {7, "I and Q are 7 bits wide"}, + {8, "I and Q are 8 bits wide"}, + {9, "I and Q are 9 bits wide"}, + {10, "I and Q are 10 bits wide"}, + {11, "I and Q are 11 bits wide"}, + {12, "I and Q are 12 bits wide"}, + {13, "I and Q are 13 bits wide"}, + {14, "I and Q are 14 bits wide"}, + {15, "I and Q are 15 bits wide"}, + {0, NULL} +}; + +static const value_string bfw_comp_headers_comp_meth[] = { + {COMP_NONE, "no compression"}, + {COMP_BLOCK_FP, "block floating point"}, + {COMP_BLOCK_SCALE, "block scaling"}, + {COMP_U_LAW, "u-law"}, + {4, "beamspace compression type I"}, + {5, "beamspace compression type II"}, + {0, NULL} +}; + +/* 7.7.6.2 */ +static const value_string rbg_size_vals[] = { + {0, "reserved"}, + {1, "1"}, + {2, "2"}, + {3, "3"}, + {4, "4"}, + {5, "6"}, + {6, "8"}, + {7, "16"}, + {0, NULL} +}; + +/* 7.7.6.5 */ +static const value_string priority_vals[] = { + {0, "0"}, + {1, "+1"}, + {2, "-2 (reserved, should not be used)"}, + {3, "-1"}, + {0, NULL} +}; + +/* 7.7.10.2 beamGroupType */ +static const value_string beam_group_type_vals[] = { + {0x0, "common beam"}, + {0x1, "beam matrix indication"}, + {0x2, "beam vector listing"}, + {0x3, "reserved"}, + {0, NULL} +}; + +/* 7.7.9.2 technology (interface name) */ +static const value_string interface_name_vals[] = { + {0x0, "LTE"}, + {0x1, "NR"}, + {0, NULL} +}; + +/* 7.7.18.4 toT (type of transmission) */ +static const value_string type_of_transmission_vals[] = { + {0x0, "normal transmission mode, data can be distributed in any way the O-RU is implemented to transmit data"}, + {0x1, "uniformly distributed over the transmission window"}, + {0, NULL} +}; + +/* 7.7.2.2 (width of bfa parameters) */ +static const value_string bfa_bw_vals[] = { + {0, "no bits, the field is not applicable (e.g., O-RU does not support it) or the default value shall be used"}, + {1, "2-bit bitwidth"}, + {2, "3-bit bitwidth"}, + {3, "4-bit bitwidth"}, + {4, "5-bit bitwidth"}, + {5, "6-bit bitwidth"}, + {6, "7-bit bitwidth"}, + {7, "8-bit bitwidth"}, + {0, NULL} +}; + +/* 7.7.2.7 & 7.7.2.8 */ +static const value_string sidelobe_suppression_vals[] = { + {0, "10 dB"}, + {1, "15 dB"}, + {2, "20 dB"}, + {3, "25 dB"}, + {4, "30 dB"}, + {5, "35 dB"}, + {6, "40 dB"}, + {7, ">= 45 dB"}, + {0, NULL} +}; + +static const value_string lbtTrafficClass_vals[] = { + {1, "Priority 1"}, + {2, "Priority 2"}, + {3, "Priority 3"}, + {4, "Priority 4"}, + {0, NULL} +}; + +static const value_string lbtPdschRes_vals[] = { + {0, "not sensing – indicates that the O-RU is transmitting data"}, + {1, "currently sensing – indicates the O-RU has not yet acquired the channel"}, + {2, "success – indicates that the channel was successfully acquired"}, + {3, "Failure – indicates expiration of the LBT timer. The LBT process should be reset"}, + {0, NULL} +}; + + +static const true_false_string tfs_sfStatus = +{ + "subframe was transmitted", + "subframe was dropped" +}; + +static const true_false_string tfs_lbtBufErr = +{ + "buffer overflow – data received at O-RU is larger than the available buffer size", + "reserved" +}; + + +/* Config (and worked-out allocations) bundles for ext11 (dynamic BFW) */ +typedef struct { + /* Ext 6 config */ + gboolean ext6_set; + + guint8 ext6_rbg_size; /* number of PRBs allocated by bitmask */ + + guint8 ext6_num_bits_set; + guint8 ext6_bits_set[28]; /* Which bit position this entry has */ + + /* Ext 12 config */ + gboolean ext12_set; + guint ext12_num_pairs; +#define MAX_BFW_EXT12_PAIRS 128 + struct { + guint8 off_start_prb; + guint8 num_prb; + } ext12_pairs[MAX_BFW_EXT12_PAIRS]; + + /* Ext 13 config */ + gboolean ext13_set; + guint ext13_num_start_prbs; +#define MAX_BFW_EXT13_ALLOCATIONS 128 + guint ext13_start_prbs[MAX_BFW_EXT13_ALLOCATIONS]; + /* TODO: store nextSymbolId here too? */ + + /* Results (after calling ext11_work_out_bundles()) */ + guint32 num_bundles; +#define MAX_BFW_BUNDLES 512 + struct { + guint32 start; /* first prb of bundle */ + guint32 end; /* last prb of bundle*/ + gboolean is_orphan; /* TRUE if not complete (i.e., < numBundPrb) */ + } bundles[MAX_BFW_BUNDLES]; +} ext11_settings_t; + + +/* Work out bundle allocation for ext 11. Take into account ext6, ext12 or ext13 in this section before ext 11. */ +/* Won't be called with numBundPrb=0 */ +static void ext11_work_out_bundles(guint startPrbc, + guint numPrbc, + guint numBundPrb, /* number of PRBs pre (full) bundle */ + ext11_settings_t *settings) +{ + /* Allocation configured by ext 6 */ + if (settings->ext6_set) { + guint bundles_per_entry = (settings->ext6_rbg_size / numBundPrb); + + guint bundles_set = 0; + for (guint8 n=0; n < settings->ext6_num_bits_set; n++) { + /* For each bit set in the mask */ + guint32 prb_start = (settings->ext6_bits_set[n] * settings->ext6_rbg_size); + + /* For each bundle within identified rbgSize block */ + for (guint m=0; m < bundles_per_entry; m++) { + settings->bundles[bundles_set].start = startPrbc+prb_start+(m*numBundPrb); + /* Start already beyond end, so doesn't count. */ + if (settings->bundles[bundles_set].start > (startPrbc+numPrbc-1)) { + break; + } + settings->bundles[bundles_set].end = startPrbc+prb_start+((m+1)*numBundPrb)-1; + if (settings->bundles[bundles_set].end > (startPrbc+numPrbc-1)) { + /* Extends beyond end, so counts but is an orphan bundle */ + settings->bundles[bundles_set].end = numPrbc; + settings->bundles[bundles_set].is_orphan = TRUE; + } + bundles_set++; + if (bundles_set == MAX_BFW_BUNDLES) { + return; + } + } + } + settings->num_bundles = bundles_set; + } + + /* Allocation configured by ext 12 */ + else if (settings->ext12_set) { + /* First, allocate normally from startPrbc, numPrbc */ + settings->num_bundles = (numPrbc+numBundPrb-1) / numBundPrb; + + /* Don't overflow settings->bundles[] ! */ + settings->num_bundles = MIN(MAX_BFW_BUNDLES, settings->num_bundles); + + for (guint32 n=0; n < settings->num_bundles; n++) { + settings->bundles[n].start = startPrbc + n*numBundPrb; + settings->bundles[n].end = settings->bundles[n].start + numBundPrb-1; + /* Does it go beyond the end? */ + if (settings->bundles[n].end > startPrbc+numPrbc) { + settings->bundles[n].end = numPrbc+numPrbc; + settings->bundles[n].is_orphan = TRUE; + } + } + if (settings->num_bundles == MAX_BFW_BUNDLES) { + return; + } + + guint prb_offset = startPrbc + numPrbc; + + /* Loop over pairs, adding bundles for each */ + for (guint p=0; p < settings->ext12_num_pairs; p++) { + prb_offset += settings->ext12_pairs[p].off_start_prb; + guint pair_bundles = (settings->ext12_pairs[p].num_prb+numBundPrb-1) / numBundPrb; + + for (guint32 n=0; n < pair_bundles; n++) { + guint idx = settings->num_bundles; + + settings->bundles[idx].start = prb_offset + n*numBundPrb; + settings->bundles[idx].end = settings->bundles[idx].start + numBundPrb-1; + /* Does it go beyond the end? */ + if (settings->bundles[idx].end > prb_offset + settings->ext12_pairs[p].num_prb) { + settings->bundles[idx].end = prb_offset + settings->ext12_pairs[p].num_prb; + settings->bundles[idx].is_orphan = TRUE; + } + /* Range check / return */ + settings->num_bundles++; + if (settings->num_bundles == MAX_BFW_BUNDLES) { + return; + } + } + + prb_offset += settings->ext12_pairs[p].num_prb; + } + } + + /* Allocation configured by ext 13 */ + else if (settings->ext13_set) { + guint alloc_size = (numPrbc+numBundPrb-1) / numBundPrb; + settings->num_bundles = alloc_size * settings->ext13_num_start_prbs; + + /* Don't overflow settings->bundles[] ! */ + settings->num_bundles = MIN(MAX_BFW_BUNDLES, settings->num_bundles); + + for (guint alloc=0; alloc < settings->ext13_num_start_prbs; alloc++) { + guint alloc_start = alloc * alloc_size; + for (guint32 n=0; n < alloc_size; n++) { + if ((alloc_start+n) >= MAX_BFW_BUNDLES) { + /* ERROR */ + return; + } + settings->bundles[alloc_start+n].start = settings->ext13_start_prbs[alloc] + startPrbc + n*numBundPrb; + settings->bundles[alloc_start+n].end = settings->bundles[alloc_start+n].start + numBundPrb-1; + if (settings->bundles[alloc_start+n].end > settings->ext13_start_prbs[alloc] + numPrbc) { + settings->bundles[alloc_start+n].end = settings->ext13_start_prbs[alloc] + numPrbc; + settings->bundles[alloc_start+n].is_orphan = TRUE; + } + } + } + } + + /* Bundles not controlled by other extensions - just divide up range into bundles we have */ + else { + settings->num_bundles = (numPrbc+numBundPrb-1) / numBundPrb; + + /* Don't overflow settings->bundles[] ! */ + settings->num_bundles = MIN(MAX_BFW_BUNDLES, settings->num_bundles); + + for (guint32 n=0; n < settings->num_bundles; n++) { + settings->bundles[n].start = startPrbc + n*numBundPrb; + settings->bundles[n].end = settings->bundles[n].start + numBundPrb-1; + /* Does it go beyond the end? */ + if (settings->bundles[n].end > startPrbc+numPrbc) { + settings->bundles[n].end = numPrbc+numPrbc; + settings->bundles[n].is_orphan = TRUE; + } + } + } +} + + + +/*******************************************************/ +/* Overall state of a flow (eAxC) */ +typedef struct { + guint32 last_cplane_frame; + nstime_t last_cplane_frame_ts; + /* TODO: add udCompHdr info for subsequence U-Plane frames? */ + + /* First U-PLane frame following 'last_cplane' frame */ + guint32 first_uplane_frame; + nstime_t first_uplane_frame_ts; +} flow_state_t; + +/* Table maintained on first pass from eAxC (guint16) -> flow_state_t* */ +static wmem_tree_t *flow_states_table = NULL; + + + +static void write_pdu_label_and_info(proto_item *ti1, proto_item *ti2, + packet_info *pinfo, const char *format, ...) G_GNUC_PRINTF(4, 5); + + /* Write the given formatted text to: + - the info column (if pinfo != NULL) + - 1 or 2 other labels (optional) + */ +static void write_pdu_label_and_info(proto_item *ti1, proto_item *ti2, + packet_info *pinfo, const char *format, ...) +{ +#define MAX_INFO_BUFFER 256 + char info_buffer[MAX_INFO_BUFFER]; + va_list ap; + + if ((ti1 == NULL) && (ti2 == NULL) && (pinfo == NULL)) { + return; + } + + va_start(ap, format); + vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap); + va_end(ap); + + /* Add to indicated places */ + if (pinfo != NULL) { + col_append_str(pinfo->cinfo, COL_INFO, info_buffer); + } + if (ti1 != NULL) { + proto_item_append_text(ti1, "%s", info_buffer); + } + if (ti2 != NULL) { + proto_item_append_text(ti2, "%s", info_buffer); + } +} + +/* Add section (type + PRB range) for C-Plane, U-Plane */ +static void +write_section_info(proto_item *section_heading, packet_info *pinfo, proto_item *protocol_item, + guint32 section_id, guint32 start_prbx, guint32 num_prbx, guint32 rb) +{ + switch (num_prbx) { + case 0: + write_pdu_label_and_info(section_heading, protocol_item, pinfo, ", Id: %d (all PRBs)", section_id); + break; + case 1: + write_pdu_label_and_info(section_heading, protocol_item, pinfo, ", Id: %d (PRB: %3u)", section_id, start_prbx); + break; + default: + write_pdu_label_and_info(section_heading, protocol_item, pinfo, ", Id: %d (PRB: %3u-%3u%s)", section_id, start_prbx, + start_prbx + (num_prbx-1)*(1+rb), rb ? " (every-other)" : ""); + } +} + +/* 5.1.3.2.7 (real time control data / IQ data transfer message series identifier */ +static void +addPcOrRtcid(tvbuff_t *tvb, proto_tree *tree, gint *offset, const char *name, guint16 *eAxC) +{ + /* Subtree */ + proto_item *item; + proto_tree *oran_pcid_tree = proto_tree_add_subtree(tree, tvb, *offset, 2, ett_oran_ecpri_pcid, &item, name); + guint64 duPortId, bandSectorId, ccId, ruPortId = 0; + gint id_offset = *offset; + + /* All parts of eAxC should be above 0, and should total 16 bits (breakdown controlled by preferences) */ + if (!((pref_du_port_id_bits > 0) && (pref_bandsector_id_bits > 0) && (pref_cc_id_bits > 0) && (pref_ru_port_id_bits > 0) && + ((pref_du_port_id_bits + pref_bandsector_id_bits + pref_cc_id_bits + pref_ru_port_id_bits) == 16))) { + expert_add_info(NULL, tree, &ei_oran_invalid_eaxc_bit_width); + *offset += 2; + return; + } + + guint bit_offset = *offset * 8; + + /* N.B. For sequence analysis / tapping, just interpret these 2 bytes as eAxC ID... */ + *eAxC = tvb_get_guint16(tvb, *offset, ENC_BIG_ENDIAN); + + /* DU Port ID */ + proto_tree_add_bits_ret_val(oran_pcid_tree, hf_oran_du_port_id, tvb, bit_offset, pref_du_port_id_bits, &duPortId, ENC_BIG_ENDIAN); + bit_offset += pref_du_port_id_bits; + /* BandSector ID */ + proto_tree_add_bits_ret_val(oran_pcid_tree, hf_oran_bandsector_id, tvb, bit_offset, pref_bandsector_id_bits, &bandSectorId, ENC_BIG_ENDIAN); + bit_offset += pref_bandsector_id_bits; + /* CC ID */ + proto_tree_add_bits_ret_val(oran_pcid_tree, hf_oran_cc_id, tvb, bit_offset, pref_cc_id_bits, &ccId, ENC_BIG_ENDIAN); + bit_offset += pref_cc_id_bits; + /* RU Port ID */ + proto_tree_add_bits_ret_val(oran_pcid_tree, hf_oran_ru_port_id, tvb, bit_offset, pref_ru_port_id_bits, &ruPortId, ENC_BIG_ENDIAN); + *offset += 2; + + proto_item_append_text(item, " (DU_Port_ID: %d, BandSector_ID: %d, CC_ID: %d, RU_Port_ID: %d)", (int)duPortId, (int)bandSectorId, (int)ccId, (int)ruPortId); + char id[16]; + snprintf(id, 16, "%x:%x:%x:%x", (int)duPortId, (int)bandSectorId, (int)ccId, (int)ruPortId); + proto_item *pi = proto_tree_add_string(oran_pcid_tree, hf_oran_c_eAxC_ID, tvb, id_offset, 2, id); + proto_item_set_generated(pi); +} + +/* 5.1.3.2.8 (message series identifier) */ +static void +addSeqid(tvbuff_t *tvb, proto_tree *oran_tree, gint *offset) +{ + /* Subtree */ + proto_item *seqIdItem; + proto_tree *oran_seqid_tree = proto_tree_add_subtree(oran_tree, tvb, *offset, 2, ett_oran_ecpri_seqid, &seqIdItem, "ecpriSeqid"); + guint32 seqId, subSeqId, e = 0; + /* Sequence ID */ + proto_tree_add_item_ret_uint(oran_seqid_tree, hf_oran_sequence_id, tvb, *offset, 1, ENC_NA, &seqId); + *offset += 1; + /* E bit */ + proto_tree_add_item_ret_uint(oran_seqid_tree, hf_oran_e_bit, tvb, *offset, 1, ENC_NA, &e); + /* Subsequence ID */ + proto_tree_add_item_ret_uint(oran_seqid_tree, hf_oran_subsequence_id, tvb, *offset, 1, ENC_NA, &subSeqId); + *offset += 1; + proto_item_append_text(seqIdItem, ", SeqId: %d, SubSeqId: %d, E: %d", seqId, subSeqId, e); +} + +/* Special case for uncompressed/16-bit value */ +static float uncompressed_to_float(guint32 h) +{ + gint16 i16 = h & 0x0000ffff; + return ((float)i16) / 0x7fff; +} + +/* 7.7.1.2 bfwCompHdr (beamforming weight compression header) */ +static int dissect_bfwCompHdr(tvbuff_t *tvb, proto_tree *tree, gint offset, + guint32 *iq_width, guint32 *comp_meth, proto_item **comp_meth_ti) +{ + /* Subtree */ + proto_item *bfwcomphdr_ti = proto_tree_add_string_format(tree, hf_oran_bfwCompHdr, + tvb, offset, 1, "", + "bfwCompHdr"); + proto_tree *bfwcomphdr_tree = proto_item_add_subtree(bfwcomphdr_ti, ett_oran_bfwcomphdr); + + /* Width and method */ + proto_tree_add_item_ret_uint(bfwcomphdr_tree, hf_oran_bfwCompHdr_iqWidth, + tvb, offset, 1, ENC_BIG_ENDIAN, iq_width); + *comp_meth_ti = proto_tree_add_item_ret_uint(bfwcomphdr_tree, hf_oran_bfwCompHdr_compMeth, + tvb, offset, 1, ENC_BIG_ENDIAN, comp_meth); + offset++; + + /* Summary */ + proto_item_append_text(bfwcomphdr_ti, " (IqWidth=%u, compMeth=%s)", + *iq_width, + val_to_str_const(*comp_meth, bfw_comp_headers_comp_meth, "reserved")); + + return offset; +} + +/* 7.7.1.3 bfwCompParam (beamforming weight compression parameter). + * Depends upon passed-in bfwCompMeth (field may be empty) */ +static int dissect_bfwCompParam(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint offset, + proto_item *ti, guint32 bfw_comp_method, + guint32 *exponent, gboolean *supported) +{ + /* Subtree */ + proto_item *bfwcompparam_ti = proto_tree_add_string_format(tree, hf_oran_bfwCompParam, + tvb, offset, 1, "", + "bfwCompParam"); + proto_tree *bfwcompparam_tree = proto_item_add_subtree(bfwcompparam_ti, ett_oran_bfwcompparam); + + proto_item_append_text(bfwcompparam_ti, + " (meth=%s)", val_to_str_const(bfw_comp_method, bfw_comp_headers_comp_meth, "Unknown")); + + + *supported = FALSE; + switch (bfw_comp_method) { + case COMP_NONE: /* no compression */ + /* In this case, bfwCompParam is absent! */ + *supported = TRUE; + break; + case COMP_BLOCK_FP: /* block floating point */ + /* 4 reserved bits + exponent */ + proto_tree_add_item_ret_uint(bfwcompparam_tree, hf_oran_exponent, + tvb, offset, 1, ENC_BIG_ENDIAN, exponent); + proto_item_append_text(bfwcompparam_ti, " exponent=%u", *exponent); + *supported = TRUE; + offset++; + break; + case COMP_BLOCK_SCALE: /* block scaling */ + proto_tree_add_item(bfwcompparam_tree, hf_oran_blockScaler, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + break; + case COMP_U_LAW: /* u-law */ + /* compBitWidth, compShift */ + proto_tree_add_item(bfwcompparam_tree, hf_oran_compBitWidth, + tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(bfwcompparam_tree, hf_oran_compShift, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + break; + case 4: /* beamspace I */ + /* TODO: activeBeamspaceCoefficientMask - ceil(K/8) octets */ + /* proto_tree_add_item(extension_tree, hf_oran_blockScaler, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; */ + break; + case 5: /* beamspace II */ + /* TODO: activeBeamspaceCoefficientMask - ceil(K/8) octets */ + /* reserved (4 bits) + exponent (4 bits) + proto_tree_add_item(bfwcompparam_tree, hf_oran_reserved_4bits, tvb, offset, 1, ENC_NA); + proto_tree_add_item_ret_uint(bfwcompparam_tree, hf_oran_exponent, tvb, offset, 1, ENC_BIG_ENDIAN, exponent); + offset += 1; + */ + break; + + default: + /* Not handled */ + break; + } + + /* Can't go on if compression scheme not supported */ + if (!*supported) { + expert_add_info_format(pinfo, ti, &ei_oran_unsupported_bfw_compression_method, + "BFW Compression method %u (%s) not supported by dissector", + bfw_comp_method, + val_to_str_const(bfw_comp_method, bfw_comp_headers_comp_meth, "Unknown")); + } + return offset; +} + + +static gfloat decompress_value(guint32 bits, guint32 comp_method, guint8 iq_width, guint32 exponent) +{ + switch (comp_method) { + case COMP_NONE: /* no compression */ + return uncompressed_to_float(bits); + + case COMP_BLOCK_FP: /* block floating point */ + { + /* A.1.2 Block Floating Point Decompression Algorithm */ + gint32 cPRB = bits; + guint32 scaler = 1 << exponent; /* i.e. 2^exponent */ + + /* Check last bit, in case we need to flip to -ve */ + if (cPRB >= (1<<(iq_width-1))) { + cPRB -= (1<<iq_width); + } + + const guint8 mantissa_bits = iq_width-1; + return (cPRB / (gfloat)(1 << (mantissa_bits))) * scaler; + } + + case COMP_BLOCK_SCALE: + case COMP_U_LAW: + case COMP_MODULATION: + case BFP_AND_SELECTIVE_RE: + case MOD_COMPR_AND_SELECTIVE_RE: + default: + /* TODO: Not supported! */ + return 0.0; + } +} + +/* Out-of-range value used for special case */ +#define ORPHAN_BUNDLE_NUMBER 999 + +/* Bundle of PRBs/TRX I/Q samples (ext 11) */ +static guint32 dissect_bfw_bundle(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, guint offset, + proto_item *comp_meth_ti, guint32 bfwcomphdr_comp_meth, + guint8 iq_width, + guint bundle_number, + guint first_prb, guint last_prb, gboolean is_orphan) +{ + /* Set bundle name */ + char bundle_name[32]; + if (!is_orphan) { + snprintf(bundle_name, 32, "Bundle %3u", bundle_number); + } + else { + g_strlcpy(bundle_name, "Orphaned ", 32); + } + + /* Create Bundle root */ + proto_item *bundle_ti = proto_tree_add_string_format(tree, hf_oran_bfw_bundle, + tvb, offset, 0, "", + "%s: (PRBs %3u-%3u)", + bundle_name, + first_prb, last_prb); + proto_tree *bundle_tree = proto_item_add_subtree(bundle_ti, ett_oran_bfw_bundle); + + /* Generated bundle id */ + proto_item *bundleid_ti = proto_tree_add_uint(bundle_tree, hf_oran_bfw_bundle_id, tvb, 0, 0, + bundle_number); + proto_item_set_generated(bundleid_ti); + proto_item_set_hidden(bundleid_ti); + + /* bfwCompParam */ + gboolean compression_method_supported = FALSE; + guint32 exponent = 0; + offset = dissect_bfwCompParam(tvb, bundle_tree, pinfo, offset, comp_meth_ti, + bfwcomphdr_comp_meth, &exponent, &compression_method_supported); + + /* Can't show details of unsupported compression method */ + if (!compression_method_supported) { + /* Don't know how to show, so give up */ + return offset; + } + + /* Create Bundle subtree */ + gint bit_offset = offset*8; + gint bfw_offset; + gint prb_offset = offset; + + /* beamId */ + guint32 beam_id; + proto_tree_add_item_ret_uint(bundle_tree, hf_oran_beam_id, tvb, offset, 2, ENC_BIG_ENDIAN, &beam_id); + proto_item_append_text(bundle_ti, " (beamId:%u) ", beam_id); + bit_offset += 16; + + /* Number of weights per bundle (from preference) */ + proto_item *wpb_ti = proto_tree_add_uint(bundle_tree, hf_oran_num_weights_per_bundle, tvb, 0, 0, + pref_num_weights_per_bundle); + proto_item_set_generated(wpb_ti); + + /* Add the weights for this bundle */ + for (guint m=0; m < pref_num_weights_per_bundle; m++) { + + /* Create subtree */ + bfw_offset = bit_offset / 8; + guint8 bfw_extent = ((bit_offset + (iq_width*2)) / 8) - bfw_offset; + proto_item *bfw_ti = proto_tree_add_string_format(bundle_tree, hf_oran_bfw, + tvb, bfw_offset, bfw_extent, + "", "TRX %3u: (", m); + proto_tree *bfw_tree = proto_item_add_subtree(bfw_ti, ett_oran_bfw); + + /* I */ + /* Get bits, and convert to float. */ + guint32 bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + gfloat value = decompress_value(bits, bfwcomphdr_comp_meth, iq_width, exponent); + /* Add to tree. */ + proto_tree_add_float_format_value(bfw_tree, hf_oran_bfw_i, tvb, bit_offset/8, (iq_width+7)/8, value, "#%u=%f", m, value); + bit_offset += iq_width; + proto_item_append_text(bfw_ti, "I%u=%f ", m, value); + + /* Q */ + /* Get bits, and convert to float. */ + bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + value = decompress_value(bits, bfwcomphdr_comp_meth, iq_width, exponent); + /* Add to tree. */ + proto_tree_add_float_format_value(bfw_tree, hf_oran_bfw_q, tvb, bit_offset/8, (iq_width+7)/8, value, "#%u=%f", m, value); + bit_offset += iq_width; + proto_item_append_text(bfw_ti, "Q%u=%f)", m, value); + } + + /* Set extent of bundle */ + proto_item_set_len(bundle_ti, (bit_offset+7)/8 - prb_offset); + + return (bit_offset+7)/8; +} + + +/* Section 7. + * N.B. these are the green parts of the tables showing Section Types, differing by section Type */ +static int dissect_oran_c_section(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, + guint32 sectionType, proto_item *protocol_item) +{ + guint offset = 0; + proto_tree *oran_tree = NULL; + proto_item *sectionHeading = NULL; + + oran_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_oran_section, §ionHeading, "Section"); + guint32 sectionId = 0; + + guint32 startPrbc; + guint32 numPrbc; + guint32 ueId = 0; + guint32 beamId = 0; + proto_item *beamId_ti = NULL; + gboolean beamId_ignored = FALSE; + + /* Config affecting ext11 bundles (initially unset) */ + ext11_settings_t ext11_settings; + memset(&ext11_settings, 0, sizeof(ext11_settings)); + + gboolean extension_flag = FALSE; + + /* These sections are similar, so handle as common with per-type differences */ + if (sectionType <= SEC_C_UE_SCHED) { + /* sectionID */ + proto_item *ti = proto_tree_add_item_ret_uint(oran_tree, hf_oran_section_id, tvb, offset, 2, ENC_BIG_ENDIAN, §ionId); + if (sectionId == 4095) { + proto_item_append_text(ti, " (not default coupling C/U planes using sectionId)"); + } + offset++; + + /* rb */ + guint32 rb; + proto_tree_add_item_ret_uint(oran_tree, hf_oran_rb, tvb, offset, 1, ENC_NA, &rb); + /* symInc */ + proto_tree_add_item(oran_tree, hf_oran_symInc, tvb, offset, 1, ENC_NA); + /* startPrbc */ + proto_tree_add_item_ret_uint(oran_tree, hf_oran_startPrbc, tvb, offset, 2, ENC_BIG_ENDIAN, &startPrbc); + offset += 2; + /* numPrbc */ + proto_item *numprbc_ti = proto_tree_add_item_ret_uint(oran_tree, hf_oran_numPrbc, tvb, offset, 1, ENC_NA, &numPrbc); + if (numPrbc == 0) { + proto_item_append_text(numprbc_ti, " (all PRBs - configured as %u)", pref_data_plane_section_total_rbs); + } + offset += 1; + /* reMask */ + proto_tree_add_item(oran_tree, hf_oran_reMask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset++; + /* numSymbol */ + guint32 numSymbol; + proto_tree_add_item_ret_uint(oran_tree, hf_oran_numSymbol, tvb, offset, 1, ENC_NA, &numSymbol); + offset++; + + /* [ef] (extension flag) */ + switch (sectionType) { + case SEC_C_NORMAL: /* Section Type "1" */ + case SEC_C_PRACH: /* Section Type "3" */ + case SEC_C_UE_SCHED: /* Section Type "5" */ + proto_tree_add_item_ret_boolean(oran_tree, hf_oran_ef, tvb, offset, 1, ENC_BIG_ENDIAN, &extension_flag); + break; + default: + break; + } + + write_section_info(sectionHeading, pinfo, protocol_item, sectionId, startPrbc, numPrbc, rb); + proto_item_append_text(sectionHeading, ", Symbols: %d", numSymbol); + + if (numPrbc == 0) { + /* Special case for all PRBs */ + numPrbc = pref_data_plane_section_total_rbs; + startPrbc = 0; /* may already be 0... */ + } + + /* Section type specific fields (after 'numSymbol') */ + switch (sectionType) { + case SEC_C_UNUSED_RB: /* Section Type "0" - Table 5.4 */ + /* reserved */ + proto_tree_add_item(oran_tree, hf_oran_rsvd16, tvb, offset, 2, ENC_NA); + offset += 2; + break; + + case SEC_C_NORMAL: /* Section Type "1" - Table 5.5 */ + /* beamId */ + beamId_ti = proto_tree_add_item_ret_uint(oran_tree, hf_oran_beamId, tvb, offset, 2, ENC_BIG_ENDIAN, &beamId); + offset += 2; + + proto_item_append_text(sectionHeading, ", BeamId: %d", beamId); + break; + + case SEC_C_PRACH: /* Section Type "3" - Table 5.6 */ + { + /* beamId */ + beamId_ti = proto_tree_add_item_ret_uint(oran_tree, hf_oran_beamId, tvb, offset, 2, ENC_BIG_ENDIAN, &beamId); + offset += 2; + + /* freqOffset */ + gint32 freqOffset; /* Yes, this is signed, so the implicit cast is intentional. */ + proto_item *freq_offset_item = proto_tree_add_item_ret_uint(oran_tree, hf_oran_freqOffset, tvb, offset, 3, ENC_BIG_ENDIAN, &freqOffset); + freqOffset |= 0xff000000; /* Must sign-extend */ + proto_item_set_text(freq_offset_item, "Frequency offset: %d \u0394f", freqOffset); + offset += 3; + + /* reserved */ + proto_tree_add_item(oran_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_item_append_text(sectionHeading, ", BeamId: %d, FreqOffset: %d \u0394f", beamId, freqOffset); + break; + } + + case SEC_C_UE_SCHED: /* Section Type "5" - Table 5.7 */ + /* ueId */ + proto_tree_add_item_ret_uint(oran_tree, hf_oran_ueId, tvb, offset, 2, ENC_NA, &ueId); + offset += 2; + + proto_item_append_text(sectionHeading, ", UEId: %d", ueId); + break; + + default: + break; + } + } + else if (sectionType == SEC_C_CH_INFO) { /* Section Type "6" */ + /* ef */ + proto_tree_add_item_ret_boolean(oran_tree, hf_oran_ef, tvb, offset, 1, ENC_BIG_ENDIAN, &extension_flag); + /* ueId */ + proto_tree_add_item_ret_uint(oran_tree, hf_oran_ueId, tvb, offset, 2, ENC_NA, &ueId); + offset += 2; + /* regularizationFactor */ + proto_tree_add_item(oran_tree, hf_oran_regularizationFactor, tvb, offset, 2, ENC_NA); + offset += 2; + /* reserved */ + proto_tree_add_item(oran_tree, hf_oran_reserved_4bits, tvb, offset, 1, ENC_NA); + /* rb */ + proto_tree_add_item(oran_tree, hf_oran_rb, tvb, offset, 1, ENC_NA); + /* symInc */ + proto_tree_add_item(oran_tree, hf_oran_symInc, tvb, offset, 1, ENC_NA); + /* startPrbc */ + proto_tree_add_item_ret_uint(oran_tree, hf_oran_startPrbc, tvb, offset, 2, ENC_BIG_ENDIAN, &startPrbc); + offset += 2; + /* numPrbc */ + proto_tree_add_item_ret_uint(oran_tree, hf_oran_numPrbc, tvb, offset, 1, ENC_NA, &numPrbc); + offset += 1; + + /* ciIsample,ciQsample pairs */ + guint m; + guint prb; + guint32 bit_offset = offset*8; + + /* Antenna count from preference */ + guint num_trx = pref_num_bf_antennas; + if (numPrbc > 1) { + proto_item_append_text(sectionHeading, " (UEId=%u PRBs %u-%u, %u antennas", ueId, startPrbc, startPrbc+numPrbc-1, num_trx); + } + else { + proto_item_append_text(sectionHeading, " (UEId=%u PRB %u, %u antennas", ueId, startPrbc, num_trx); + } + + for (prb=startPrbc; prb < startPrbc+numPrbc; prb++) { + + /* PRB subtree */ + guint prb_start_offset = bit_offset; + proto_item *prb_ti = proto_tree_add_string_format(oran_tree, hf_oran_samples_prb, + tvb, bit_offset/8, 0, + "", "PRB=%u", prb); + proto_tree *prb_tree = proto_item_add_subtree(prb_ti, ett_oran_prb_cisamples); + + /* Antennas */ + for (m=0; m < num_trx; m++) { + + guint sample_offset = bit_offset / 8; + guint8 sample_extent = ((bit_offset + (16*2)) / 8) - sample_offset; + + /* Create subtree for antenna */ + proto_item *sample_ti = proto_tree_add_string_format(prb_tree, hf_oran_ciSample, + tvb, sample_offset, sample_extent, + "", "TRX=%u: ", m); + proto_tree *sample_tree = proto_item_add_subtree(sample_ti, ett_oran_cisample); + + /* I */ + /* Get bits, and convert to float. */ + guint32 bits = tvb_get_bits(tvb, bit_offset, 16, ENC_BIG_ENDIAN); + gfloat value = uncompressed_to_float(bits); + + /* Add to tree. */ + proto_tree_add_float_format_value(sample_tree, hf_oran_ciIsample, tvb, bit_offset/8, (16+7)/8, value, "#%u=%f", m, value); + bit_offset += 16; + proto_item_append_text(sample_ti, "I%u=%f ", m, value); + + /* Q */ + /* Get bits, and convert to float. */ + bits = tvb_get_bits(tvb, bit_offset, 16, ENC_BIG_ENDIAN); + value = uncompressed_to_float(bits); + + /* Add to tree. */ + proto_tree_add_float_format_value(sample_tree, hf_oran_ciQsample, tvb, bit_offset/8, (16+7)/8, value, "#%u=%f", m, value); + bit_offset += 16; + proto_item_append_text(sample_ti, "Q%u=%f ", m, value); + } + proto_item_set_len(prb_ti, (bit_offset-prb_start_offset)/8); + } + offset = (bit_offset/8); + } + else if (sectionType == SEC_C_LAA) { /* Section Type "7" */ + /* 7.2.5 Table 6.4-6 */ + + /* laaMsgType */ + guint32 laa_msg_type; + proto_tree_add_item_ret_uint(oran_tree, hf_oran_laaMsgType, tvb, offset, 1, ENC_NA, &laa_msg_type); + /* laaMsgLen */ + guint32 laa_msg_len; + proto_item *len_ti = proto_tree_add_item_ret_uint(oran_tree, hf_oran_laaMsgLen, tvb, offset, 1, ENC_NA, &laa_msg_len); + proto_item_append_text(len_ti, " (%u bytes)", 4*(laa_msg_len+1)); + offset += 1; + + int payload_offset = offset; + + /* Payload */ + switch (laa_msg_type) { + case 0: + /* LBT_PDSCH_REQ */ + /* lbtHandle (16 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtHandle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* lbtOffset (10 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtOffset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 1; + /* lbtMode (2 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_lbtMode, tvb, offset*8, 2, ENC_BIG_ENDIAN); + /* reserved (1 bit) */ + /* lbtDeferFactor (3 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtDeferFactor, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* lbtBackoffCounter (10 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtBackoffCounter, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 1; + /* MCOT (4 bits) */ + proto_tree_add_item(oran_tree, hf_oran_MCOT, tvb, offset, 1, ENC_BIG_ENDIAN); + /* reserved (10 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_reserved, tvb, (offset*8)+6, 10, ENC_BIG_ENDIAN); + break; + case 1: + /* LBT_DRS_REQ */ + /* lbtHandle (16 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtHandle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* lbtOffset (10 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtOffset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 1; + /* lbtMode (2 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_lbtMode, tvb, offset*8, 2, ENC_BIG_ENDIAN); + /* reserved (28 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_reserved, tvb, (offset*8)+4, 28, ENC_BIG_ENDIAN); + break; + case 2: + /* LBT_PDSCH_RSP */ + /* lbtHandle (16 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtHandle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* lbtPdschRes (2 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtPdschRes, tvb, offset, 1, ENC_BIG_ENDIAN); + /* inParSF (1 bit) */ + proto_tree_add_item(oran_tree, hf_oran_initialPartialSF, tvb, offset, 1, ENC_BIG_ENDIAN); + /* sfStatus (1 bit) */ + proto_tree_add_item(oran_tree, hf_oran_sfStatus, tvb, offset, 1, ENC_BIG_ENDIAN); + /* sfnSf (12 bits) */ + proto_tree_add_item(oran_tree, hf_oran_sfnSfEnd, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* reserved (24 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_reserved, tvb, (offset*8), 24, ENC_BIG_ENDIAN); + break; + case 3: + /* LBT_DRS_RSP */ + /* lbtHandle (16 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtHandle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* lbtDrsRes (1 bit) */ + proto_tree_add_item(oran_tree, hf_oran_lbtDrsRes, tvb, offset, 1, ENC_BIG_ENDIAN); + /* reserved (7 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_reserved, tvb, (offset*8)+1, 7, ENC_BIG_ENDIAN); + break; + case 4: + /* LBT_Buffer_Error */ + /* lbtHandle (16 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtHandle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* lbtBufErr (1 bit) */ + proto_tree_add_item(oran_tree, hf_oran_lbtBufErr, tvb, offset, 1, ENC_BIG_ENDIAN); + /* reserved (7 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_reserved, tvb, (offset*8)+1, 7, ENC_BIG_ENDIAN); + break; + case 5: + /* LBT_CWCONFIG_REQ */ + /* lbtHandle (16 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtHandle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* lbtCWConfig_H (8 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtCWConfig_H, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* lbtCWConfig_T (8 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtCWConfig_T, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* lbtMode (2 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_lbtMode, tvb, offset*8, 2, ENC_BIG_ENDIAN); + /* lbtTrafficClass (3 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtTrafficClass, tvb, offset, 1, ENC_BIG_ENDIAN); + /* reserved (19 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_reserved, tvb, (offset*8)+5, 19, ENC_BIG_ENDIAN); + break; + case 6: + /* LBT_CWCONFIG_RSP */ + /* lbtHandle (16 bits) */ + proto_tree_add_item(oran_tree, hf_oran_lbtHandle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* lbtCWR_Rst (1 bit) */ + proto_tree_add_item(oran_tree, hf_oran_lbtCWR_Rst, tvb, offset, 1, ENC_BIG_ENDIAN); + /* reserved (7 bits) */ + proto_tree_add_bits_item(oran_tree, hf_oran_reserved, tvb, (offset*8)+1, 7, ENC_BIG_ENDIAN); + break; + + default: + /* Unhandled! */ + break; + } + /* For now just skip indicated length of bytes */ + offset = payload_offset + 4*(laa_msg_len+1); + } + + /* Section extension commands */ + while (extension_flag) { + + gint extension_start_offset = offset; + + /* Create subtree for each extension (with summary) */ + proto_item *extension_ti = proto_tree_add_string_format(oran_tree, hf_oran_extension, + tvb, offset, 0, "", "Extension"); + proto_tree *extension_tree = proto_item_add_subtree(extension_ti, ett_oran_c_section_extension); + + /* ef (i.e. another extension after this one?) */ + proto_tree_add_item_ret_boolean(extension_tree, hf_oran_ef, tvb, offset, 1, ENC_BIG_ENDIAN, &extension_flag); + + /* extType */ + guint32 exttype; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_exttype, tvb, offset, 1, ENC_BIG_ENDIAN, &exttype); + offset++; + proto_item_append_text(sectionHeading, " (ext-%u)", exttype); + + proto_item_append_text(extension_ti, " (ext-%u: %s)", exttype, val_to_str_const(exttype, exttype_vals, "Unknown")); + + /* extLen (number of 32-bit words) */ + guint32 extlen_len = ((exttype==11)||(exttype==19)||(exttype==20)) ? 2 : 1; /* Extensions 11/19/20 are special */ + guint32 extlen; + proto_item *extlen_ti = proto_tree_add_item_ret_uint(extension_tree, hf_oran_extlen, tvb, + offset, extlen_len, ENC_BIG_ENDIAN, &extlen); + proto_item_append_text(extlen_ti, " (%u bytes)", extlen*4); + offset += extlen_len; + if (extlen == 0) { + expert_add_info_format(pinfo, extlen_ti, &ei_oran_extlen_zero, + "extlen value of 0 is reserved"); + /* Break out to avoid infinitely looping! */ + break; + } + + switch (exttype) { + + case 1: /* Beamforming Weights Extension type */ + { + guint32 bfwcomphdr_iq_width, bfwcomphdr_comp_meth; + proto_item *comp_meth_ti = NULL; + + /* bfwCompHdr (2 subheaders - bfwIqWidth and bfwCompMeth)*/ + offset = dissect_bfwCompHdr(tvb, extension_tree, offset, + &bfwcomphdr_iq_width, &bfwcomphdr_comp_meth, &comp_meth_ti); + + /* Look up width of samples. */ + guint8 iq_width = !bfwcomphdr_iq_width ? 16 : bfwcomphdr_iq_width; + + /* bfwCompParam */ + guint32 exponent = 0; + gboolean compression_method_supported = FALSE; + offset = dissect_bfwCompParam(tvb, extension_tree, pinfo, offset, comp_meth_ti, + bfwcomphdr_comp_meth, &exponent, &compression_method_supported); + + /* Can't show details of unsupported compression method */ + if (!compression_method_supported) { + break; + } + + /* We know: + - iq_width (above) + - numBfWeights (taken from preference) + - remaining bytes in extension + We can therefore derive TRX (number of antennas). + */ + + /* I & Q samples + Don't know how many there will be, so just fill available bytes... + */ + guint weights_bytes = (extlen*4)-3; + guint num_weights_pairs = (weights_bytes*8) / (iq_width*2); + guint num_trx = num_weights_pairs; + gint bit_offset = offset*8; + + for (guint n=0; n < num_trx; n++) { + /* Create antenna subtree */ + gint bfw_offset = bit_offset / 8; + proto_item *bfw_ti = proto_tree_add_string_format(extension_tree, hf_oran_bfw, + tvb, bfw_offset, 0, "", "TRX %3u: (", n); + proto_tree *bfw_tree = proto_item_add_subtree(bfw_ti, ett_oran_bfw); + + /* I value */ + /* Get bits, and convert to float. */ + guint32 bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + gfloat value = decompress_value(bits, COMP_BLOCK_FP, iq_width, exponent); + /* Add to tree. */ + proto_tree_add_float_format_value(bfw_tree, hf_oran_bfw_i, tvb, bit_offset/8, (iq_width+7)/8, value, "%f", value); + bit_offset += iq_width; + proto_item_append_text(bfw_ti, "I=%f ", value); + + /* Leave a gap between I and Q values */ + proto_item_append_text(bfw_ti, " "); + + /* Q value */ + /* Get bits, and convert to float. */ + bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + value = decompress_value(bits, COMP_BLOCK_FP, iq_width, exponent); + /* Add to tree. */ + proto_tree_add_float_format_value(bfw_tree, hf_oran_bfw_q, tvb, bit_offset/8, (iq_width+7)/8, value, "%f", value); + bit_offset += iq_width; + proto_item_append_text(bfw_ti, "Q=%f", value); + + proto_item_append_text(bfw_ti, ")"); + proto_item_set_len(bfw_ti, (bit_offset+7)/8 - bfw_offset); + } + /* Need to round to next byte */ + offset = (bit_offset+7)/8; + + break; + } + + case 2: /* Beamforming attributes */ + { + /* bfaCompHdr (get widths of fields to follow) */ + guint32 bfAzPtWidth, bfZePtWidth, bfAz3ddWidth, bfZe3ddWidth; + /* subtree */ + proto_item *bfa_ti = proto_tree_add_string_format(extension_tree, hf_oran_bfaCompHdr, + tvb, offset, 2, "", "bfaCompHdr"); + proto_tree *bfa_tree = proto_item_add_subtree(bfa_ti, ett_oran_bfacomphdr); + + /* reserved (2 bits) */ + proto_tree_add_item(bfa_tree, hf_oran_reserved_2bits, tvb, offset, 1, ENC_BIG_ENDIAN); + /* bfAzPtWidth (3 bits) */ + proto_tree_add_item_ret_uint(bfa_tree, hf_oran_bfAzPtWidth, tvb, offset, 1, ENC_BIG_ENDIAN, &bfAzPtWidth); + /* bfZePtWidth (3 bits) */ + proto_tree_add_item_ret_uint(bfa_tree, hf_oran_bfZePtWidth, tvb, offset, 1, ENC_BIG_ENDIAN, &bfZePtWidth); + offset += 1; + + /* reserved (2 bits) */ + proto_tree_add_item(bfa_tree, hf_oran_reserved_2bits, tvb, offset, 1, ENC_BIG_ENDIAN); + /* bfAz3ddWidth (3 bits) */ + proto_tree_add_item_ret_uint(bfa_tree, hf_oran_bfAz3ddWidth, tvb, offset, 1, ENC_BIG_ENDIAN, &bfAz3ddWidth); + /* bfZe3ddWidth (3 bits) */ + proto_tree_add_item_ret_uint(bfa_tree, hf_oran_bfZe3ddWidth, tvb, offset, 1, ENC_BIG_ENDIAN, &bfZe3ddWidth); + offset += 1; + + guint bit_offset = offset*8; + + /* bfAzPt */ + if (bfAzPtWidth > 0) { + proto_tree_add_bits_item(extension_tree, hf_oran_bfAzPt, tvb, bit_offset, bfAzPtWidth+1, ENC_BIG_ENDIAN); + bit_offset += (bfAzPtWidth+1); + } + /* bfZePt */ + if (bfZePtWidth > 0) { + proto_tree_add_bits_item(extension_tree, hf_oran_bfZePt, tvb, bit_offset, bfZePtWidth+1, ENC_BIG_ENDIAN); + bit_offset += (bfZePtWidth+1); + } + /* bfAz3dd */ + if (bfAz3ddWidth > 0) { + proto_tree_add_bits_item(extension_tree, hf_oran_bfAz3dd, tvb, bit_offset, bfAz3ddWidth+1, ENC_BIG_ENDIAN); + bit_offset += (bfAz3ddWidth+1); + } + /* bfZe3dd */ + if (bfZe3ddWidth > 0) { + proto_tree_add_bits_item(extension_tree, hf_oran_bfZe3dd, tvb, bit_offset, bfZe3ddWidth+1, ENC_BIG_ENDIAN); + bit_offset += (bfZe3ddWidth+1); + } + + /* go to next byte (zero-padding.. - a little confusing..) */ + offset = (bit_offset+7) / 8; + + /* 2 reserved/padding bits */ + /* bfAzSl (3 bits) */ + proto_tree_add_item(extension_tree, hf_oran_bfAzSl, tvb, offset, 1, ENC_BIG_ENDIAN); + /* bfZeSl (3 bits) */ + proto_tree_add_item(extension_tree, hf_oran_bfZeSl, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + } + + case 4: /* Modulation compression params (5.4.7.4) */ + { + /* csf */ + proto_tree_add_bits_item(extension_tree, hf_oran_csf, tvb, offset*8, 1, ENC_BIG_ENDIAN); + /* modCompScaler */ + guint32 modCompScaler; + proto_item *ti = proto_tree_add_item_ret_uint(extension_tree, hf_oran_modcompscaler, + tvb, offset, 2, ENC_BIG_ENDIAN, &modCompScaler); + /* Work out and show floating point value too. */ + guint16 exponent = (modCompScaler >> 11) & 0x000f; /* m.s. 4 bits */ + guint16 mantissa = modCompScaler & 0x07ff; /* l.s. 11 bits */ + double value = (double)mantissa * (1.0 / (1 << exponent)); + proto_item_append_text(ti, " (%f)", value); + + offset += 2; + break; + } + + case 5: /* Modulation Compression Additional Parameters Extension Type (7.7.5) */ + { + /* Applies only to section types 1,3 and 5 */ + + /* There may be one or 2 entries, depending upon extlen */ + gint sets = 1, reserved_bits = 0; + switch (extlen) { + case 2: + sets = 1; + reserved_bits = 20; + break; + case 3: + sets = 2; + reserved_bits = 24; + break; + case 4: + /* sets can be 3 or 4, depending upon whether last 28 bits are 0.. */ + if ((tvb_get_ntohl(tvb, offset+10) & 0x0fffffff) == 0) { + sets = 3; + reserved_bits = 28; + } + else { + sets = 4; + reserved_bits = 0; + } + break; + + default: + /* Malformed error!!! */ + expert_add_info_format(pinfo, extlen_ti, &ei_oran_extlen_wrong, + "For section 5, extlen must be 2, 3 or 4, but %u was dissected", + extlen); + break; + } + + guint bit_offset = offset*8; + + for (gint n=0; n < sets; n++) { + /* Subtree for each set */ + guint set_start_offset = bit_offset/8; + proto_item *set_ti = proto_tree_add_string(extension_tree, hf_oran_modcomp_param_set, + tvb, set_start_offset, 0, ""); + proto_tree *set_tree = proto_item_add_subtree(set_ti, ett_oran_modcomp_param_set); + + guint64 mcScaleReMask, csf, mcScaleOffset; + + /* mcScaleReMask (12 bits) */ + proto_tree_add_bits_ret_val(set_tree, hf_oran_mc_scale_re_mask, tvb, bit_offset, 12, &mcScaleReMask, ENC_BIG_ENDIAN); + bit_offset += 12; + /* csf (1 bit) */ + proto_tree_add_bits_ret_val(set_tree, hf_oran_csf, tvb, bit_offset, 1, &csf, ENC_BIG_ENDIAN); + bit_offset += 1; + /* mcScaleOffset (15 bits) */ + proto_tree_add_bits_ret_val(set_tree, hf_oran_mc_scale_offset, tvb, bit_offset, 15, &mcScaleOffset, ENC_BIG_ENDIAN); + bit_offset += 15; + + /* Summary */ + proto_item_set_len(set_ti, (bit_offset+7)/8 - set_start_offset); + proto_item_append_text(set_ti, " (mcScaleReMask=%u csf=%s mcScaleOffset=%u)", + (guint)mcScaleReMask, tfs_get_true_false((gboolean)csf), (guint)mcScaleOffset); + } + + proto_item_append_text(extension_ti, " (%u sets)", sets); + + /* Reserved */ + if (reserved_bits) { + proto_tree_add_bits_item(extension_tree, hf_oran_reserved, tvb, bit_offset, reserved_bits, ENC_BIG_ENDIAN); + bit_offset += reserved_bits; + } + + offset = bit_offset/8; + break; + } + + case 6: /* Non-contiguous PRB allocation in time and frequency domain */ + { + /* Update ext6 recorded info */ + ext11_settings.ext6_set = TRUE; + + /* repetition */ + proto_tree_add_bits_item(extension_tree, hf_oran_repetition, tvb, offset*8, 1, ENC_BIG_ENDIAN); + /* rbgSize */ + guint32 rbgSize; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_rbgSize, tvb, offset, 1, ENC_BIG_ENDIAN, &rbgSize); + if (rbgSize == 0) { + expert_add_info_format(pinfo, extlen_ti, &ei_oran_rbg_size_reserved, + "rbgSize value of 0 is reserved"); + } + /* rbgMask (28 bits) */ + guint32 rbgMask; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_rbgMask, tvb, offset, 4, ENC_BIG_ENDIAN, &rbgMask); + offset += 4; + /* priority */ + proto_tree_add_item(extension_tree, hf_oran_noncontig_priority, tvb, offset, 1, ENC_BIG_ENDIAN); + /* symbolMask */ + proto_tree_add_item(extension_tree, hf_oran_symbolMask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* Look up rbg_size enum -> value */ + switch (rbgSize) { + case 0: + /* N.B. reserved, but covered above with expert info (would remain 0) */ + break; + case 1: + ext11_settings.ext6_rbg_size = 1; break; + case 2: + ext11_settings.ext6_rbg_size = 2; break; + case 3: + ext11_settings.ext6_rbg_size = 3; break; + case 4: + ext11_settings.ext6_rbg_size = 4; break; + case 5: + ext11_settings.ext6_rbg_size = 6; break; + case 6: + ext11_settings.ext6_rbg_size = 8; break; + case 7: + ext11_settings.ext6_rbg_size = 16; break; + /* N.B., encoded in 3 bits, so no other values are possible */ + } + /* Record which bits (and count) are set in rbgMask */ + for (guint n=0; n < 28 && ext11_settings.ext6_num_bits_set < 28; n++) { + if ((rbgMask >> n) & 0x01) { + ext11_settings.ext6_bits_set[ext11_settings.ext6_num_bits_set++] = n; + } + } + break; + } + + case 7: /* eAxC mask */ + proto_tree_add_item(extension_tree, hf_oran_eAxC_mask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + + case 8: /* Regularization factor */ + proto_tree_add_item(extension_tree, hf_oran_regularizationFactor, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + + case 9: /* Dynamic Spectrum Sharing parameters */ + proto_tree_add_item(extension_tree, hf_oran_technology, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bits_item(extension_tree, hf_oran_reserved, tvb, offset*8, 8, ENC_BIG_ENDIAN); + offset += 1; + break; + + case 10: /* Section description for group configuration of multiple ports */ + { + /* beamGroupType */ + guint32 beam_group_type = 0; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_beamGroupType, + tvb, offset, 1, ENC_BIG_ENDIAN, &beam_group_type); + proto_item_append_text(extension_ti, " (%s)", val_to_str_const(beam_group_type, beam_group_type_vals, "Unknown")); + + /* numPortc */ + guint32 numPortc; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_numPortc, + tvb, offset, 1, ENC_BIG_ENDIAN, &numPortc); + offset++; + + /* TODO: any generated fields or expert info should be added, due to enties in table 5-35 ? */ + + /* Will append all beamId values to extension_ti, regardless of beamGroupType */ + proto_item_append_text(extension_ti, "("); + guint n; + + switch (beam_group_type) { + case 0x0: /* common beam */ + /* Reserved byte */ + proto_tree_add_item(oran_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset++; + + /* All entries are beamId... */ + for (n=0; n < numPortc; n++) { + proto_item_append_text(extension_ti, "%u ", beamId); + } + break; + + case 0x1: /* beam matrix indication */ + /* Reserved byte */ + proto_tree_add_item(oran_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset++; + + /* Entries inc from beamId... */ + for (n=0; n < numPortc; n++) { + proto_item_append_text(extension_ti, "%u ", beamId+n); + } + break; + + case 0x2: /* beam vector listing */ + { + /* Beam listing vector case */ + /* Work out how many port beam entries there is room for */ + /* Using numPortC as visible in issue 18116 */ + proto_item_append_text(extension_ti, " (%u entries) ", numPortc); + for (n=0; n < numPortc; n++) { + /* TODO: Single reserved bit */ + + /* port beam ID (or UEID) */ + guint32 id; + proto_item *beamid_or_ueid_ti = proto_tree_add_item_ret_uint(oran_tree, hf_oran_beamId, + tvb, offset, 2, ENC_BIG_ENDIAN, &id); + proto_item_append_text(beamid_or_ueid_ti, " port #%u beam ID (or UEId) %u", n, id); + offset += 2; + + proto_item_append_text(extension_ti, "%u ", id); + } + break; + } + + default: + /* TODO: warning for unsupported/reserved value */ + break; + } + proto_item_append_text(extension_ti, ")"); + break; + } + + case 11: /* Flexible Weights Extension Type */ + { + gboolean disableBFWs; + guint32 numBundPrb; + + /* disableBFWs */ + proto_tree_add_item_ret_boolean(extension_tree, hf_oran_disable_bfws, + tvb, offset, 1, ENC_BIG_ENDIAN, &disableBFWs); + if (disableBFWs) { + proto_item_append_text(extension_ti, " (disableBFWs)"); + } + /* RAD */ + proto_tree_add_item(extension_tree, hf_oran_rad, + tvb, offset, 1, ENC_BIG_ENDIAN); + /* 6 reserved bits */ + proto_tree_add_item(extension_tree, hf_oran_ext11_reserved, tvb, + offset, 1, ENC_BIG_ENDIAN); + offset++; + + /* numBundPrb (number of prbs in each bundle) */ + proto_item *num_bund_prb_ti = proto_tree_add_item_ret_uint(extension_tree, hf_oran_num_bund_prbs, + tvb, offset, 1, ENC_BIG_ENDIAN, &numBundPrb); + offset++; + /* value zero is reserved.. */ + if (numBundPrb == 0) { + expert_add_info_format(pinfo, num_bund_prb_ti, &ei_oran_reserved_numBundPrb, + "Reserved value 0 for numBundPrb seen - not valid"); + } + + guint32 num_bundles; + gboolean orphaned_prbs = FALSE; + + if (!disableBFWs) { + /********************************************/ + /* Table 7.7.1.1-1 */ + /********************************************/ + + guint32 bfwcomphdr_iq_width, bfwcomphdr_comp_meth; + proto_item *comp_meth_ti = NULL; + + /* bfwCompHdr (2 subheaders - bfwIqWidth and bfwCompMeth)*/ + offset = dissect_bfwCompHdr(tvb, extension_tree, offset, + &bfwcomphdr_iq_width, &bfwcomphdr_comp_meth, &comp_meth_ti); + + /* Look up width of samples. */ + guint8 iq_width = !bfwcomphdr_iq_width ? 16 : bfwcomphdr_iq_width; + + + /* Work out number of bundles, but take care not to divide by zero. */ + if (numBundPrb == 0) { + break; + } + + /* Work out bundles! */ + ext11_work_out_bundles(startPrbc, numPrbc, numBundPrb, &ext11_settings); + num_bundles = ext11_settings.num_bundles; + + /* Add (complete) bundles */ + for (guint b=0; b < num_bundles; b++) { + + offset = dissect_bfw_bundle(tvb, extension_tree, pinfo, offset, + comp_meth_ti, bfwcomphdr_comp_meth, + iq_width, + b, /* bundle number */ + ext11_settings.bundles[b].start, + ext11_settings.bundles[b].end, + ext11_settings.bundles[b].is_orphan); + if (!offset) { + break; + } + } + if (num_bundles > 0) { + /* Set flag from last bundle entry */ + orphaned_prbs = ext11_settings.bundles[num_bundles-1].is_orphan; + } + } + else { + /********************************************/ + /* Table 7.7.1.1-2 */ + /* No weights in this case */ + /********************************************/ + + /* Work out number of bundles, but take care not to divide by zero. */ + if (numBundPrb == 0) { + break; + } + + ext11_work_out_bundles(startPrbc, numPrbc, numBundPrb, &ext11_settings); + num_bundles = ext11_settings.num_bundles; + + for (guint n=0; n < num_bundles; n++) { + /* beamId */ + proto_item *ti = proto_tree_add_item(extension_tree, hf_oran_beam_id, + tvb, offset, 2, ENC_BIG_ENDIAN); + if (!ext11_settings.bundles[n].is_orphan) { + proto_item_append_text(ti, " (Bundle %u)", n); + } + else { + orphaned_prbs = TRUE; + proto_item_append_text(ti, " (Orphaned PRBs)"); + } + offset += 2; + } + } + + /* Add summary to extension root */ + if (orphaned_prbs) { + proto_item_append_text(extension_ti, " (%u bundles + orphaned)", num_bundles); + } + else { + proto_item_append_text(extension_ti, " (%u bundles)", num_bundles); + } + } + + break; + + case 12: /* Non-Contiguous PRB Allocation with Frequency Ranges */ + { + ext11_settings.ext12_set = TRUE; + + /* priority */ + proto_tree_add_item(extension_tree, hf_oran_noncontig_priority, tvb, offset, 1, ENC_BIG_ENDIAN); + + /* symbolMask */ + proto_tree_add_item(extension_tree, hf_oran_symbolMask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* There are now 'R' pairs of (offStartPrb, numPrb) values. Fill extlen bytes with values. If last one is not set, + should be populated with 0s. */ + guint32 extlen_remaining_bytes = (extlen*4) - 4; + guint8 prb_index; + + for (prb_index = 1; extlen_remaining_bytes > 0; prb_index++) + { + /* Create a subtree for each pair */ + proto_item *pair_ti = proto_tree_add_string(extension_tree, hf_oran_off_start_prb_num_prb_pair, + tvb, offset, 2, ""); + proto_tree *pair_tree = proto_item_add_subtree(pair_ti, ett_oran_offset_start_prb_num_prb); + + /* offStartPrb */ + guint32 off_start_prb; + proto_tree_add_item_ret_uint(pair_tree, hf_oran_off_start_prb, tvb, offset, 1, ENC_BIG_ENDIAN, &off_start_prb); + offset++; + + /* numPrb */ + guint32 num_prb; + proto_tree_add_item_ret_uint(pair_tree, hf_oran_num_prb, tvb, offset, 1, ENC_BIG_ENDIAN, &num_prb); + offset++; + + extlen_remaining_bytes -= 2; + + /* Last pair may be 0,0 if not used. Check for this */ + if ((extlen_remaining_bytes == 0) && (off_start_prb == 0) && (num_prb == 0)) { + proto_item_append_text(pair_ti, " (not used)"); + } + /* Add summary to pair root item, and configure details in ext11_settings */ + else { + proto_item_append_text(pair_ti, "(%u) offStartPrb=%3u, numPrb=%u", + prb_index, off_start_prb, num_prb); + if (ext11_settings.ext12_num_pairs < MAX_BFW_EXT12_PAIRS) { + ext11_settings.ext12_pairs[ext11_settings.ext12_num_pairs].off_start_prb = off_start_prb; + ext11_settings.ext12_pairs[ext11_settings.ext12_num_pairs++].num_prb = num_prb; + } + } + } + break; + } + + case 13: /* PRB Allocation with Frequency Hopping */ + { + /* Will update settings for ext11 */ + ext11_settings.ext13_set = TRUE; + + guint32 extlen_remaining_bytes = (extlen*4) - 2; + guint8 allocation_index; + + guint prev_next_symbol_id = 0, prev_next_start_prbc = 0; + + for (allocation_index = 1; extlen_remaining_bytes > 0; allocation_index++) + { + /* Subtree for allocation */ + proto_item *allocation_ti = proto_tree_add_string(extension_tree, hf_oran_prb_allocation, + tvb, offset, 2, ""); + proto_tree *allocation_tree = proto_item_add_subtree(allocation_ti, ett_oran_prb_allocation); + + /* Reserved (2 bits) */ + proto_tree_add_item(allocation_tree, hf_oran_reserved_2bits, tvb, offset, 1, ENC_BIG_ENDIAN); + + /* nextSymbolId (4 bits) */ + guint32 next_symbol_id; + proto_tree_add_item_ret_uint(allocation_tree, hf_oran_nextSymbolId, tvb, offset, 1, ENC_BIG_ENDIAN, &next_symbol_id); + + /* nextStartPrbc (10 bits) */ + guint32 next_start_prbc; + proto_tree_add_item_ret_uint(allocation_tree, hf_oran_nextStartPrbc, tvb, offset, 2, ENC_BIG_ENDIAN, &next_start_prbc); + offset += 2; + + /* Add summary to allocation root item */ + proto_item_append_text(allocation_ti, "(%u) nextSymbolId=%3u, nextStartPrbc=%u", + allocation_index, next_symbol_id, next_start_prbc); + + /* Checking for duplicates (expected if e.g. had only 2 entries but extlen bytes still to fill */ + if ((allocation_index > 1) && (next_symbol_id == prev_next_symbol_id) && (next_start_prbc == prev_next_start_prbc)) { + proto_item_append_text(allocation_ti, " (repeated - to fill up extlen)"); + } + else { + /* Add entry for configuring ext11. don't store out of range */ + if (ext11_settings.ext13_num_start_prbs < MAX_BFW_EXT13_ALLOCATIONS) { + ext11_settings.ext13_start_prbs[ext11_settings.ext13_num_start_prbs++] = next_start_prbc; + } + } + prev_next_symbol_id = next_symbol_id; + prev_next_start_prbc = next_start_prbc; + + extlen_remaining_bytes -= 2; + } + break; + } + + case 14: /* Nulling-layer Info. for ueId-based beamforming */ + proto_tree_add_item(extension_tree, hf_oran_nullLayerInd, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bits_item(extension_tree, hf_oran_reserved, tvb, offset*8, 8, ENC_BIG_ENDIAN); + offset += 1; + break; + + case 15: /* Mixed-numerology Info. for ueId-based beamforming */ + /* frameStructure */ + proto_tree_add_item(extension_tree, hf_oran_frameStructure_fft, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(extension_tree, hf_oran_frameStructure_subcarrier_spacing, tvb, offset, 1, ENC_NA); + offset += 1; + /* freqOffset */ + proto_tree_add_item(extension_tree, hf_oran_freqOffset, tvb, offset, 3, ENC_BIG_ENDIAN); + offset += 3; + /* cpLength */ + proto_tree_add_item(extension_tree, hf_oran_cpLength, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + + case 16: /* Section description for antenna mapping in UE channel information based UL beamforming */ + { + guint32 extlen_remaining_bytes = (extlen*4) - 2; + guint num_ant_masks = extlen_remaining_bytes / 8; + for (guint n=0; n < num_ant_masks; n++) { + proto_item *ti = proto_tree_add_item(extension_tree, hf_oran_antMask, tvb, offset, 8, ENC_BIG_ENDIAN); + proto_item_append_text(ti, " (RX eAxC #%u)", n+1); + offset += 8; + } + break; + } + + case 17: /* Section description for indication of user port group */ + { + guint32 extlen_remaining_bytes = (extlen*4) - 2; + guint32 end_bit = (offset+extlen_remaining_bytes) * 8; + guint32 ueid_index = 1; + /* TODO: just filling up all available bytes - some may actually be padding.. */ + for (guint32 bit_offset=offset*8; bit_offset < end_bit; bit_offset+=4, ueid_index++) { + proto_item *ti = proto_tree_add_bits_item(extension_tree, hf_oran_num_ueid, tvb, bit_offset, 4, ENC_BIG_ENDIAN); + proto_item_append_text(ti, " (user #%u)", ueid_index); + } + break; + } + + case 18: /* Section description for Uplink Transmission Management */ + /* transmissionWindowOffset */ + proto_tree_add_item(extension_tree, hf_oran_transmissionWindowOffset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* reserved (2 bits) */ + proto_tree_add_item(extension_tree, hf_oran_reserved_2bits, tvb, offset, 1, ENC_BIG_ENDIAN); + /* transmissionWindowSize (14 bits) */ + proto_tree_add_item(extension_tree, hf_oran_transmissionWindowSize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* reserved (6 bits) */ + proto_tree_add_item(extension_tree, hf_oran_reserved_6bits, tvb, offset, 1, ENC_BIG_ENDIAN); + /* toT (2 bits) */ + proto_tree_add_item(extension_tree, hf_oran_toT, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + break; + + case 19: /* Compact beamforming information for multiple port */ + { + /* beamId in section header should be ignored */ + if (beamId_ti && !beamId_ignored) { + proto_item_append_text(beamId_ti, " (ignored)"); + beamId_ignored = TRUE; + } + + /* disableBFWs */ + gboolean disableBFWs; + proto_tree_add_item_ret_boolean(extension_tree, hf_oran_disable_bfws, + tvb, offset, 1, ENC_BIG_ENDIAN, &disableBFWs); + if (disableBFWs) { + proto_item_append_text(extension_ti, " (disableBFWs)"); + } + /* Repetition */ + proto_tree_add_bits_item(extension_tree, hf_oran_repetition, tvb, (offset*8)+1, 1, ENC_BIG_ENDIAN); + /* numPortc */ + guint32 numPortc; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_numPortc, + tvb, offset, 1, ENC_BIG_ENDIAN, &numPortc); + offset++; + + /* priority */ + proto_tree_add_item(extension_tree, hf_oran_noncontig_priority, tvb, offset, 1, ENC_BIG_ENDIAN); + /* symbolMask */ + proto_tree_add_item(extension_tree, hf_oran_symbolMask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* bfwCompHdr */ + guint32 bfwcomphdr_iq_width, bfwcomphdr_comp_meth; + proto_item *comp_meth_ti = NULL; + offset = dissect_bfwCompHdr(tvb, extension_tree, offset, + &bfwcomphdr_iq_width, &bfwcomphdr_comp_meth, &comp_meth_ti); + + /* Add entries for each port */ + for (guint port=0; port < numPortc; port++) { + + /* Create subtree for port entry*/ + gint port_start_offset = offset; + proto_item *port_ti = proto_tree_add_string_format(extension_tree, hf_oran_ext19_port, + tvb, offset, 0, + "", "Port %u: ", port); + proto_tree *port_tree = proto_item_add_subtree(port_ti, ett_oran_ext19_port); + + + + /* Reserved (4 bits) */ + proto_tree_add_item(port_tree, hf_oran_reserved_4bits, tvb, offset, 1, ENC_BIG_ENDIAN); + /* portReMask (12 bits) */ + proto_tree_add_item(port_tree, hf_oran_portReMask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* Reserved (2 bits) */ + proto_tree_add_item(port_tree, hf_oran_reserved_2bits, tvb, offset, 1, ENC_BIG_ENDIAN); + /* portSymbolMask (14 bits) */ + proto_tree_add_item(port_tree, hf_oran_portSymbolMask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* Reserved (1 bit) */ + proto_tree_add_item(port_tree, hf_oran_reserved_1bit, tvb, offset, 1, ENC_BIG_ENDIAN); + /* beamID (15 bits) */ + proto_tree_add_item_ret_uint(port_tree, hf_oran_beamId, tvb, offset, 2, ENC_BIG_ENDIAN, &beamId); + proto_item_append_text(port_ti, " (beamId=%u)", beamId); + offset += 2; + + /* bfwCompParam (TODO: present in disableBFWs case?) */ + gboolean compression_method_supported = FALSE; + guint32 exponent = 0; + offset = dissect_bfwCompParam(tvb, port_tree, pinfo, offset, comp_meth_ti, + bfwcomphdr_comp_meth, &exponent, &compression_method_supported); + + + if (!disableBFWs) { + /*****************************************************************/ + /* Table 7.7.19.1-1 (there is no part 2 for disableBFWs case...) */ + /*****************************************************************/ + + /* Look up width of samples. */ + guint8 iq_width = !bfwcomphdr_iq_width ? 16 : bfwcomphdr_iq_width; + + gint bit_offset = offset*8; + gint bfw_offset; + + /* Add weights for each TRX */ + for (guint b=0; b < pref_num_bf_antennas; b++) { + + /* Create BFW subtree */ + bfw_offset = bit_offset / 8; + guint8 bfw_extent = ((bit_offset + (iq_width*2)) / 8) - bfw_offset; + proto_item *bfw_ti = proto_tree_add_string_format(port_tree, hf_oran_bfw, + tvb, bfw_offset, bfw_extent, + "", "TRX %u: (", b); + proto_tree *bfw_tree = proto_item_add_subtree(bfw_ti, ett_oran_bfw); + + /* I */ + /* Get bits, and convert to float. */ + guint32 bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + gfloat value = decompress_value(bits, bfwcomphdr_comp_meth, iq_width, exponent); + /* Add to tree. */ + proto_tree_add_float_format_value(bfw_tree, hf_oran_bfw_i, tvb, bit_offset/8, (iq_width+7)/8, value, "#%u=%f", b, value); + bit_offset += iq_width; + proto_item_append_text(bfw_ti, "I%u=%f ", b, value); + + /* Q */ + /* Get bits, and convert to float. */ + bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + value = decompress_value(bits, bfwcomphdr_comp_meth, iq_width, exponent); + /* Add to tree. */ + proto_tree_add_float_format_value(bfw_tree, hf_oran_bfw_q, tvb, bit_offset/8, (iq_width+7)/8, value, "#%u=%f", b, value); + bit_offset += iq_width; + proto_item_append_text(bfw_ti, "Q%u=%f)", b, value); + } + + offset = (bit_offset+7)/8; + } + else { + /* No weights... */ + + /* Reserved (1 bit) */ + proto_tree_add_bits_item(extension_tree, hf_oran_reserved, tvb, offset*8, 1, ENC_BIG_ENDIAN); + /* beamID (15 bits) */ + proto_tree_add_item_ret_uint(extension_tree, hf_oran_beamId, tvb, offset, 2, ENC_BIG_ENDIAN, &beamId); + proto_item_append_text(port_ti, " (beamId=%u)", beamId); + offset += 2; + } + + /* Set length of this port entry */ + proto_item_set_len(port_ti, offset-port_start_offset); + } + break; + } + + case 20: /* Puncturing extension */ + { + /* numPuncPatterns */ + guint32 numPuncPatterns; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_numPuncPatterns, tvb, offset, 1, ENC_BIG_ENDIAN, &numPuncPatterns); + offset += 1; + + /* Add each puncturing pattern */ + for (guint32 n=0; n < numPuncPatterns; n++) { + guint pattern_start_offset = offset; + + /* Subtree for this puncturing pattern */ + proto_item *pattern_ti = proto_tree_add_string_format(extension_tree, hf_oran_puncPattern, + tvb, offset, 0, + "", "Puncturing Pattern: %u/%u", n+1, hf_oran_numPuncPatterns); + proto_tree *pattern_tree = proto_item_add_subtree(pattern_ti, ett_oran_punc_pattern); + + /* SymbolMask (14 bits) */ + proto_tree_add_item(pattern_tree, hf_oran_symbolMask_ext20, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 1; + /* startPuncPrb (10 bits) */ + proto_tree_add_item(pattern_tree, hf_oran_startPuncPrb, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 2; + /* numPuncPrb (8 bits) */ + proto_tree_add_item(pattern_tree, hf_oran_numPuncPrb, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* puncReMask (12 bits) */ + proto_tree_add_item(pattern_tree, hf_oran_puncReMask, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 1; + /* rb (1 bit) */ + proto_tree_add_item(pattern_tree, hf_oran_rb, tvb, offset, 1, ENC_BIG_ENDIAN); + /* reserved (2 bits? - spec says 1) */ + proto_tree_add_bits_item(pattern_tree, hf_oran_reserved, tvb, offset*8, 2, ENC_BIG_ENDIAN); + /* rbgIncl */ + gboolean rbgIncl; + proto_tree_add_item_ret_boolean(pattern_tree, hf_oran_RbgIncl, tvb, offset, 1, ENC_BIG_ENDIAN, &rbgIncl); + offset += 1; + + if (rbgIncl) { + /* reserved (1 bit) */ + proto_tree_add_item(pattern_tree, hf_oran_reserved_1bit, tvb, offset, 1, ENC_BIG_ENDIAN); + /* rbgSize(3 bits) */ + proto_tree_add_item(pattern_tree, hf_oran_rbgSize, tvb, offset, 1, ENC_BIG_ENDIAN); + /* rbgMask (28 bits) */ + proto_tree_add_item(pattern_tree, hf_oran_rbgMask, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + } + + proto_item_set_len(pattern_ti, offset-pattern_start_offset); + } + + break; + } + case 21: /* Variable PRB group size for channel information */ + /* ciPrbGroupSize */ + proto_tree_add_item(extension_tree, hf_oran_ci_prb_group_size, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* reserved (8 bits) */ + proto_tree_add_bits_item(extension_tree, hf_oran_reserved, tvb, offset*8, 8, ENC_BIG_ENDIAN); + offset += 1; + break; + + case 22: /* ACK/NACK request */ + proto_tree_add_item(extension_tree, hf_oran_ack_nack_req_id, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + + default: + /* Other/unexpected extension types. */ + break; + } + + /* Check offset compared with extlen. There should be 0-3 bytes of padding */ + gint num_padding_bytes = (extension_start_offset + (extlen*4) - offset); + if ((num_padding_bytes<0) || (num_padding_bytes>3)) { + expert_add_info_format(pinfo, extlen_ti, &ei_oran_extlen_wrong, + "extlen signalled %u bytes (+ 0-3 bytes padding), but %u were dissected", + extlen*4, offset-extension_start_offset); + } + + /* Move offset to beyond signalled length of extension */ + offset = extension_start_offset + (extlen*4); + + /* Set length of extension header. */ + proto_item_set_len(extension_ti, extlen*4); + } + + /* Set extent of overall section */ + proto_item_set_len(sectionHeading, offset); + + return offset; +} + +/* Dissect udCompHdr (user data compression header, 7.5.2.10) */ +/* bit_width and comp_meth are out params */ +static int dissect_udcomphdr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, + guint *bit_width, guint *comp_meth) +{ + /* Subtree */ + proto_item *udcomphdr_ti = proto_tree_add_string_format(tree, hf_oran_udCompHdr, + tvb, offset, 1, "", + "udCompHdr"); + proto_tree *udcomphdr_tree = proto_item_add_subtree(udcomphdr_ti, ett_oran_udcomphdr); + + /* udIqWidth */ + guint32 hdr_iq_width; + proto_item *iq_width_item = proto_tree_add_item_ret_uint(udcomphdr_tree, hf_oran_udCompHdrIqWidth , tvb, offset, 1, ENC_NA, &hdr_iq_width); + *bit_width = (hdr_iq_width) ? hdr_iq_width : 16; + proto_item_append_text(iq_width_item, " (%u bits)", *bit_width); + + /* udCompMeth */ + guint32 ud_comp_meth; + proto_tree_add_item_ret_uint(udcomphdr_tree, hf_oran_udCompHdrMeth, tvb, offset, 1, ENC_NA, &ud_comp_meth); + if (comp_meth) { + *comp_meth = ud_comp_meth; + } + offset += 1; + + /* Summary */ + proto_item_append_text(udcomphdr_ti, " (IqWidth=%u, udCompMeth=%s)", + *bit_width, rval_to_str_const(ud_comp_meth, ud_comp_header_meth, "Unknown")); + return offset; +} + + +/* Control plane dissector (section 7). */ +static int dissect_oran_c(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + guint offset = 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "O-RAN-FH-C"); + col_set_str(pinfo->cinfo, COL_INFO, "C-Plane"); + + /* Create display subtree for the protocol */ + proto_item *protocol_item = proto_tree_add_item(tree, proto_oran, tvb, 0, -1, ENC_NA); + proto_item_append_text(protocol_item, "-C"); + proto_tree *oran_tree = proto_item_add_subtree(protocol_item, ett_oran); + + guint16 eAxC; + addPcOrRtcid(tvb, oran_tree, &offset, "ecpriRtcid", &eAxC); + + if (!PINFO_FD_VISITED(pinfo)) { + /* TODO: create or update conversation for stream eAxC */ + } + else { + /* TODO: show stored state for this stream */ + } + + /* Message identifier */ + addSeqid(tvb, oran_tree, &offset); + + proto_item *sectionHeading; + + /* section subtree */ + gint section_tree_offset = offset; + proto_tree *section_tree = proto_tree_add_subtree(oran_tree, tvb, offset, 2, ett_oran_section_type, §ionHeading, "C-Plane Section Type "); + + /* dataDirection */ + guint32 direction = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_data_direction, tvb, offset, 1, ENC_NA, &direction); + /* payloadVersion */ + proto_tree_add_item(section_tree, hf_oran_payload_version, tvb, offset, 1, ENC_NA); + /* payloadVersion */ + proto_tree_add_item(section_tree, hf_oran_filter_index, tvb, offset, 1, ENC_NA); + offset += 1; + + guint ref_a_offset = 0; + /* frameId */ + guint32 frameId = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_frame_id, tvb, offset, 1, ENC_NA, &frameId); + offset += 1; + + /* subframeId */ + guint32 subframeId = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_subframe_id, tvb, offset, 1, ENC_NA, &subframeId); + /* slotId */ + guint32 slotId = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_slot_id, tvb, offset, 2, ENC_BIG_ENDIAN, &slotId); + offset++; + /* startSymbolId */ + guint32 startSymbolId = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_start_symbol_id, tvb, offset, 1, ENC_NA, &startSymbolId); + offset++; + + char id[16]; + snprintf(id, 16, "%d-%d-%d", frameId, subframeId, slotId); + proto_item *pi = proto_tree_add_string(section_tree, hf_oran_refa, tvb, ref_a_offset, 3, id); + proto_item_set_generated(pi); + + /* numberOfSections */ + guint32 nSections = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_numberOfSections, tvb, offset, 1, ENC_NA, &nSections); + offset += 1; + + /* sectionType */ + guint32 sectionType = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_sectionType, tvb, offset, 1, ENC_NA, §ionType); + offset += 1; + + /* Section-specific fields (white entries in Section Type diagrams) */ + guint bit_width = 0; + + guint32 scs, slots_per_subframe; + guint32 num_ues = 0; + proto_item *ti; + + switch (sectionType) { + case SEC_C_UNUSED_RB: /* Section Type "0" */ + /* timeOffset */ + proto_tree_add_item(section_tree, hf_oran_timeOffset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* frameStructure */ + proto_tree_add_item(section_tree, hf_oran_frameStructure_fft, tvb, offset, 1, ENC_NA); + proto_tree_add_item_ret_uint(section_tree, hf_oran_frameStructure_subcarrier_spacing, tvb, offset, 1, ENC_NA, &scs); + /* slots_per_subframe = 1 << scs; */ + offset += 1; + + /* cpLength */ + proto_tree_add_item(section_tree, hf_oran_cpLength, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* reserved */ + proto_tree_add_item(section_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + break; + + case SEC_C_NORMAL: /* Section Type "1" */ + case SEC_C_UE_SCHED: /* Section Type "5" */ + /* udCompHdr */ + offset = dissect_udcomphdr(tvb, pinfo, section_tree, offset, &bit_width, NULL); + /* reserved */ + proto_tree_add_item(section_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + break; + + case SEC_C_PRACH: /* Section Type "3" */ + /* timeOffset */ + proto_tree_add_item(section_tree, hf_oran_timeOffset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* frameStructure */ + proto_tree_add_item(section_tree, hf_oran_frameStructure_fft, tvb, offset, 1, ENC_NA); + proto_tree_add_item_ret_uint(section_tree, hf_oran_frameStructure_subcarrier_spacing, tvb, offset, 1, ENC_NA, &scs); + slots_per_subframe = 1 << scs; + ti = proto_tree_add_uint(section_tree, hf_oran_slot_within_frame, tvb, 0, 0, (slots_per_subframe*subframeId) + slotId); + proto_item_set_generated(ti); + offset += 1; + /* cpLength */ + proto_tree_add_item(section_tree, hf_oran_cpLength, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* udCompHdr */ + offset = dissect_udcomphdr(tvb, pinfo, section_tree, offset, &bit_width, NULL); + break; + + case SEC_C_CH_INFO: + /* numberOfUEs */ + proto_tree_add_item_ret_uint(section_tree, hf_oran_numberOfUEs, tvb, offset, 1, ENC_NA, &num_ues); + offset += 1; + /* reserved */ + proto_tree_add_item(section_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + + /* Number of sections may not be filled in, so set to the number of UEs */ + if (nSections == 0) { + nSections = num_ues; + } + break; + + case SEC_C_RSVD2: + case SEC_C_LAA: + /* TODO: */ + break; + }; + + /* Set actual length of section. */ + proto_item_set_len(section_tree, offset - section_tree_offset); + + proto_item_append_text(sectionHeading, "%d, %s, Frame: %d, Subframe: %d, Slot: %d, StartSymbol: %d", + sectionType, val_to_str_const(direction, data_direction_vals, "Unknown"), + frameId, subframeId, slotId, startSymbolId); + write_pdu_label_and_info(protocol_item, NULL, pinfo, ", Type: %d %s", sectionType, + rval_to_str_const(sectionType, section_types_short, "Unknown")); + + /* Dissect each C section */ + for (guint32 i = 0; i < nSections; ++i) { + tvbuff_t *section_tvb = tvb_new_subset_length_caplen(tvb, offset, -1, -1); + offset += dissect_oran_c_section(section_tvb, oran_tree, pinfo, sectionType, protocol_item); + } + + /* Expert error if we are short of tvb by > 3 bytes */ + if (tvb_reported_length_remaining(tvb, offset) > 3) { + expert_add_info_format(pinfo, protocol_item, &ei_oran_frame_length, + "%u bytes remain at end of frame - should be 0-3", + tvb_reported_length_remaining(tvb, offset)); + } + + return tvb_captured_length(tvb); +} + +/* User plane dissector (section 8) */ +static int +dissect_oran_u(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + /* Set up structures needed to add the protocol subtree and manage it */ + gint offset = 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "O-RAN-FH-U"); + col_set_str(pinfo->cinfo, COL_INFO, "U-Plane"); + + /* create display subtree for the protocol */ + proto_item *protocol_item = proto_tree_add_item(tree, proto_oran, tvb, 0, -1, ENC_NA); + proto_item_append_text(protocol_item, "-U"); + proto_tree *oran_tree = proto_item_add_subtree(protocol_item, ett_oran); + + /* Transport header */ + /* Real-time control data / IQ data transfer message series identifier */ + guint16 eAxC; + addPcOrRtcid(tvb, oran_tree, &offset, "ecpriPcid", &eAxC); + + if (!PINFO_FD_VISITED(pinfo)) { + /* TODO: create or update conversation for stream eAxC */ + } + else { + /* TODO: show stored state for this stream */ + } + + /* Message identifier */ + addSeqid(tvb, oran_tree, &offset); + + /* Common header for time reference */ + proto_item *timingHeader; + proto_tree *timing_header_tree = proto_tree_add_subtree(oran_tree, tvb, offset, 4, ett_oran_u_timing, &timingHeader, "Timing header"); + + /* dataDirection */ + guint32 direction; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_data_direction, tvb, offset, 1, ENC_NA, &direction); + /* payloadVersion */ + proto_tree_add_item(timing_header_tree, hf_oran_payload_version, tvb, offset, 1, ENC_NA); + /* filterIndex */ + proto_tree_add_item(timing_header_tree, hf_oran_filter_index, tvb, offset, 1, ENC_NA); + offset += 1; + + gint ref_a_offset = offset; + + /* frameId */ + guint32 frameId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_frame_id, tvb, offset, 1, ENC_NA, &frameId); + offset += 1; + + /* subframeId */ + guint32 subframeId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_subframe_id, tvb, offset, 1, ENC_NA, &subframeId); + /* slotId */ + guint32 slotId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_slot_id, tvb, offset, 2, ENC_BIG_ENDIAN, &slotId); + offset++; + /* symbolId */ + guint32 symbolId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_symbolId, tvb, offset, 1, ENC_NA, &symbolId); + offset++; + + char id[16]; + snprintf(id, 16, "%d-%d-%d", frameId, subframeId, slotId); + proto_item *pi = proto_tree_add_string(timing_header_tree, hf_oran_refa, tvb, ref_a_offset, 3, id); + proto_item_set_generated(pi); + + proto_item_append_text(timingHeader, " %s, Frame: %d, Subframe: %d, Slot: %d, Symbol: %d", + val_to_str_const(direction, data_direction_vals, "Unknown"), frameId, subframeId, slotId, symbolId); + + guint sample_bit_width; + gint compression; + gboolean includeUdCompHeader; + + if (direction == DIR_UPLINK) { + sample_bit_width = pref_sample_bit_width_uplink; + compression = pref_iqCompressionUplink; + includeUdCompHeader = pref_includeUdCompHeaderUplink; + } else { + sample_bit_width = pref_sample_bit_width_downlink; + compression = pref_iqCompressionDownlink; + includeUdCompHeader = pref_includeUdCompHeaderDownlink; + } + + /* Need a valid value (e.g. 9, 14). 0 definitely won't work, as won't progress around loop! */ + if (sample_bit_width == 0) { + expert_add_info_format(pinfo, protocol_item, &ei_oran_invalid_sample_bit_width, + "%cL Sample bit width from preference (%u) not valid, so can't decode sections", + (direction == DIR_UPLINK) ? 'U' : 'D', sample_bit_width); + return offset; + } + + guint bytesLeft; + + guint number_of_sections = 0; + guint nBytesPerPrb; + + do { + proto_item *sectionHeading; + proto_tree *section_tree = proto_tree_add_subtree(oran_tree, tvb, offset, 2, ett_oran_u_section, §ionHeading, "Section"); + + /* Section Header fields (darker green part) */ + + /* sectionId */ + guint32 sectionId = 0; + proto_item *ti = proto_tree_add_item_ret_uint(section_tree, hf_oran_section_id, tvb, offset, 2, ENC_BIG_ENDIAN, §ionId); + if (sectionId == 4095) { + proto_item_append_text(ti, " (not default coupling C/U planes using sectionId)"); + } + offset++; + /* rb */ + guint32 rb; + proto_tree_add_item_ret_uint(section_tree, hf_oran_rb, tvb, offset, 1, ENC_NA, &rb); + /* symInc */ + proto_tree_add_item(section_tree, hf_oran_symInc, tvb, offset, 1, ENC_NA); + /* startPrbu */ + guint32 startPrbu = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_startPrbu, tvb, offset, 2, ENC_BIG_ENDIAN, &startPrbu); + offset += 2; + + /* numPrbu */ + guint32 numPrbu = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_numPrbu, tvb, offset, 1, ENC_NA, &numPrbu); + offset += 1; + + if (includeUdCompHeader) { + /* 5.4.4.10. Described in 6.3.3.13 */ + /* Extract these values to inform how wide IQ samples in each PRB will be. */ + offset = dissect_udcomphdr(tvb, pinfo, section_tree, offset, &sample_bit_width, &compression); + + /* Not part of udCompHdr */ + proto_tree_add_item(section_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + } + else { + /* Showing comp values from prefs */ + /* iqWidth */ + proto_item *iq_width_item = proto_tree_add_uint(section_tree, hf_oran_udCompHdrIqWidth_pref, tvb, 0, 0, sample_bit_width); + proto_item_append_text(iq_width_item, " (from preferences)"); + proto_item_set_generated(iq_width_item); + + /* udCompMethod */ + proto_item *ud_comp_meth_item = proto_tree_add_uint(section_tree, hf_oran_udCompHdrMeth_pref, tvb, 0, 0, compression); + proto_item_append_text(ud_comp_meth_item, " (from preferences)"); + proto_item_set_generated(ud_comp_meth_item); + } + + /* Work this out each time, as udCompHdr may have changed things */ + guint nBytesForSamples = (sample_bit_width * 12 * 2) / 8; + nBytesPerPrb = nBytesForSamples; + if ((compression != COMP_NONE) && (compression != COMP_MODULATION)) { + nBytesPerPrb++; /* 1 extra byte reserved/exponent */ + } + + + write_section_info(sectionHeading, pinfo, protocol_item, sectionId, startPrbu, numPrbu, rb); + + /* TODO: should this use the same pref as c-plane? */ + if (numPrbu == 0) { + /* Special case for all PRBs (NR: the total number of PRBs may be > 255) */ + numPrbu = pref_data_plane_section_total_rbs; + startPrbu = 0; /* may already be 0... */ + } + + for (guint i = 0; i < numPrbu; i++) { + /* Create subtree */ + proto_item *prbHeading = proto_tree_add_string_format(section_tree, hf_oran_samples_prb, + tvb, offset, nBytesPerPrb, + "", "PRB"); + proto_tree *rb_tree = proto_item_add_subtree(prbHeading, ett_oran_u_prb); + guint32 exponent = 0; + if ((compression != COMP_NONE) && (compression != COMP_MODULATION)) { + proto_tree_add_item(rb_tree, hf_oran_reserved_4bits, tvb, offset, 1, ENC_NA); + proto_tree_add_item_ret_uint(rb_tree, hf_oran_exponent, tvb, offset, 1, ENC_BIG_ENDIAN, &exponent); + offset += 1; + } + /* Show PRB number in root */ + proto_item_append_text(prbHeading, " %u", startPrbu + i*(1+rb)); + + + proto_tree_add_item(rb_tree, hf_oran_iq_user_data, tvb, offset, nBytesForSamples, ENC_NA); + + if (pref_showIQSampleValues) { + /* Individual values */ + guint samples_offset = offset*8; + guint sample_number = 0; + for (guint n = 0; n<12; n++) { + /* I */ + guint i_bits = tvb_get_bits(tvb, samples_offset, sample_bit_width, ENC_BIG_ENDIAN); + gfloat i_value = decompress_value(i_bits, COMP_BLOCK_FP, sample_bit_width, exponent); + guint sample_len_in_bytes = ((samples_offset%8)+sample_bit_width+7)/8; + proto_item *i_ti = proto_tree_add_float(rb_tree, hf_oran_iSample, tvb, samples_offset/8, sample_len_in_bytes, i_value); + proto_item_set_text(i_ti, "iSample: %0.12f 0x%04x (iSample-%u in the PRB)", i_value, i_bits, sample_number); + samples_offset += sample_bit_width; + /* Q */ + guint q_bits = tvb_get_bits(tvb, samples_offset, sample_bit_width, ENC_BIG_ENDIAN); + gfloat q_value = decompress_value(q_bits, COMP_BLOCK_FP, sample_bit_width, exponent); + sample_len_in_bytes = ((samples_offset%8)+sample_bit_width+7)/8; + proto_item *q_ti = proto_tree_add_float(rb_tree, hf_oran_qSample, tvb, samples_offset/8, sample_len_in_bytes, q_value); + proto_item_set_text(q_ti, "qSample: %0.12f 0x%04x (qSample-%u in the PRB)", q_value, q_bits, sample_number); + samples_offset += sample_bit_width; + + sample_number++; + } + proto_item_append_text(prbHeading, " (%u samples)", sample_number); + } + + offset += nBytesForSamples; + + proto_item_set_len(sectionHeading, nBytesPerPrb * numPrbu + 4); /* 4 bytes for section header */ + } + bytesLeft = tvb_captured_length(tvb) - offset; + number_of_sections++; + } while (bytesLeft >= (4 + nBytesPerPrb)); /* FIXME: bad heuristic */ + + /* Show number of sections found */ + proto_item *ti = proto_tree_add_uint(oran_tree, hf_oran_numberOfSections, tvb, 0, 0, number_of_sections); + proto_item_set_generated(ti); + + /* Expert error if we are short of tvb by > 3 bytes */ + if (tvb_reported_length_remaining(tvb, offset) > 3) { + expert_add_info_format(pinfo, protocol_item, &ei_oran_frame_length, + "%u bytes remain at end of frame - should be 0-3", + tvb_reported_length_remaining(tvb, offset)); + } + + return tvb_captured_length(tvb); +} + + +/*****************************/ +/* Main dissection function. */ +/* N.B. ecpri message type passed in as 'data' arg by eCPRI dissector */ +static int +dissect_oran(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + guint32 ecpri_message_type = *(guint32 *)data; + + switch (ecpri_message_type) { + case ECPRI_MT_IQ_DATA: + return dissect_oran_u(tvb, pinfo, tree, data); + case ECPRI_MT_RT_CTRL_DATA: + return dissect_oran_c(tvb, pinfo, tree, data); + + default: + /* Not dissecting other types - assume these are handled by eCPRI dissector */ + return 0; + } +} + + +/* Register the protocol with Wireshark. */ +void +proto_register_oran(void) +{ + static hf_register_info hf[] = { + + /* Section 3.1.3.1.6 */ + { &hf_oran_du_port_id, + { "DU Port ID", "oran_fh_cus.du_port_id", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "Width set in dissector preference", HFILL } + }, + + /* Section 3.1.3.1.6 */ + { &hf_oran_bandsector_id, + { "BandSector ID", "oran_fh_cus.bandsector_id", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "Width set in dissector preference", HFILL } + }, + + /* Section 3.1.3.1.6 */ + { &hf_oran_cc_id, + { "CC ID", "oran_fh_cus.cc_id", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "Width set in dissector preference", HFILL } + }, + + /* Section 3.1.3.1.6 */ + { &hf_oran_ru_port_id, + { "RU Port ID", "oran_fh_cus.ru_port_id", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "Width set in dissector preference", HFILL } + }, + + /* Section 3.1.3.1.7 */ + { &hf_oran_sequence_id, + { "Sequence ID", "oran_fh_cus.sequence_id", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "The Sequence ID wraps around individually per c_eAxC", + HFILL } + }, + + /* Section 3.1.3.1.7 */ + { &hf_oran_e_bit, + { "E Bit", "oran_fh_cus.e_bit", + FT_UINT8, BASE_DEC, + VALS(e_bit), 0x80, + "One bit (the \"E-bit\") is reserved to indicate the last message of a subsequence", + HFILL } + }, + + /* Section 3.1.3.1.7 */ + { &hf_oran_subsequence_id, + { "Subsequence ID", "oran_fh_cus.subsequence_id", + FT_UINT8, BASE_DEC, + NULL, 0x7f, + "The subsequence identifier", + HFILL } + }, + + /* Section 5.4.4.1 */ + { &hf_oran_data_direction, + { "Data Direction", "oran_fh_cus.data_direction", + FT_UINT8, BASE_DEC, + VALS(data_direction_vals), 0x80, + "The gNB data direction", + HFILL } + }, + + /* Section 5.4.4.2 */ + { &hf_oran_payload_version, + {"Payload Version", "oran_fh_cus.payloadVersion", + FT_UINT8, BASE_DEC, + NULL, 0x70, + "Payload protocol version valid for the " + "following IEs in the application layer. In this version of the " + "specification payloadVersion=001b shall be used", + HFILL} + }, + + /* Section 5.4.4.3 */ + {&hf_oran_filter_index, + {"Filter Index", "oran_fh_cus.filterIndex", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(filter_indices), 0x0f, + "An index to the channel filter to be used " + "between IQ data and air interface, both in DL and UL. For most " + "physical channels filterIndex =0000b is used which indexes the " + "standard channel filter, e.g. 100MHz channel filter for 100MHz " + "nominal carrier bandwidth. Another use case is PRACH in UL, where " + "different filter indices can be used for different PRACH formats, " + "assuming that before FFT processing of PRACH data there is a " + "separate PRACH filter or PRACH filter in addition to the standard " + "channel filter in UL. Please note that for PRACH there is typically " + "also a frequency offset (see freqOffset) applied before the " + "PRACH filter. NOTE: Filter index is commanded from lls-CU to RU. " + "Likewise, it is not mandatory to command special filters, and " + "filter index = 0000b is also allowed for PRACH", + HFILL} + }, + + /* Section 5.4.4.4 */ + {&hf_oran_frame_id, + {"Frame ID", "oran_fh_cus.frameId", + FT_UINT8, BASE_DEC, + NULL, 0x00, + "A counter for 10 ms frames (wrapping period 2.56 seconds)", + HFILL} + }, + + /* Section 5.4.4.5 */ + {&hf_oran_subframe_id, + {"Subframe ID", "oran_fh_cus.subframe_id", + FT_UINT8, BASE_DEC, + NULL, 0xf0, + "A counter for 1 ms sub-frames within 10ms frame", + HFILL} + }, + + /* Section 5.4.4.6 */ + {&hf_oran_slot_id, + {"Slot ID", "oran_fh_cus.slotId", + FT_UINT16, BASE_DEC, + NULL, 0x0fc0, + "Slot number within a 1ms sub-frame. All slots " + "in one sub-frame are counted by this parameter, slotId running " + "from 0 to Nslot-1. In this version of the specification the " + "maximum Nslot=16, All other values of the 6 bits are reserved for " + "future use", + HFILL} + }, + + /* Section 5.4.4.6 */ + {&hf_oran_slot_within_frame, + {"Slot within frame", "oran_fh_cus.slot-within-frame", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "Slot within frame, to match DT logs", + HFILL} + }, + + /* Section 5.4.4.7 */ + {&hf_oran_start_symbol_id, + {"Start Symbol ID", "oran_fh_cus.startSymbolId", + FT_UINT8, BASE_DEC, + NULL, 0x3f, + "The first symbol number within slot, to " + "which the information of this message is applies", + HFILL} + }, + + /* Section 5.4.4.8 */ + {&hf_oran_numberOfSections, + {"Number of Sections", "oran_fh_cus.numberOfSections", + FT_UINT8, BASE_DEC, + NULL, 0x00, + "The number of section IDs included in this C-Plane message", + HFILL} + }, + + /* Section 5.4.4.9 */ + {&hf_oran_sectionType, + {"Section Type", "oran_fh_cus.sectionType", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(section_types), 0x00, + "Determines the characteristics of U-plane data to " + "be transferred or received from a beam with one pattern id", + HFILL} + }, + + /* Section 5.4.4.10 */ + {&hf_oran_udCompHdr, + {"udCompHdr", "oran_fh_cus.udCompHdr", + FT_STRING, BASE_NONE, + NULL, 0x00, + NULL, + HFILL} + }, + + /* Section 5.4.4.11 */ + {&hf_oran_numberOfUEs, + {"Number Of UEs", "oran_fh_cus.numberOfUEs", + FT_UINT8, BASE_DEC, + NULL, 0x00, + "Applies to section type 6 messages and indicates " + "the number of UEs (for which channel information is provided) are " + "included in the message. This allows the parser to determine " + "when the last UE's data has been parsed", + HFILL} + }, + + /* Section 5.4.4.12 */ + {&hf_oran_timeOffset, + {"Time Offset", "oran_fh_cus.timeOffset", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "The time_offset from the start of the slot " + "to the start of the Cyclic Prefix (CP) in number of samples tsample " + "(=1/30.72MHz as specified in 3GPP TS38.211 section 4.1). " + "Because this is denominated in \"samples\" there is no fixed " + "microsecond unit for this parameter; time_offset = \"n\" may be longer " + "or shorter in time depending on the sampling interval (which is " + "a NR capability only, not applicable to LTE). time_offset = time" + "Offset * tsample", + HFILL} + }, + + /* Section 7.5.2.13 */ + { &hf_oran_frameStructure_fft, + { "FFT Size", "oran_fh_cus.frameStructure.fft", + FT_UINT8, BASE_HEX | BASE_RANGE_STRING, + RVALS(frame_structure_fft), 0xf0, + "The FFT/iFFT size being used for all IQ data processing related " + "to this message", + HFILL } + }, + + /* Section 7.5.2.13 */ + { &hf_oran_frameStructure_subcarrier_spacing, + { "Subcarrier Spacing", "oran_fh_cus.frameStructure.spacing", + FT_UINT8, BASE_HEX | BASE_RANGE_STRING, + RVALS(subcarrier_spacings), 0x0f, + "The sub carrier spacing " + "as well as the number of slots per 1ms sub-frame according " + "to 3GPP TS 38.211, taking for completeness also 3GPP TS 36.211 " + "into account. The parameter \u03bc=0...5 from 3GPP TS 38.211 is " + "extended to apply for PRACH processing", + HFILL } + }, + + /* Section 7.5.2.14 */ + {&hf_oran_cpLength, + {"cpLength", "oran_fh_cus.cpLength", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "cyclic prefix length", + HFILL} + }, + + /* Section 7.5.3.1 */ + {&hf_oran_section_id, + {"sectionId", "oran_fh_cus.sectionId", + FT_UINT16, BASE_DEC, + NULL, 0xfff0, + "section identifier of data", + HFILL} + }, + + /* Section 7.5.3.2 */ + {&hf_oran_rb, + {"rb", "oran_fh_cus.rb", + FT_UINT8, BASE_DEC, + VALS(rb_vals), 0x08, + "resource block indicator", + HFILL} + }, + + /* Section 7.5.5.3 */ + {&hf_oran_symInc, + {"symInc", "oran_fh_cus.symInc", + FT_UINT8, BASE_DEC, + VALS(sym_inc_vals), 0x04, + "Symbol Number Increment Command", + HFILL} + }, + + /* Section 7.5.3.4 */ + {&hf_oran_startPrbc, + {"startPrbc", "oran_fh_cus.startPrbc", + FT_UINT16, BASE_DEC, + NULL, 0x03ff, + "Starting PRB of Control Plane Section", + HFILL} + }, + + /* Section 7.5.3.5 */ + {&hf_oran_reMask, + {"RE Mask", "oran_fh_cus.reMask", + FT_UINT16, BASE_HEX, + NULL, 0xfff0, + "The Resource Element (RE) mask within a " + "PRB. Each bit setting in the reMask indicates if the section control " + "is applicable to the RE sent in U-Plane messages (0=not applicable; " + "1=applicable)", + HFILL} + }, + + /* Section 7.5.3.6 */ + {&hf_oran_numPrbc, + {"numPrbc", "oran_fh_cus.numPrbc", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "Number of contiguous PRBs per data section description", + HFILL} + }, + + /* Section 7.5.3.7 */ + {&hf_oran_numSymbol, + {"Number of Symbols", "oran_fh_cus.numSymbol", + FT_UINT8, BASE_DEC, + NULL, 0x0f, + "Defines number of symbols to which the section " + "control is applicable. At minimum, the section control shall be " + "applicable to at least one symbol. However, possible optimizations " + "could allow for several (up to 14) symbols, if e.g., all 14 " + "symbols use the same beam ID", + HFILL} + }, + + /* Section 7.5.3.8 */ + {&hf_oran_ef, + {"Extension Flag", "oran_fh_cus.ef", + FT_BOOLEAN, 8, + NULL, 0x80, + "Used to indicate if this section will contain " + "both beamforming index and any extension information (ef=1) or " + "just a beamforming index (ewf=0)", + HFILL} + }, + + /* Section 7.5.3.9 */ + {&hf_oran_beamId, + {"Beam ID", "oran_fh_cus.beamId", + FT_UINT16, BASE_DEC, + NULL, 0x7fff, + "Defines the beam pattern to be applied to the U-Plane " + "data. beamId = 0 means no beamforming operation will be " + "performed. Note that the beamId encodes the beamforming to be done " + "on the RU. This beamforming may be digital, analog or both " + "(\"hybrid beamforming\") and the beamId provides all the information " + "necessary for the RU to select the correct beam (or weight table " + "from which to create a beam). The specific mapping of beamId " + "to e.g. weight table, directionality, beam adjacency or any other " + "beam attributes is specific to the RU design and must be conveyed " + "via M-Plane from the RU to lls-CU upon startup", + HFILL} + }, + + /* Section 5.4.6.2 */ + {&hf_oran_extension, + {"Extension", "oran_fh_cus.extension", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Section extension", + HFILL} + }, + + /* Section 5.4.6.1 */ + {&hf_oran_exttype, + {"extType", "oran_fh_cus.extType", + FT_UINT8, BASE_DEC, + VALS(exttype_vals), 0x7f, + "The extension type, which provides additional parameters specific to subject data extension", + HFILL} + }, + + /* Section 5.4.6.3 */ + {&hf_oran_extlen, + {"extLen", "oran_fh_cus.extLen", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "Extension length in 32-bit words", + HFILL} + }, + + /* Section 5.4.7.1 */ + {&hf_oran_bfw, + {"bfw", "oran_fh_cus.bfw", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Set of weights for a particular antenna", + HFILL} + }, + + /* Section 5.4.7.1.3 */ + {&hf_oran_bfw_bundle, + {"Bundle", "oran_fh_cus.bfw.bundle", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Bundle of BFWs", + HFILL} + }, + {&hf_oran_bfw_bundle_id, + {"Bundle Id", "oran_fh_cus.bfw.bundleId", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, + HFILL} + }, + {&hf_oran_bfw_i, + {"bfwI", "oran_fh_cus.bfwI", + FT_FLOAT, BASE_NONE, + NULL, 0x0, + "In-phase beamforming weight value. The total " + "number of weights in the section is RU-specific and is conveyed " + "from the RU to the lls-CU as part of the initialization procedure " + "via the M-Plane", + HFILL} + }, + + /* Section 5.4.7.1.4 */ + {&hf_oran_bfw_q, + {"bfwQ", "oran_fh_cus.bfwQ", + FT_FLOAT, BASE_NONE, + NULL, 0x0, + "Quadrature beamforming weight value. The " + "total number of weights in the section is RU-specific and is " + "conveyed from the RU to the lls-CU as part of the initialization " + "procedure via the M-Plane", + HFILL} + }, + + /* Section 7.5.3.10 */ + {&hf_oran_ueId, + {"UE ID", "oran_fh_cus.ueId", + FT_UINT16, BASE_HEX_DEC, + NULL, 0x7fff, + "Label for the UE for which the section " + "contents apply. This is used to support channel information " + "sending from the lls-CU to the RU. This is just a label and the " + "specific value has no meaning regarding types of UEs that may be " + "supported within the system", + HFILL} + }, + + /* Section 7.5.3.11 */ + {&hf_oran_freqOffset, + {"Frequency Offset", "oran_fh_cus.freqOffset", + FT_UINT24, BASE_DEC, + NULL, 0x0, + "The frequency offset with respect to the " + "carrier center frequency before additional filtering (e.g. for " + "PRACH) and FFT processing (in UL) in steps of subcarrier spacings" + " ?f. The frequency offset shall be individual per control section. " + "frequency_offset = freqOffset * ?f Note: It may be studied " + "whether this IEs should be individual per control section to allow " + "scheduling of several simultaneous PRACH opportunities with " + "different individual frequency offsets", + HFILL} + }, + + /* Section 7.5.3.12 */ + {&hf_oran_regularizationFactor, + {"Regularization Factor", "oran_fh_cus.regularizationFactor", + FT_INT16, BASE_DEC, + NULL, 0x0, + "Provides a signed value to support MMSE operation " + "within the RU when beamforming weights are supported in the RU, " + "so related to section type 6", + HFILL} + }, + + /* Section 7.5.3.14 */ + {&hf_oran_laaMsgType, + {"LAA Message Type", "oran_fh_cus.laaMsgType", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(laaMsgTypes), 0xf0, + NULL, + HFILL} + }, + + /* Section 7.5.3.15 */ + {&hf_oran_laaMsgLen, + {"LAA Message Length", "oran_fh_cus.laaMsgLen", + FT_UINT8, BASE_DEC, + NULL, 0x0f, + "Defines number of 32-bit words in the LAA section, " + "where \"0\" means one 32-bit word, \"1\" means 2 32-bit words, etc. " + "- including the byte containing the lssMsgLen parameter", + HFILL} + }, + + /* Section 7.5.3.16 */ + {&hf_oran_lbtHandle, + {"LBT Handle", "oran_fh_cus.lbtHandle", + FT_UINT16, BASE_HEX, + NULL, 0x0, + "Provides a label that is included in the configuration " + "request message (e.g., LBT_PDSCH_REQ, LBT_DRS_REQ) transmitted " + "from the lls-CU to the RU and returned in the corresponding " + "response message (e.g., LBT_PDSCH_RSP, LBT_DRS_RSP)", + HFILL} + }, + + /* Section 7.5.3.17 */ + {&hf_oran_lbtDeferFactor, + {"Defer Factor", "oran_fh_cus.lbtDeferFactor", + FT_UINT8, BASE_DEC, + NULL, 0x1c, + "Defer factor in sensing slots as described in 3GPP TS 36.213 " + "Section 15.1.1. This parameter is used for LBT CAT 4 and can take " + "one of three values: {1,3, 7} based on the priority class. Four " + "priority classes are defined in 3GPP TS 36.213", + HFILL} + }, + + /* Section 7.5.3.18 */ + {&hf_oran_lbtBackoffCounter, + {"Backoff Counter", "oran_fh_cus.lbtBackoffCounter", + FT_UINT16, BASE_DEC, + NULL, 0x03ff, + "LBT backoff counter in sensing slots as described in 3GPP TS 36.213 " + "Section 15.1.1. This parameter is used for LBT CAT 4 and can " + "take one of nine values: {3, 7, 15, 31, 63, 127, 255, 511, 1023} " + "based on the priority class. Four priority classes are defined " + "in 3GPP TS 36.213", + HFILL} + }, + + /* Section 7.5.3.19 */ + {&hf_oran_lbtOffset, + {"LBT Offset", "oran_fh_cus.lbtOffset", + FT_UINT16, BASE_DEC, + NULL, 0xff80, + "LBT start time in microseconds from the beginning of the subframe " + "scheduled by this message", + HFILL} + }, + + /* Section 7.5.3.20 */ + {&hf_oran_MCOT, + {"Maximum Channel Occupancy Time", "oran_fh_cus.MCOT", + FT_UINT8, BASE_DEC, + NULL, 0xf0, + "LTE TXOP duration in subframes as described in 3GPP TS 36.213 " + "Section 15.1.1. The maximum values for this parameter are {2, 3, 8, " + "10} based on the priority class. Four priority classes are " + "defined in 3GPP TS 36.213", + HFILL} + }, + + /* Section 7.5.3.21 */ + {&hf_oran_lbtMode, + {"LBT Mode", "oran_fh_cus.lbtMode", + FT_UINT8, BASE_DEC, + VALS(lbtMode_vals), 0x0, + NULL, + HFILL} + }, + + /* Section 7.5.3.22 */ + {&hf_oran_lbtPdschRes, + {"lbtPdschRes", "oran_fh_cus.lbtPdschRes", + FT_UINT8, BASE_DEC, + VALS(lbtPdschRes_vals), 0xc0, + "LBT result of SFN/SF", + HFILL} + }, + + /* Section 7.5.3.23 */ + {&hf_oran_sfStatus, + {"sfStatus", "oran_fh_cus.sfStatus", + FT_BOOLEAN, 8, + TFS(&tfs_sfStatus), 0x10, + "Indicates whether the subframe was dropped or transmitted", + HFILL} + }, + + /* Section 7.5.3.22 */ + {&hf_oran_lbtDrsRes, + {"lbtDrsRes", "oran_fh_cus.lbtDrsRes", + FT_BOOLEAN, 8, + TFS(&tfs_fail_success), 0x80, + "Indicates whether the subframe was dropped or transmitted", + HFILL} + }, + + /* Section 7.5.3.25 */ + {&hf_oran_initialPartialSF, + {"Initial partial SF", "oran_fh_cus.initialPartialSF", + FT_UINT8, BASE_DEC, + NULL, 0x40, + "Indicates whether the initial SF in the LBT process is full or " + "partial. 0 - full SF (two slots, 14 symbols). 1 - partial SF (only " + "second slot, last 7 symbols)", + HFILL} + }, + + /* Section 7.5.3.26. */ + {&hf_oran_lbtBufErr, + {"lbtBufErr", "oran_fh_cus.lbtBufErr", + FT_BOOLEAN, 8, + TFS(&tfs_lbtBufErr), 0x80, + "LBT buffer error", + HFILL} + }, + + /* Section 7.5.3.27 */ + {&hf_oran_sfnSfEnd, + {"SFN/SF End", "oran_fh_cus.sfnSfEnd", + FT_UINT16, BASE_DEC, + NULL, 0x0fff, + "SFN/SF by which the DRS window must end", + HFILL} + }, + + /* Section 7.5.3.28 */ + {&hf_oran_lbtCWConfig_H, + {"lbtCWConfig_H", "oran_fh_cus.lbtCWConfig_H", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "HARQ parameters for congestion window management", + HFILL} + }, + + /* Section 7.5.3.29 */ + {&hf_oran_lbtCWConfig_T, + {"lbtCWConfig_T", "oran_fh_cus.lbtCWConfig_T", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "TB parameters for congestion window management", + HFILL} + }, + + /* Section 7.5.3.30 */ + {&hf_oran_lbtTrafficClass, + {"lbtTrafficClass", "oran_fh_cus.lbtTrafficClass", + FT_UINT8, BASE_DEC, + VALS(lbtTrafficClass_vals), 0x38, + "Traffic class priority for congestion window management", + HFILL} + }, + + /* Section 7.5.3.31 */ + {&hf_oran_lbtCWR_Rst, + {"lbtCWR_Rst", "oran_fh_cus.lbtCWR_Rst", + FT_BOOLEAN, 8, + TFS(&tfs_fail_success), 0x80, + "Traffic class priority for congestion window management", + HFILL} + }, + + {&hf_oran_reserved, + {"reserved", "oran_fh_cus.reserved", + FT_UINT64, BASE_HEX, + NULL, 0x0, + NULL, + HFILL} + }, + + {&hf_oran_reserved_1bit, + {"reserved", "oran_fh_cus.reserved", + FT_UINT8, BASE_HEX, + NULL, 0x80, + NULL, + HFILL} + }, + {&hf_oran_reserved_2bits, + {"reserved", "oran_fh_cus.reserved", + FT_UINT8, BASE_HEX, + NULL, 0xc0, + NULL, + HFILL} + }, + {&hf_oran_reserved_4bits, + {"reserved", "oran_fh_cus.reserved", + FT_UINT8, BASE_HEX, + NULL, 0xf0, + NULL, + HFILL} + }, + {&hf_oran_reserved_6bits, + {"reserved", "oran_fh_cus.reserved", + FT_UINT8, BASE_HEX, + NULL, 0xfc, + NULL, + HFILL} + }, + + {&hf_oran_ext11_reserved, + {"Reserved", "oran_fh_cus.reserved", + FT_UINT8, BASE_HEX, + NULL, 0x3f, + NULL, + HFILL} + }, + + /* 7.7.1.2 bfwCompHdr (beamforming weight compression header) */ + {&hf_oran_bfwCompHdr, + {"bfwCompHdr", "oran_fh_cus.bfwCompHdr", + FT_STRING, BASE_NONE, + NULL, 0x0, + NULL, + HFILL} + }, + + + /* Section 5.4.7.1.1 */ + {&hf_oran_bfwCompHdr_iqWidth, + {"IQ Bit Width", "oran_fh_cus.bfwCompHdr_iqWidth", + FT_UINT8, BASE_HEX, + VALS(bfw_comp_headers_iq_width), 0xf0, + "Defines the compression method and IQ bit width " + "for the beamforming weights in the specific section in the C-Plane " + "message. In this way each set of weights may employ a separate " + "compression method. Note that for the block compression methods, " + "the block size is the entire vector of beamforming weights, not " + "some subset of them", + HFILL} + }, + + /* Section 5.4.7.1.1 */ + {&hf_oran_bfwCompHdr_compMeth, + {"Compression Method", "oran_fh_cus.bfwCompHdr_compMeth", + FT_UINT8, BASE_HEX, + VALS(bfw_comp_headers_comp_meth), 0x0f, + "Defines the compression method and IQ bit width for " + "the beamforming weights in the specific section in the C-Plane " + "message. In this way each set of weights may employ a separate " + "compression method. Note that for the block compression methods, " + "the block size is the entire vector of beamforming weights, " + "not some subset of them", + HFILL} + }, + + /* Section 5.4.7.1.2 */ + {&hf_oran_blockScaler, + {"blockScaler", "oran_fh_cus.blockScaler", + FT_UINT8, BASE_HEX, + NULL, 0x0, + "unsigned, 1 integer bit, 7 fractional bits", + HFILL} + }, + {&hf_oran_compBitWidth, + {"compBitWidth", "oran_fh_cus.compBitWidth", + FT_UINT8, BASE_DEC, + NULL, 0xf0, + "Length of I bits and length of Q bits after compression over entire PRB", + HFILL} + }, + {&hf_oran_compShift, + {"compShift", "oran_fh_cus.compShift", + FT_UINT8, BASE_DEC, + NULL, 0x0f, + "The shift applied to the entire PRB", + HFILL} + }, + + /* Section 5.4.7.6 */ + {&hf_oran_repetition, + {"repetition", "oran_fh_cus.repetition", + FT_BOOLEAN, 1, + NULL, 0x0, + "Repetition of a highest priority data section inside a C-Plane message", + HFILL} + }, + {&hf_oran_rbgSize, + {"rbgSize", "oran_fh_cus.rbgSize", + FT_UINT8, BASE_HEX, + VALS(rbg_size_vals), 0x70, + "Number of PRBs of the resource block groups allocated by the bit mask", + HFILL} + }, + {&hf_oran_rbgMask, + {"rbgMask", "oran_fh_cus.rbgMask", + FT_UINT32, BASE_HEX, + NULL, 0x0fffffff, + "Each bit indicates whether a corresponding resource block group is present", + HFILL} + }, + {&hf_oran_noncontig_priority, + {"priority", "oran_fh_cus.priority", + FT_UINT8, BASE_HEX, + VALS(priority_vals), 0xc0, + NULL, + HFILL} + }, + {&hf_oran_symbolMask, + {"symbolMask", "oran_fh_cus.symbolMask", + FT_UINT16, BASE_HEX, + NULL, 0x3fff, + "Each bit indicates whether the rbgMask applies to a given symbol in the slot", + HFILL} + }, + + /* 7.7.22.1 */ + {&hf_oran_ack_nack_req_id, + {"ackNackReqId", "oran_fh_cus.ackNackReqId", + FT_UINT16, BASE_HEX, + NULL, 0x0, + "Indicates the ACK/NACK request ID of a section description", + HFILL} + }, + + /* Section 5.4.7.12 */ + {&hf_oran_off_start_prb_num_prb_pair, + {"Pair", "oran_fh_cus.offStartPrb_numPrb", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Pair of offStartPrb and numPrb", + HFILL} + }, + + {&hf_oran_off_start_prb, + {"offStartPrb", "oran_fh_cus.offStartPrb", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "Offset of PRB range start", + HFILL} + }, + {&hf_oran_num_prb, + {"numPrb", "oran_fh_cus.numPrb", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "Number of PRBs in PRB range", + HFILL} + }, + + /* symbolId 8.3.3.7 */ + {&hf_oran_symbolId, + {"Symbol Identifier", "oran_fh_cus.symbolId", + FT_UINT8, BASE_HEX, + NULL, 0x3f, + "Identifies a symbol number within a slot", + HFILL} + }, + + /* startPrbu 8.3.3.11 */ + {&hf_oran_startPrbu, + {"startPrbu", "oran_fh_cus.startPrbu", + FT_UINT16, BASE_DEC, + NULL, 0x03ff, + "starting PRB of user plane section", + HFILL} + }, + + /* numPrbu 8.3.3.12 */ + { &hf_oran_numPrbu, + {"numPrbu", "oran_fh_cus.numPrbu", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "number of PRBs per user plane section", + HFILL} + }, + + /* 7.7.1.3 */ + {&hf_oran_bfwCompParam, + {"bfwCompParam", "oran_fh_cus.bfwCompParam", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Beamforming weight compression parameter", + HFILL} + }, + + /* 6.3.3.13 */ + { &hf_oran_udCompHdrMeth, + {"User Data Compression Method", "oran_fh_cus.udCompHdrMeth", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(ud_comp_header_meth), 0x0f, + "Defines the compression method for " + "the user data in every section in the C-Plane message", + HFILL} + }, + { &hf_oran_udCompHdrMeth_pref, + {"User Data Compression Method", "oran_fh_cus.udCompHdrMeth", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(ud_comp_header_meth), 0x0, + "Defines the compression method for " + "the user data in every section in the C-Plane message", + HFILL} + }, + + /* 6.3.3.13 */ + { &hf_oran_udCompHdrIqWidth, + {"User Data IQ width", "oran_fh_cus.udCompHdrWidth", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(ud_comp_header_width), 0xf0, + "Defines the IQ bit width " + "for the user data in every section in the C-Plane message", + HFILL} + }, + { &hf_oran_udCompHdrIqWidth_pref, + {"User Data IQ width", "oran_fh_cus.udCompHdrWidth", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "Defines the IQ bit width " + "for the user data in every section in the C-Plane message", + HFILL} + }, + +#if 0 + /* Section 6.3.3.14 */ + {&hf_oran_udCompParam, + {"User Data Compression Parameter", "oran_fh_cus.udCompParam", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(udCompParams), 0x0, + "Applies to whatever compression method is specified " + "by the associated sectionID's compMeth value", + HFILL} + }, +#endif + + /* Section 6.3.3.15 */ + {&hf_oran_iSample, + {"iSample", "oran_fh_cus.iSample", + FT_FLOAT, BASE_NONE, + NULL, 0x0, + "In-phase Sample value", HFILL} + }, + + /* Section 6.3.3.16 */ + {&hf_oran_qSample, + {"qSample", "oran_fh_cus.qSample", + FT_FLOAT, BASE_NONE, + NULL, 0x0, + "Quadrature Sample value", HFILL} + }, + + { &hf_oran_rsvd8, + { "Reserved", "oran_fh_cus.reserved8", + FT_UINT8, BASE_HEX, + NULL, 0x00, + "Reserved for future use", HFILL } + }, + + { &hf_oran_rsvd16, + { "Reserved", "oran_fh_cus.reserved16", + FT_UINT16, BASE_HEX, + NULL, 0x00, + "Reserved for future use", HFILL } + }, + + { &hf_oran_exponent, + { "Exponent", "oran_fh_cus.exponent", + FT_UINT8, BASE_DEC, + NULL, 0x0f, + "Exponent applicable to the I & Q mantissas. " + "NOTE : Exponent is used for all mantissa sample sizes(i.e. 6bit " + "- 16bit). Likewise, a native \"uncompressed\" format is not supported " + "within this specification", + HFILL } + }, + + { &hf_oran_iq_user_data, + { "IQ User Data", "oran_fh_cus.iq_user_data", + FT_BYTES, BASE_NONE, + NULL, 0x0, + "Used for the In-phase and Quadrature sample " + "mantissa. Twelve I/Q Samples are included per resource block. The width " + "of the mantissa can be between 6 and 16 bits", + HFILL } + }, + + { &hf_oran_c_eAxC_ID, + { "c_eAxC_ID", "oran_fh_cus.c_eaxc_id", + FT_STRING, BASE_NONE, + NULL, 0x0, + "This is a calculated field for the c_eAxC ID, which identifies the message stream", + HFILL } }, + + { &hf_oran_refa, + { "RefA", "oran_fh_cus.refa", + FT_STRING, BASE_NONE, + NULL, 0x0, + "This is a calculated field for the RefA ID, which provides a reference in time", + HFILL } + }, + + { &hf_oran_disable_bfws, + { "disableBFWs", "oran_fh_cus.disableBFWs", + FT_BOOLEAN, 8, + NULL, 0x80, + "Indicate if BFWs under section extension are disabled", + HFILL } + }, + { &hf_oran_rad, + { "RAD", "oran_fh_cus.rad", + FT_BOOLEAN, 8, + NULL, 0x40, + "Reset After PRB Discontinuity", + HFILL } + }, + { &hf_oran_num_bund_prbs, + { "numBundPrb", "oran_fh_cus.numBundPrb", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "Number of bundled PRBs per BFWs", + HFILL } + }, + { &hf_oran_beam_id, + { "beamId", "oran_fh_cus.beamId", + FT_UINT16, BASE_DEC, + NULL, 0x7fff, + NULL, + HFILL } + }, + { &hf_oran_num_weights_per_bundle, + { "Num weights per bundle", "oran_fh_cus.num_weights_per_bundle", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "From dissector preference", + HFILL } + }, + + + { &hf_oran_samples_prb, + {"PRB", "oran_fh_cus.prb", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Grouping of samples for a particular Physical Resource Block", + HFILL} + }, + + {&hf_oran_ciSample, + {"ciSample", "oran_fh_cus.ciSample", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Sample (I and Q values)", + HFILL} + }, + {&hf_oran_ciIsample, + {"ciIsample", "oran_fh_cus.ciISample", + FT_FLOAT, BASE_NONE, + NULL, 0x0, + "Channel information complex value - I part", + HFILL} + }, + {&hf_oran_ciQsample, + { "ciQsample", "oran_fh_cus.ciQSample", + FT_FLOAT, BASE_NONE, + NULL, 0x0, + "Channel information complex value - Q part", + HFILL} + }, + + /* 7.7.10.2 */ + { &hf_oran_beamGroupType, + { "beamGroupType", "oran_fh_cus.beamGroupType", + FT_UINT8, BASE_DEC, + VALS(beam_group_type_vals), 0xc0, + "The type of beam grouping", + HFILL } + }, + /* 7.7.10.3 */ + { &hf_oran_numPortc, + { "numPortc", "oran_fh_cus.numPortc", + FT_UINT8, BASE_DEC, + NULL, 0x3f, + "The number of eAxC ports", + HFILL } + }, + + /* 7.7.4.2 (1 bit) */ + { &hf_oran_csf, + { "csf", "oran_fh_cus.csf", + FT_BOOLEAN, 1, + NULL, 0x0, + "constellation shift flag", + HFILL } + }, + /* 7.7.4.3 */ + { &hf_oran_modcompscaler, + { "modCompScaler", "oran_fh_cus.modcompscaler", + FT_UINT16, BASE_DEC, + NULL, 0x7fff, + "modulation compression scaler value", + HFILL } + }, + + /* 7.7.5.1 */ + { &hf_oran_modcomp_param_set, + { "Set", "oran_fh_cus.modcomp-param-set", + FT_STRING, BASE_NONE, + NULL, 0x0, + NULL, + HFILL } + }, + + /* mcScaleReMask 7.7.5.2 (12 bits) */ + { &hf_oran_mc_scale_re_mask, + { "mcScaleReMask", "oran_fh_cus.mcscaleremask", + FT_BOOLEAN, 12, + NULL, 0x0, + "modulation compression power scale RE mask", + HFILL } + }, + /* mcScaleOffset 7.7.5.4 (15 bits) */ + { &hf_oran_mc_scale_offset, + { "mcScaleOffset", "oran_fh_cus.mcscaleoffset", + FT_UINT24, BASE_DEC, + NULL, 0x0, + "scaling value for modulation compression", + HFILL } + }, + /* eAxCmask (7.7.7.2) */ + { &hf_oran_eAxC_mask, + { "eAxC Mask", "oran_fh_cus.eaxcmask", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "Which eAxC_ID values the C-Plane message applies to", + HFILL } + }, + /* technology (interface name) 7.7.9.2 */ + { &hf_oran_technology, + { "Technology", "oran_fh_cus.technology", + FT_UINT8, BASE_DEC, + VALS(interface_name_vals), 0x0, + "Interface name (that C-PLane section applies to)", + HFILL } + }, + /* Exttype 14 (7.7.14.2) */ + { &hf_oran_nullLayerInd, + { "nullLayerInd", "oran_fh_cus.nulllayerind", + FT_BOOLEAN, 8, + NULL, 0x0, + "Whether corresponding layer is nulling-layer or not", + HFILL } + }, + + /* Exttype 19 (7.7.19.8) */ + { &hf_oran_portReMask, + { "portReMask", "oran_fh_cus.portReMask", + FT_BOOLEAN, 16, + TFS(&tfs_set_notset), 0x0fff, + "RE bitmask per port", + HFILL } + }, + { &hf_oran_portSymbolMask, + { "portSymbolMask", "oran_fh_cus.portSymbolMask", + FT_BOOLEAN, 16, + TFS(&tfs_set_notset), 0x3fff, + "Symbol bitmask port port", + HFILL } + }, + + { &hf_oran_ext19_port, + {"Port", "oran_fh_cus.ext19.port", + FT_STRING, BASE_NONE, + NULL, 0x0, + "Entry for a given port in ext19", + HFILL} + }, + + /* Ext 13 */ + { &hf_oran_prb_allocation, + {"PRB allocation", "oran_fh_cus.prb-allocation", + FT_STRING, BASE_NONE, + NULL, 0x0, + NULL, + HFILL} + }, + { &hf_oran_nextSymbolId, + { "nextSymbolId", "oran_fh_cus.nextSymbolId", + FT_UINT8, BASE_DEC, + NULL, 0x3c, + "offset of PRB range start", + HFILL } + }, + { &hf_oran_nextStartPrbc, + { "nextStartPrbc", "oran_fh_cus.nextStartPrbc", + FT_UINT16, BASE_DEC, + NULL, 0x03ff, + "number of PRBs in PRB range", + HFILL } + }, + + /* Puncturing patters as appears in SE 20 */ + {&hf_oran_puncPattern, + {"puncPattern", "oran_fh_cus.puncPattern", + FT_STRING, FT_NONE, + NULL, 0x0, + NULL, + HFILL} + }, + + /* 7.7.20.2 numPuncPatterns */ + { &hf_oran_numPuncPatterns, + { "numPuncPatterns", "oran_fh_cus.numPuncPatterns", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "number of puncturing patterns", + HFILL } + }, + /* 7.7.20.3 symbolMask */ + {&hf_oran_symbolMask_ext20, + {"symbolMask", "oran_fh_cus.symbolMask", + FT_UINT16, BASE_HEX, + NULL, 0xfffc, + "Bitmask where each bit indicates the symbols associated with the puncturing pattern", + HFILL} + }, + /* 7.7.20.4 startPuncPrb */ + {&hf_oran_startPuncPrb, + {"startPuncPrb", "oran_fh_cus.startPuncPrb", + FT_UINT16, BASE_DEC, + NULL, 0x03ff, + "starting PRB to which one puncturing pattern applies", + HFILL} + }, + /* 7.7.20.5 numPuncPrb */ + {&hf_oran_numPuncPrb, + {"numPuncPrb", "oran_fh_cus.numPuncPrb", + FT_UINT24, BASE_DEC, + NULL, 0x03ffff, + "the number of PRBs of the puncturing pattern", + HFILL} + }, + /* 7.7.20.6 puncReMask */ + {&hf_oran_puncReMask, + {"puncReMask", "oran_fh_cus.puncReMask", + FT_UINT16, BASE_DEC, + NULL, 0xffc0, + "puncturing pattern RE mask", + HFILL} + }, + /* 7.7.20.4 rbgIncl */ + {&hf_oran_RbgIncl, + {"rbgIncl", "oran_fh_cus.rbgIncl", + FT_BOOLEAN, 8, + NULL, 0x01, + "rbg included flag", + HFILL} + }, + + /* 7.7.21.2 ciPrbGroupSize */ + {&hf_oran_ci_prb_group_size, + {"ciPrbGroupSize", "oran_fh_cus.ciPrbGroupSize", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "channel information PRB group size", + HFILL} + }, + + /* 7.7.17.2 numUeID */ + {&hf_oran_num_ueid, + {"numUeID", "oran_fh_cus.numUeID", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "number of ueIDs per user", + HFILL} + }, + + /* 7.7.16.2 antMask */ + {&hf_oran_antMask, + {"antMask", "oran_fh_cus.antMask", + FT_UINT64, BASE_HEX, + NULL, 0xffffffffffffffff, + "indices of antennas to be pre-combined per RX endpoint", + HFILL} + }, + + /* 7.7.18.2 transmissionWindowOffset */ + {&hf_oran_transmissionWindowOffset, + {"transmissionWindowOffset", "oran_fh_cus.transmissionWindowOffset", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "start of the transmission window as an offset to when the transmission window would have been without this parameter, i.e. (Ta3_max - Ta3_min)", + HFILL} + }, + /* 7.7.18.3 transmissionWindowSize */ + {&hf_oran_transmissionWindowSize, + {"transmissionWindowSize", "oran_fh_cus.transmissionWindowSize", + FT_UINT16, BASE_DEC, + NULL, 0x3fff, + "size of the transmission window in resolution µs", + HFILL} + }, + /* 7.7.18.4 toT */ + {&hf_oran_toT, + {"toT", "oran_fh_cus.toT", + FT_UINT8, BASE_DEC, + VALS(type_of_transmission_vals), 0x03, + "type of transmission", + HFILL} + }, + + /* 7.7.2.2 bfaCompHdr */ + {&hf_oran_bfaCompHdr, + {"bfaCompHdr", "oran_fh_cus.bfaCompHdr", + FT_STRING, BASE_NONE, + NULL, 0x0, + "beamforming attributes compression header", + HFILL} + }, + /* 7.7.2.2-2: bfAzPtWidth */ + {&hf_oran_bfAzPtWidth, + {"bfAzPtWidth", "oran_fh_cus.bfAzPtWidth", + FT_UINT8, BASE_DEC, + VALS(bfa_bw_vals), 0x38, + NULL, + HFILL} + }, + /* 7.7.2.2-3: bfZePtWidth */ + {&hf_oran_bfZePtWidth, + {"bfZePtWidth", "oran_fh_cus.bfZePtWidth", + FT_UINT8, BASE_DEC, + VALS(bfa_bw_vals), 0x07, + NULL, + HFILL} + }, + /* 7.7.2.2-4: bfAz3ddWidth */ + {&hf_oran_bfAz3ddWidth, + {"bfAz3ddWidth", "oran_fh_cus.bfAz3ddWidth", + FT_UINT8, BASE_DEC, + VALS(bfa_bw_vals), 0x38, + NULL, + HFILL} + }, + /* 7.7.2.2-5: bfZe3ddWidth */ + {&hf_oran_bfZe3ddWidth, + {"bfZe3ddWidth", "oran_fh_cus.bfZe3ddWidth", + FT_UINT8, BASE_DEC, + VALS(bfa_bw_vals), 0x07, + NULL, + HFILL} + }, + + /* 7.7.2.3 bfAzPt */ + {&hf_oran_bfAzPt, + {"bfAzPt", "oran_fh_cus.bfAzPt", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "beamforming azimuth pointing parameter", + HFILL} + }, + /* 7.7.2.4 bfZePt */ + {&hf_oran_bfZePt, + {"bfZePt", "oran_fh_cus.bfZePt", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "beamforming zenith pointing parameter", + HFILL} + }, + /* 7.7.2.5 bfAz3dd */ + {&hf_oran_bfAz3dd, + {"bfAz3dd", "oran_fh_cus.bfAz3dd", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "beamforming azimuth beamwidth parameter", + HFILL} + }, + /* 7.7.2.6 bfZe3dd */ + {&hf_oran_bfZe3dd, + {"bfZe3dd", "oran_fh_cus.bfZe3dd", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "beamforming zenith beamwidth parameter", + HFILL} + }, + + /* 7.7.2.7 bfAzSl */ + {&hf_oran_bfAzSl, + {"bfAzSl", "oran_fh_cus.bfAzSl", + FT_UINT8, BASE_DEC, + VALS(sidelobe_suppression_vals), 0x38, + "beamforming azimuth sidelobe parameter", + HFILL} + }, + /* 7.7.2.8 bfZeSl */ + {&hf_oran_bfZeSl, + {"bfZeSl", "oran_fh_cus.bfZeSl", + FT_UINT8, BASE_DEC, + VALS(sidelobe_suppression_vals), 0x38, + "beamforming zenith sidelobe parameter", + HFILL} + } + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_oran, + &ett_oran_ecpri_pcid, + &ett_oran_ecpri_rtcid, + &ett_oran_ecpri_seqid, + &ett_oran_section_type, + &ett_oran_u_timing, + &ett_oran_u_section, + &ett_oran_u_prb, + &ett_oran_section, + &ett_oran_iq, + &ett_oran_c_section_extension, + &ett_oran_bfw_bundle, + &ett_oran_bfw, + &ett_oran_offset_start_prb_num_prb, + &ett_oran_prb_cisamples, + &ett_oran_cisample, + &ett_oran_udcomphdr, + &ett_oran_bfwcomphdr, + &ett_oran_bfwcompparam, + &ett_oran_ext19_port, + &ett_oran_prb_allocation, + &ett_oran_punc_pattern, + &ett_oran_bfacomphdr, + &ett_oran_modcomp_param_set + }; + + expert_module_t* expert_oran; + + static ei_register_info ei[] = { + { &ei_oran_unsupported_bfw_compression_method, { "oran_fh_cus.unsupported_bfw_compression_method", PI_UNDECODED, PI_WARN, "Unsupported BFW Compression Method", EXPFILL }}, + { &ei_oran_invalid_sample_bit_width, { "oran_fh_cus.invalid_sample_bit_width", PI_UNDECODED, PI_ERROR, "Unsupported sample bit width", EXPFILL }}, + { &ei_oran_reserved_numBundPrb, { "oran_fh_cus.reserved_numBundPrb", PI_MALFORMED, PI_ERROR, "Reserved value of numBundPrb", EXPFILL }}, + { &ei_oran_extlen_wrong, { "oran_fh_cus.extlen_wrong", PI_MALFORMED, PI_ERROR, "extlen doesn't match number of dissected bytes", EXPFILL }}, + { &ei_oran_invalid_eaxc_bit_width, { "oran_fh_cus.invalid_exac_bit_width", PI_UNDECODED, PI_ERROR, "Inconsistent eAxC bit width", EXPFILL }}, + { &ei_oran_extlen_zero, { "oran_fh_cus.extlen_zero", PI_MALFORMED, PI_ERROR, "extlen - zero is reserved value", EXPFILL }}, + { &ei_oran_rbg_size_reserved, { "oran_fh_cus.rbg_size_reserved", PI_MALFORMED, PI_ERROR, "rbgSize - zero is reserved value", EXPFILL }}, + { &ei_oran_frame_length, { "oran_fh_cus.frame_length", PI_MALFORMED, PI_ERROR, "there should be 0-3 bytes remaining after PDU in frame", EXPFILL }}, + }; + + /* Register the protocol name and description */ + proto_oran = proto_register_protocol("O-RAN Fronthaul CUS", "O-RAN FH CUS", "oran_fh_cus"); + + /* Allow dissector to find be found by name. */ + register_dissector("oran_fh_cus", dissect_oran, proto_oran); + + /* Required function calls to register the header fields and subtrees */ + proto_register_field_array(proto_oran, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + expert_oran = expert_register_protocol(proto_oran); + expert_register_field_array(expert_oran, ei, array_length(ei)); + + module_t * oran_module = prefs_register_protocol(proto_oran, NULL); + + /* Register bit width/compression preferences separately by direction. */ + prefs_register_uint_preference(oran_module, "oran.du_port_id_bits", "DU Port ID bits [a]", + "The bit width of DU Port ID - sum of a,b,c&d (eAxC) must be 16", 10, &pref_du_port_id_bits); + prefs_register_uint_preference(oran_module, "oran.bandsector_id_bits", "BandSector ID bits [b]", + "The bit width of BandSector ID - sum of a,b,c&d (eAxC) must be 16", 10, &pref_bandsector_id_bits); + prefs_register_uint_preference(oran_module, "oran.cc_id_bits", "CC ID bits [c]", + "The bit width of CC ID - sum of a,b,c&d (eAxC) must be 16", 10, &pref_cc_id_bits); + prefs_register_uint_preference(oran_module, "oran.ru_port_id_bits", "RU Port ID bits [d]", + "The bit width of RU Port ID - sum of a,b,c&d (eAxC) must be 16", 10, &pref_ru_port_id_bits); + + prefs_register_uint_preference(oran_module, "oran.iq_bitwidth_up", "IQ Bitwidth Uplink", + "The bit width of a sample in the Uplink (if no udcompHdr)", 10, &pref_sample_bit_width_uplink); + prefs_register_enum_preference(oran_module, "oran.ud_comp_up", "Uplink User Data Compression", + "Uplink User Data Compression", &pref_iqCompressionUplink, compression_options, TRUE); + prefs_register_bool_preference(oran_module, "oran.ud_comp_hdr_up", "udCompHdr field is present for uplink", + "The udCompHdr field in U-Plane messages may or may not be present, depending on the " + "configuration of the O-RU. This preference instructs the dissector to expect " + "this field to be present in uplink messages", &pref_includeUdCompHeaderUplink); + + prefs_register_uint_preference(oran_module, "oran.iq_bitwidth_down", "IQ Bitwidth Downlink", + "The bit width of a sample in the Downlink (if no udcompHdr)", 10, &pref_sample_bit_width_downlink); + prefs_register_enum_preference(oran_module, "oran.ud_comp_down", "Downlink User Data Compression", + "Downlink User Data Compression", &pref_iqCompressionDownlink, compression_options, TRUE); + prefs_register_bool_preference(oran_module, "oran.ud_comp_hdr_down", "udCompHdr field is present for downlink", + "The udCompHdr field in U-Plane messages may or may not be present, depending on the " + "configuration of the O-RU. This preference instructs the dissector to expect " + "this field to be present in downlink messages", &pref_includeUdCompHeaderDownlink); + + prefs_register_uint_preference(oran_module, "oran.rbs_in_uplane_section", "Total RBs in User-Plane data section", + "This is used if numPrbu is signalled as 0", 10, &pref_data_plane_section_total_rbs); + + prefs_register_uint_preference(oran_module, "oran.num_weights_per_bundle", "Number of weights per bundle", + "Used in decoding of section extension type 11 (Flexible BF weights)", 10, &pref_num_weights_per_bundle); + + prefs_register_uint_preference(oran_module, "oran.num_bf_antennas", "Number of BF Antennas", + "Number of BF Antennas (used for C section type 6)", 10, &pref_num_bf_antennas); + + prefs_register_bool_preference(oran_module, "oran.show_iq_samples", "Show IQ Sample values", + "When enabled, for U-Plane frames show each I and Q value in PRB", &pref_showIQSampleValues); + + prefs_register_obsolete_preference(oran_module, "oran.num_bf_weights"); + + flow_states_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); +} + +/* Simpler form of proto_reg_handoff_oran which can be used if there are + * no prefs-dependent registration function calls. */ +void +proto_reg_handoff_oran(void) +{ +} + +/* +* Editor modelines - http://www.wireshark.org/tools/modelines.html +* +* Local Variables: +* c-basic-offset: 4 +* tab-width: 8 +* indent-tabs-mode: nil +* End: +* +* ex: set shiftwidth=4 tabstop=8 expandtab: +* :indentSize=4:tabSize=8:noTabs=true: +*/ |