diff --git a/docbook/release-notes.adoc b/docbook/release-notes.adoc index efda7c746e..ccba144310 100644 --- a/docbook/release-notes.adoc +++ b/docbook/release-notes.adoc @@ -57,6 +57,7 @@ The following features are new (or have been significantly updated) since versio // Add one protocol per line between the -- delimiters in the format // "Full protocol name (Abbreviation)" +O-RAN fronthaul UC-plane (O-RAN) [commaize] -- -- diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt index 90b641fc1b..164d3de749 100644 --- a/epan/dissectors/CMakeLists.txt +++ b/epan/dissectors/CMakeLists.txt @@ -1548,6 +1548,7 @@ set(DISSECTOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/packet-openwire.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-opsi.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-optommp.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-oran.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-osc.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-oscore.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-osi-options.c diff --git a/epan/dissectors/packet-ecpri.c b/epan/dissectors/packet-ecpri.c index 57dd7b6ba5..ff07a9a92e 100644 --- a/epan/dissectors/packet-ecpri.c +++ b/epan/dissectors/packet-ecpri.c @@ -162,25 +162,39 @@ static expert_field ei_ecpri_not_dis_yet = EI_INIT; /**************************************************************************************************/ /* Field Encoding of Message Types */ /**************************************************************************************************/ + +#define ECPRI_MT_IQ_DATA 0 +#define ECPRI_MT_BIT_SEQ 1 +#define ECPRI_MT_RT_CTRL_DATA 2 +#define ECPRI_MT_GEN_DATA_TFER 3 +#define ECPRI_MT_REM_MEM_ACC 4 +#define ECPRI_MT_1WAY_DELAY 5 +#define ECPRI_MT_REM_RST 6 +#define ECPRI_MT_EVT_IND 7 +#define ECPRI_MT_IWF_STARTUP 8 +#define ECRPI_MT_IWF_OP 9 +#define ECRPI_MT_IWF_MAPPING 10 +#define ECRPI_MT_IWF_DELAY_CONTROL 11 + static const range_string ecpri_msg_types[] = { - /* Message Types 0 - 7 */ - { 0x0, 0x0, "IQ Data" }, - { 0x1, 0x1, "Bit Sequence" }, - { 0x2, 0x2, "Real-Time Control Data" }, - { 0x3, 0x3, "Generic Data Transfer" }, - { 0x4, 0x4, "Remote Memory Access" }, - { 0x5, 0x5, "One-Way Delay Measurement" }, - { 0x6, 0x6, "Remote Reset" }, - { 0x7, 0x7, "Event Indication" }, - { 0x8, 0x8, "IWF Start-Up" }, - { 0x9, 0x9, "IWF Operation" }, - { 0xa, 0xa, "IWF Mapping" }, - { 0xb, 0xb, "IWF Delay Control" }, + /* Message Types (3.2.4) */ + { ECPRI_MT_IQ_DATA, ECPRI_MT_IQ_DATA, "IQ Data" }, + { ECPRI_MT_BIT_SEQ, ECPRI_MT_BIT_SEQ, "Bit Sequence" }, + { ECPRI_MT_RT_CTRL_DATA, ECPRI_MT_RT_CTRL_DATA, "Real-Time Control Data" }, + { ECPRI_MT_GEN_DATA_TFER, ECPRI_MT_GEN_DATA_TFER, "Generic Data Transfer" }, + { ECPRI_MT_REM_MEM_ACC, ECPRI_MT_REM_MEM_ACC, "Remote Memory Access" }, + { ECPRI_MT_1WAY_DELAY, ECPRI_MT_1WAY_DELAY, "One-Way Delay Measurement" }, + { ECPRI_MT_REM_RST, ECPRI_MT_REM_RST, "Remote Reset" }, + { ECPRI_MT_EVT_IND, ECPRI_MT_EVT_IND, "Event Indication" }, + { ECPRI_MT_IWF_STARTUP, ECPRI_MT_IWF_STARTUP, "IWF Start-Up" }, + { ECRPI_MT_IWF_OP, ECRPI_MT_IWF_OP, "IWF Operation" }, + { ECRPI_MT_IWF_MAPPING, ECRPI_MT_IWF_MAPPING, "IWF Mapping" }, + { ECRPI_MT_IWF_DELAY_CONTROL, ECRPI_MT_IWF_DELAY_CONTROL, "IWF Delay Control" }, /* Message Types 12 - 63*/ - { 0xc, 0x3F, "Reserved" }, + { 12, 63, "Reserved" }, /* Message Types 64 - 255 */ - { 0x40, 0xFF, "Vendor Specific" }, - { 0, 0, NULL } + { 64, 255, "Vendor Specific" }, + { 0, 0, NULL } }; /**************************************************************************************************/ @@ -404,8 +418,9 @@ static int dissect_ecpri(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, vo ti_c_bit = proto_tree_add_item(header_tree, hf_c_bit, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(header_tree, hf_msg_type, tvb, offset, 1, ENC_NA, &msg_type); - /* Append Message Type into info column */ + /* Append Message Type into info column & header item */ col_append_sep_fstr(pinfo->cinfo, COL_INFO, ",", "Message Type: %s", try_rval_to_str(msg_type, ecpri_msg_types)); + proto_item_append_text(header_item, " MessageType: %s", try_rval_to_str(msg_type, ecpri_msg_types)); offset += 1; ti_payload_size = proto_tree_add_item(header_tree, hf_payload_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; @@ -426,299 +441,311 @@ static int dissect_ecpri(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, vo remaining_length = reported_length - offset; if (message_type_decoding) { - switch (msg_type) - { - case 0x00: - /* IQ Data */ - case 0x01: - /* Bit Sequence */ - if (payload_size >= ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH) + tvbuff_t *fh_tvb = tvb_new_subset_length_caplen(tvb, offset, payload_size, payload_size); + /* See whether we have an O-RAN fronthaul sub-dissector that handles this, otherwise decode vanilla eCPRI */ + dissector_handle_t oran_handle = find_dissector("oran_fh_cus"); + int ret = call_dissector_only(oran_handle, fh_tvb, pinfo, tree, &msg_type); + if (ret) { + /* Assume that it has claimed the entire tvb */ + offset = tvb_reported_length(tvb); + } + else { + switch (msg_type) { - if (remaining_length >= ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH) + case ECPRI_MT_IQ_DATA: + /* 3.2.4.1 IQ Data */ + case ECPRI_MT_BIT_SEQ: + /* 3.2.4.2 Bit Sequence */ + if (payload_size >= ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH) { - proto_tree_add_item(payload_tree, hf_pc_id, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - proto_tree_add_item(payload_tree, hf_seq_id, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - remaining_length -= ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH; - if (remaining_length >= payload_size - ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH) + if (remaining_length >= ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH) { - proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH, ENC_NA); - offset += payload_size - ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH; - } - } - } - else - { - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH); - } - break; - case 0x02: - /* Real-Time Control Data */ - if (payload_size >= ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH) - { - if (remaining_length >= ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH) - { - proto_tree_add_item(payload_tree, hf_rtc_id, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - proto_tree_add_item(payload_tree, hf_seq_id, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - remaining_length -= ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH; - if (remaining_length >= payload_size - ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH) - { - proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH, ENC_NA); - offset += payload_size - ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH; - } - } - } - else - { - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH); - } - break; - case 0x03: - /* Generic Data Transfer */ - if (payload_size >= ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH) - { - if (remaining_length >= ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH) - { - proto_tree_add_item(payload_tree, hf_pc_id2, tvb, offset, 4, ENC_BIG_ENDIAN); - offset += 4; - proto_tree_add_item(payload_tree, hf_seq_id2, tvb, offset, 4, ENC_BIG_ENDIAN); - offset += 4; - remaining_length -= ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH; - if (remaining_length >= payload_size - ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH) - { - proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH, ENC_NA); - offset += payload_size - ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH; - } - } - } - else - { - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH); - } - break; - case 0x04: - /* Remote Memory Access */ - if (payload_size >= ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH) - { - if (remaining_length >= ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH) - { - proto_tree_add_item(payload_tree, hf_rma_id, tvb, offset, 1, ENC_NA); - offset += 1; - proto_tree_add_item(payload_tree, hf_read_write, tvb, offset, 1, ENC_NA); - proto_tree_add_item(payload_tree, hf_request_response, tvb, offset, 1, ENC_NA); - offset += 1; - proto_tree_add_item(payload_tree, hf_element_id, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - proto_tree_add_item(payload_tree, hf_address, tvb, offset, 6, ENC_NA); - offset += 6; - ti_data_length = proto_tree_add_item_ret_uint(payload_tree, hf_data_length, tvb, offset, 2, ENC_BIG_ENDIAN, &data_length); - offset += 2; - remaining_length -= ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH; - if (remaining_length >= payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH) - { - if (data_length == (guint32)(payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH)) + proto_tree_add_item(payload_tree, hf_pc_id, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(payload_tree, hf_seq_id, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + remaining_length -= ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH; + if (remaining_length >= payload_size - ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH) { - proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH, ENC_NA); - offset += payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH; - } - else if (data_length < (guint32)(payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH)) - { - expert_add_info_format(pinfo, ti_data_length, &ei_data_length, "Data Length %d is too small, should be %d", data_length, payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH); - } - else - { - expert_add_info_format(pinfo, ti_data_length, &ei_data_length, "Data Length %d is too big, should be %d", data_length, payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH); + proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH, ENC_NA); + offset += payload_size - ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH; } } } - } - else - { - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH); - } - break; - case 0x05: - /* One-way Delay Measurement */ - if (payload_size >= ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH) - { - if (remaining_length >= ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH) + else { - proto_tree_add_item(payload_tree, hf_measurement_id, tvb, offset, 1, ENC_NA); - offset += 1; - proto_tree_add_item_ret_uint(payload_tree, hf_action_type, tvb, offset, 1, ENC_NA, &action_type); - offset += 1; - /* Time Stamp for seconds and nano-seconds */ - timestamp_item = proto_tree_add_item(payload_tree, hf_timestamp, tvb, offset, 10, ENC_NA); - timestamp_tree = proto_item_add_subtree(timestamp_item, ett_ecpri_timestamp); - proto_tree_add_item_ret_uint64(timestamp_tree, hf_timestamp_sec, tvb, offset, 6, ENC_BIG_ENDIAN, &time_stamp_s); - offset += 6; - proto_tree_add_item_ret_uint(timestamp_tree, hf_timestamp_nanosec, tvb, offset, 4, ENC_BIG_ENDIAN, &time_stamp_ns); - offset += 4; - if (action_type >= ECPRI_MSG_TYPE_5_RESERVED_MIN) - { - expert_add_info_format(pinfo, timestamp_item, &ei_time_stamp, "Time stamp is not defined for Action Type %d", action_type); - } - else if (action_type != ECPRI_MSG_TYPE_5_REQ && action_type != ECPRI_MSG_TYPE_5_RESPONSE && action_type != ECPRI_MSG_TYPE_5_FOLLOWUP && time_stamp_s != 0x0000000000000000 && time_stamp_ns != 0x00000000) - { - expert_add_info_format(pinfo, timestamp_item, &ei_time_stamp, "Time stamp is not defined for Action Type %d, should be 0", action_type); - } - ti_comp_val = proto_tree_add_item_ret_uint64(payload_tree, hf_compensation_value, tvb, offset, 8, ENC_BIG_ENDIAN, &comp_val); - proto_item_append_text(ti_comp_val, " = %fns", comp_val / 65536.0); - - if (action_type >= ECPRI_MSG_TYPE_5_RESERVED_MIN) - { - expert_add_info_format(pinfo, timestamp_item, &ei_time_stamp, "Compensation Value is not defined for Action Type %d", action_type); - } - else if (action_type != ECPRI_MSG_TYPE_5_REQ && action_type != ECPRI_MSG_TYPE_5_RESPONSE && action_type != ECPRI_MSG_TYPE_5_FOLLOWUP && comp_val != 0x0000000000000000) - { - expert_add_info_format(pinfo, ti_comp_val, &ei_comp_val, "Compensation Value is not defined for Action Type %d, should be 0", action_type); - } - offset += 8; - remaining_length -= ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH; - if (remaining_length >= payload_size - ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH) - { - proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH, ENC_NA); - offset += payload_size - ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH; - } + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_0_1_PAYLOAD_MIN_LENGTH); } - } - else - { - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH); - } - break; - case 0x06: - /* Remote Reset */ - if (payload_size >= ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH) - { - if (remaining_length >= ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH) + break; + case ECPRI_MT_RT_CTRL_DATA: + /* 3.2.4.3 Real-Time Control Data */ + /* N.B. if ORAN dissector is enabled, it will handle this type instead! */ + if (payload_size >= ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH) { - proto_tree_add_item(payload_tree, hf_reset_id, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - proto_tree_add_item(payload_tree, hf_reset_code, tvb, offset, 1, ENC_NA); - offset += 1; - remaining_length -= ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH; - if (remaining_length >= payload_size - ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH) + if (remaining_length >= ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH) { - proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH, ENC_NA); - offset += payload_size - ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH; - } - } - } - else - { - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH); - } - break; - case 0x07: - /* Event Indication */ - if (payload_size >= ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH) - { - if (remaining_length >= ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH) - { - proto_tree_add_item(payload_tree, hf_event_id, tvb, offset, 1, ENC_NA); - offset += 1; - proto_tree_add_item_ret_uint(payload_tree, hf_event_type, tvb, offset, 1, ENC_NA, &event_type); - offset += 1; - proto_tree_add_item(payload_tree, hf_sequence_num, tvb, offset, 1, ENC_NA); - offset += 1; - ti_num_faults = proto_tree_add_item_ret_uint(payload_tree, hf_number_faults_notif, tvb, offset, 1, ENC_NA, &num_faults_notif); - offset += 1; - /* Only for Event Type Fault Indication (0x00) and Notification Indication (0x02) */ - if (event_type == ECPRI_MSG_TYPE_7_FAULT_INDICATION || event_type == ECPRI_MSG_TYPE_7_NOTIF_INDICATION) - { - /* These two Event Types should have notifications or faults */ - if (num_faults_notif > 0) + proto_tree_add_item(payload_tree, hf_rtc_id, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(payload_tree, hf_seq_id, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + remaining_length -= ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH; + if (remaining_length >= payload_size - ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH) { - /* Check Size of Elements */ - if (payload_size == ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH + num_faults_notif * ECPRI_MSG_TYPE_7_ELEMENT_SIZE) + proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH, ENC_NA); + offset += payload_size - ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH; + } + } + } + else + { + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_2_PAYLOAD_MIN_LENGTH); + } + break; + case ECPRI_MT_GEN_DATA_TFER: + /* 3.2.4.4 Generic Data Transfer */ + if (payload_size >= ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH) + { + if (remaining_length >= ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_pc_id2, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(payload_tree, hf_seq_id2, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + remaining_length -= ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH; + if (remaining_length >= payload_size - ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH, ENC_NA); + offset += payload_size - ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH; + } + } + } + else + { + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_3_PAYLOAD_MIN_LENGTH); + } + break; + case ECPRI_MT_REM_MEM_ACC: + /* 3.2.4.5 Remote Memory Access */ + if (payload_size >= ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH) + { + if (remaining_length >= ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_rma_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(payload_tree, hf_read_write, tvb, offset, 1, ENC_NA); + proto_tree_add_item(payload_tree, hf_request_response, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(payload_tree, hf_element_id, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(payload_tree, hf_address, tvb, offset, 6, ENC_NA); + offset += 6; + ti_data_length = proto_tree_add_item_ret_uint(payload_tree, hf_data_length, tvb, offset, 2, ENC_BIG_ENDIAN, &data_length); + offset += 2; + remaining_length -= ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH; + if (remaining_length >= payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH) + { + if (data_length == (guint32)(payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH)) { - /* Dissect elements in loop */ - for (guint32 i = 0; i < num_faults_notif; i++) - { - element_item = proto_tree_add_item(payload_tree, hf_element, tvb, offset, ECPRI_MSG_TYPE_7_ELEMENT_SIZE, ENC_NA); - proto_item_prepend_text(element_item, "#%d: ", i + 1); - element_tree =proto_item_add_subtree(element_item, ett_ecpri_element); - - proto_tree_add_item(element_tree, hf_element_id2, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - proto_tree_add_item(element_tree, hf_raise_cease, tvb, offset, 1, ENC_NA); - ti_fault_notif = proto_tree_add_item_ret_uint(element_tree, hf_fault_notif, tvb, offset, 2, ENC_BIG_ENDIAN, &fault_notif); - /* Faults and Notifications cannot be mixed */ - if (event_type == ECPRI_MSG_TYPE_7_FAULT_INDICATION && !((fault_notif <= ECPRI_MSG_TYPE_7_FAULTS_MAX) || (fault_notif >= ECPRI_MSG_TYPE_7_VENDOR_MIN && fault_notif <= ECPRI_MSG_TYPE_7_VENDOR_MAX))) - { - expert_add_info_format(pinfo, ti_fault_notif, &ei_fault_notif, "Only Faults are permitted with Event Type Faults Indication (0x%.2X)", event_type); - } - else if (event_type == ECPRI_MSG_TYPE_7_NOTIF_INDICATION && !((fault_notif >= ECPRI_MSG_TYPE_7_NOTIF_MIN && fault_notif <= ECPRI_MSG_TYPE_7_NOTIF_MAX) || (fault_notif >= ECPRI_MSG_TYPE_7_VENDOR_MIN && fault_notif <= ECPRI_MSG_TYPE_7_VENDOR_MAX))) - { - expert_add_info_format(pinfo, ti_fault_notif, &ei_fault_notif, "Only Notifications are permitted with Event Type Notifications Indication (0x%.2X)", event_type); - } - offset += 2; - proto_tree_add_item(element_tree, hf_add_info, tvb, offset, 4, ENC_BIG_ENDIAN); - offset += 4; - } + proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH, ENC_NA); + offset += payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH; } - else if (payload_size < ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH + num_faults_notif * ECPRI_MSG_TYPE_7_ELEMENT_SIZE) + else if (data_length < (guint32)(payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH)) { - expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d is maybe too big", num_faults_notif); - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size is maybe too small"); + expert_add_info_format(pinfo, ti_data_length, &ei_data_length, "Data Length %d is too small, should be %d", data_length, payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH); } else { - expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d is maybe too small", num_faults_notif); - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size is maybe too big"); + expert_add_info_format(pinfo, ti_data_length, &ei_data_length, "Data Length %d is too big, should be %d", data_length, payload_size - ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH); + } + } + } + } + else + { + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_4_PAYLOAD_MIN_LENGTH); + } + break; + case ECPRI_MT_1WAY_DELAY: + /* 3.2.4.6 One-way Delay Measurement */ + if (payload_size >= ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH) + { + if (remaining_length >= ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_measurement_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item_ret_uint(payload_tree, hf_action_type, tvb, offset, 1, ENC_NA, &action_type); + offset += 1; + /* Time Stamp for seconds and nano-seconds */ + timestamp_item = proto_tree_add_item(payload_tree, hf_timestamp, tvb, offset, 10, ENC_NA); + timestamp_tree = proto_item_add_subtree(timestamp_item, ett_ecpri_timestamp); + proto_tree_add_item_ret_uint64(timestamp_tree, hf_timestamp_sec, tvb, offset, 6, ENC_BIG_ENDIAN, &time_stamp_s); + offset += 6; + proto_tree_add_item_ret_uint(timestamp_tree, hf_timestamp_nanosec, tvb, offset, 4, ENC_BIG_ENDIAN, &time_stamp_ns); + offset += 4; + if (action_type >= ECPRI_MSG_TYPE_5_RESERVED_MIN) + { + expert_add_info_format(pinfo, timestamp_item, &ei_time_stamp, "Time stamp is not defined for Action Type %d", action_type); + } + else if (action_type != ECPRI_MSG_TYPE_5_REQ && action_type != ECPRI_MSG_TYPE_5_RESPONSE && action_type != ECPRI_MSG_TYPE_5_FOLLOWUP && time_stamp_s != 0x0000000000000000 && time_stamp_ns != 0x00000000) + { + expert_add_info_format(pinfo, timestamp_item, &ei_time_stamp, "Time stamp is not defined for Action Type %d, should be 0", action_type); + } + ti_comp_val = proto_tree_add_item_ret_uint64(payload_tree, hf_compensation_value, tvb, offset, 8, ENC_BIG_ENDIAN, &comp_val); + proto_item_append_text(ti_comp_val, " = %fns", comp_val / 65536.0); + + if (action_type >= ECPRI_MSG_TYPE_5_RESERVED_MIN) + { + expert_add_info_format(pinfo, timestamp_item, &ei_time_stamp, "Compensation Value is not defined for Action Type %d", action_type); + } + else if (action_type != ECPRI_MSG_TYPE_5_REQ && action_type != ECPRI_MSG_TYPE_5_RESPONSE && action_type != ECPRI_MSG_TYPE_5_FOLLOWUP && comp_val != 0x0000000000000000) + { + expert_add_info_format(pinfo, ti_comp_val, &ei_comp_val, "Compensation Value is not defined for Action Type %d, should be 0", action_type); + } + offset += 8; + remaining_length -= ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH; + if (remaining_length >= payload_size - ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH, ENC_NA); + offset += payload_size - ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH; + } + } + } + else + { + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_5_PAYLOAD_MIN_LENGTH); + } + break; + case ECPRI_MT_REM_RST: + /* Remote Reset */ + if (payload_size >= ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH) + { + if (remaining_length >= ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_reset_id, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(payload_tree, hf_reset_code, tvb, offset, 1, ENC_NA); + offset += 1; + remaining_length -= ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH; + if (remaining_length >= payload_size - ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_data, tvb, offset, payload_size - ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH, ENC_NA); + offset += payload_size - ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH; + } + } + } + else + { + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_6_PAYLOAD_MIN_LENGTH); + } + break; + case ECPRI_MT_EVT_IND: + /* Event Indication */ + if (payload_size >= ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH) + { + if (remaining_length >= ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH) + { + proto_tree_add_item(payload_tree, hf_event_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item_ret_uint(payload_tree, hf_event_type, tvb, offset, 1, ENC_NA, &event_type); + offset += 1; + proto_tree_add_item(payload_tree, hf_sequence_num, tvb, offset, 1, ENC_NA); + offset += 1; + ti_num_faults = proto_tree_add_item_ret_uint(payload_tree, hf_number_faults_notif, tvb, offset, 1, ENC_NA, &num_faults_notif); + offset += 1; + /* Only for Event Type Fault Indication (0x00) and Notification Indication (0x02) */ + if (event_type == ECPRI_MSG_TYPE_7_FAULT_INDICATION || event_type == ECPRI_MSG_TYPE_7_NOTIF_INDICATION) + { + /* These two Event Types should have notifications or faults */ + if (num_faults_notif > 0) + { + /* Check Size of Elements */ + if (payload_size == ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH + num_faults_notif * ECPRI_MSG_TYPE_7_ELEMENT_SIZE) + { + /* Dissect elements in loop */ + for (guint32 i = 0; i < num_faults_notif; i++) + { + element_item = proto_tree_add_item(payload_tree, hf_element, tvb, offset, ECPRI_MSG_TYPE_7_ELEMENT_SIZE, ENC_NA); + proto_item_prepend_text(element_item, "#%d: ", i + 1); + element_tree =proto_item_add_subtree(element_item, ett_ecpri_element); + + proto_tree_add_item(element_tree, hf_element_id2, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(element_tree, hf_raise_cease, tvb, offset, 1, ENC_NA); + ti_fault_notif = proto_tree_add_item_ret_uint(element_tree, hf_fault_notif, tvb, offset, 2, ENC_BIG_ENDIAN, &fault_notif); + /* Faults and Notifications cannot be mixed */ + if (event_type == ECPRI_MSG_TYPE_7_FAULT_INDICATION && !((fault_notif <= ECPRI_MSG_TYPE_7_FAULTS_MAX) || (fault_notif >= ECPRI_MSG_TYPE_7_VENDOR_MIN && fault_notif <= ECPRI_MSG_TYPE_7_VENDOR_MAX))) + { + expert_add_info_format(pinfo, ti_fault_notif, &ei_fault_notif, "Only Faults are permitted with Event Type Faults Indication (0x%.2X)", event_type); + } + else if (event_type == ECPRI_MSG_TYPE_7_NOTIF_INDICATION && !((fault_notif >= ECPRI_MSG_TYPE_7_NOTIF_MIN && fault_notif <= ECPRI_MSG_TYPE_7_NOTIF_MAX) || (fault_notif >= ECPRI_MSG_TYPE_7_VENDOR_MIN && fault_notif <= ECPRI_MSG_TYPE_7_VENDOR_MAX))) + { + expert_add_info_format(pinfo, ti_fault_notif, &ei_fault_notif, "Only Notifications are permitted with Event Type Notifications Indication (0x%.2X)", event_type); + } + offset += 2; + proto_tree_add_item(element_tree, hf_add_info, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + } + } + else if (payload_size < ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH + num_faults_notif * ECPRI_MSG_TYPE_7_ELEMENT_SIZE) + { + expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d is maybe too big", num_faults_notif); + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size is maybe too small"); + } + else + { + expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d is maybe too small", num_faults_notif); + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size is maybe too big"); + } + } + else + { + expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d should be > 0", num_faults_notif); + } + } + else if (event_type == ECPRI_MSG_TYPE_7_FAULT_INDICATION_ACK || event_type == ECPRI_MSG_TYPE_7_SYNC_REQUEST || event_type == ECPRI_MSG_TYPE_7_SYNC_ACK || event_type == ECPRI_MSG_TYPE_7_SYNC_END_INDICATION) + { + /* Number of Faults/Notifs should be 0, only 4 Byte possible*/ + if (payload_size > 4) + { + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d should be 4", payload_size); + } + /* These Event Types shouldn't have faults or notifications */ + if (num_faults_notif != 0) + { + expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d should be 0", num_faults_notif); } } else { - expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d should be > 0", num_faults_notif); - } - } - else if (event_type == ECPRI_MSG_TYPE_7_FAULT_INDICATION_ACK || event_type == ECPRI_MSG_TYPE_7_SYNC_REQUEST || event_type == ECPRI_MSG_TYPE_7_SYNC_ACK || event_type == ECPRI_MSG_TYPE_7_SYNC_END_INDICATION) - { - /* Number of Faults/Notifs should be 0, only 4 Byte possible*/ - if (payload_size > 4) - { - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d should be 4", payload_size); - } - /* These Event Types shouldn't have faults or notifications */ - if (num_faults_notif != 0) - { - expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d should be 0", num_faults_notif); - } - } - else - { - /* These Event Types are reserved, don't know how to decode */ - if (num_faults_notif != 0) - { - expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d, but no knowledge about encoding, because Event Type is reserved.", num_faults_notif); + /* These Event Types are reserved, don't know how to decode */ + if (num_faults_notif != 0) + { + expert_add_info_format(pinfo, ti_num_faults, &ei_number_faults, "Number of Faults/Notif %d, but no knowledge about encoding, because Event Type is reserved.", num_faults_notif); + } } } } + else + { + /* Minimal Length is bigger then actual Payload Size */ + expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH); + } + break; + case ECPRI_MT_IWF_STARTUP: + /* 3.2.4.9 IWF Start-Up */ + case ECRPI_MT_IWF_OP: + /* 3.2.4.10 IWF Operation */ + case ECRPI_MT_IWF_MAPPING: + /* 3.2.4.11 IWF Mapping */ + case ECRPI_MT_IWF_DELAY_CONTROL: + /* 3.2.4.12 IWF Delay Control */ + proto_tree_add_expert(payload_tree, pinfo, &ei_ecpri_not_dis_yet, tvb, offset, -1); + break; + + default: + /* Reserved or Vendor Specific */ + break; } - else - { - /* Minimal Length is bigger then actual Payload Size */ - expert_add_info_format(pinfo, ti_payload_size, &ei_payload_size, "Payload Size %d is too small for encoding Message Type %d. Should be min. %d", payload_size, msg_type, ECPRI_MSG_TYPE_7_PAYLOAD_MIN_LENGTH); - } - break; - case 8: - /* IWF Start-Up 3.2.4.9 */ - case 9: - /* IWF Operation 3.2.4.10 */ - case 10: - /* IWF Mapping 3.2.4.11 */ - case 11: - /* IWF Delay Control 3.2.4.12 */ - proto_tree_add_expert(payload_tree, pinfo, &ei_ecpri_not_dis_yet, tvb, offset, -1); - break; - default: - /* Reserved or Vendor Specific */ - break; } } /* If Preference not chosen, Payload will be not decoded */ diff --git a/epan/dissectors/packet-oran.c b/epan/dissectors/packet-oran.c new file mode 100755 index 0000000000..471f7595ab --- /dev/null +++ b/epan/dissectors/packet-oran.c @@ -0,0 +1,1707 @@ +/* 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 + * 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. + */ + +#include + +#include +#include +#include +#include + +/* 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_cu_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_udCompHdrIqWidth = -1; +static int hf_oran_udCompHdrMeth = -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_frameStructure_u = -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 = -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_txopSfnSfEnd = -1; +static int hf_oran_lbtMode = -1; +static int hf_oran_sfnSfEnd = -1; +static int hf_oran_lbtResult = -1; +static int hf_oran_lteTxopSymbols = -1; +static int hf_oran_initialPartialSF = -1; +static int hf_oran_reserved = -1; +/* static int hf_oran_bfwCompParam = -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_iSample = -1; +static int hf_oran_qSample = -1; + +static int hf_oran_rsvd4 = -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; + +/* 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 = -1; + + +static guint sample_bit_width_uplink = 14; +static guint sample_bit_width_downlink = 14; + +/* These are the message types handled by this dissector */ +#define ECPRI_MT_IQ_DATA 0 +#define ECPRI_MT_RT_CTRL_DATA 2 + + +#define COMP_NONE 0 +#define COMP_BLOCK_FP 1 +#define COMP_BLOCK_SCALE 2 +#define COMP_U_LAW 3 +#define COMP_MODULATION 4 + +static gint iqCompressionUplink = COMP_BLOCK_FP; +static gint iqCompressionDownlink = COMP_BLOCK_FP; +static gboolean includeUdCompHeaderUplink = FALSE; +static gboolean includeUdCompHeaderDownlink = FALSE; + +static guint num_bf_weights = 1; + +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 }, + { 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[] = { + { DIR_UPLINK, "Uplink" }, + { DIR_DOWNLINK, "Downlink" }, + { 0, NULL} +}; + +static const value_string rb[] = { + { 0, "Every RB used" }, + { 1, "Every other RB used" }, + { 0, NULL} +}; + +static const value_string sym_inc[] = { + { 0, "Use the current symbol number" }, + { 1, "Increment the current symbol number" }, + { 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, 15, "Reserved"}, + {0, 0, NULL} +}; + +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 +}; + +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"}, + {8, 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)" }, + { 8, 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[] = { + {0, 0, "No compression" }, + {1, 1, "Block floating point compression" }, + {2, 2, "Block scaling" }, + {3, 3, "Mu - law" }, + {4, 4, "Modulation compression" }, + {5, 15, "Reserved"}, + {0, 0, NULL} +}; + +static const range_string frame_structure_fft[] = { + {0, 0, "Reserved(no FFT / iFFT processing)"}, + {1, 7, "Reserved"}, + {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 128"}, + {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 - CU to RU request to obtain a PDSCH channel"}, + {1, 1, "LBT_DRS_REQ - lls - CU to RU request to obtain the channel and send DRS"}, + {2, 2, "LBT_PDSCH_RSP - RU to lls - CU response, channel acq success or failure"}, + {3, 3, "LBT_DRS_RSP - RU to lls - CU response, DRS sending success or failure"}, + {4, 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"}, + {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"}, + {15, "I and Q are 15 bits wide"}, + {0, NULL} +}; + +static const value_string bfw_comp_headers_comp_meth[] = { + {0, "no compression"}, + {1, "block floating point"}, + {2, "block scaling"}, + {3, "u-law"}, + {4, "beamspace compression"}, + {0, NULL} +}; + + +#if 0 +static const range_string bfw_comp_parms[] = { + {0, 0, NULL} +}; +static const range_string udCompParams[] = { + {0, 0, NULL} +}; +#endif + + /* 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 + static char info_buffer[MAX_INFO_BUFFER]; + va_list ap; + + if ((ti1 == NULL) && (ti2 == NULL) && (pinfo == NULL)) { + return; + } + + va_start(ap, format); + g_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); + } +} + +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) +{ + switch (num_prbx) { + case 0: + write_pdu_label_and_info(section_heading, protocol_item, pinfo, ", Id: %d (all PRBs"); + break; + case 1: + write_pdu_label_and_info(section_heading, protocol_item, pinfo, ", Id: %d (PRB: %d)", section_id, start_prbx); + break; + default: + write_pdu_label_and_info(section_heading, protocol_item, pinfo, ", Id: %d (PRB: %d-%d)", section_id, start_prbx, start_prbx + num_prbx - 1); + } +} + +static void +addPcOrRtcid(tvbuff_t *tvb, proto_tree *tree, gint *offset, const char *name) +{ + proto_item *item; + proto_tree *oran_pcid_tree = proto_tree_add_subtree(tree, tvb, *offset, 2, ett_oran_ecpri_pcid, &item, name); + guint32 cuPortId, aCellId, ccId, ruPortId = 0; + gint id_offset = *offset; + + proto_tree_add_item_ret_uint(oran_pcid_tree, hf_oran_cu_port_id, tvb, *offset, 1, ENC_NA, &cuPortId); + proto_tree_add_item_ret_uint(oran_pcid_tree, hf_oran_bandsector_id, tvb, *offset, 1, ENC_NA, &aCellId); + *offset += 1; + proto_tree_add_item_ret_uint(oran_pcid_tree, hf_oran_cc_id, tvb, *offset, 1, ENC_NA, &ccId); + proto_tree_add_item_ret_uint(oran_pcid_tree, hf_oran_ru_port_id, tvb, *offset, 1, ENC_NA, &ruPortId); + *offset += 1; + + proto_item_append_text(item, " (CU_Port_ID: %d, A_Cell_ID: %d, CC_ID: %d, RU_Port_ID: %d)", cuPortId, aCellId, ccId, ruPortId); + char id[16]; + g_snprintf(id, 16, "%1x:%2.2x:%1x:%1x", cuPortId, aCellId, ccId, 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); +} + +static void +addSeqid(tvbuff_t *tvb, proto_tree *oran_tree, gint *offset) +{ + 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; + proto_tree_add_item_ret_uint(oran_seqid_tree, hf_oran_sequence_id, tvb, *offset, 1, ENC_NA, &seqId); + *offset += 1; + proto_tree_add_item_ret_uint(oran_seqid_tree, hf_oran_e_bit, tvb, *offset, 1, ENC_NA, &e); + 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); +} + +static float scale_to_float(guint32 h) +{ + gint16 i16 = h & 0x0000ffff; + return ((float)i16) / 0x7fff; +} + +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; + gboolean extension_flag = FALSE; + + /* sectionID */ + proto_tree_add_item_ret_uint(oran_tree, hf_oran_section_id, tvb, offset, 3, ENC_BIG_ENDIAN, §ionId); + /* rb */ + proto_tree_add_item(oran_tree, hf_oran_rb, tvb, offset, 3, ENC_NA); + /* symInc */ + proto_tree_add_item(oran_tree, hf_oran_symInc, tvb, offset, 3, ENC_NA); + /* startPrbc */ + guint32 startPrbc = 0; + proto_tree_add_item_ret_uint(oran_tree, hf_oran_startPrbc, tvb, offset, 3, ENC_BIG_ENDIAN, &startPrbc); + offset += 3; + /* numPrbc */ + guint32 numPrbc = 0; + proto_tree_add_item_ret_uint(oran_tree, hf_oran_numPrbc, tvb, offset, 1, ENC_NA, &numPrbc); + offset += 1; + /* reMask */ + proto_tree_add_item(oran_tree, hf_oran_reMask, tvb, offset, 2, ENC_BIG_ENDIAN); + /* numSymbol */ + guint32 numSymbol = 0; + proto_tree_add_item_ret_uint(oran_tree, hf_oran_numSymbol, tvb, offset, 2, ENC_NA, &numSymbol); + /* skip reserved */ + offset += 2; + + /* ef (extension flag) */ + switch (sectionType) { + case SEC_C_NORMAL: + case SEC_C_PRACH: + /* case SEC_C_UE_SCHED: */ + proto_tree_add_item_ret_boolean(oran_tree, hf_oran_ef, tvb, offset, 1, ENC_BIG_ENDIAN, &extension_flag); + break; + default: + break; + } + + guint32 beamId = 0; + + write_section_info(sectionHeading, pinfo, protocol_item, sectionId, startPrbc, numPrbc); + proto_item_append_text(sectionHeading, ", Symbols: %d", numSymbol); + + switch (sectionType) { + case SEC_C_UNUSED_RB: + proto_tree_add_item(oran_tree, hf_oran_rsvd16, tvb, offset, 2, ENC_NA); + break; + + case SEC_C_NORMAL: + 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: + { + proto_tree_add_item_ret_uint(oran_tree, hf_oran_beamId, tvb, offset, 2, ENC_BIG_ENDIAN, &beamId); + offset += 2; + + 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; + + 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; + } + + default: + break; + }; + + /* Section extension commands */ + while (extension_flag) { + + /* 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 */ + 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++; + + /* extLen (number of 32-bit words). + TODO: this field is 2 bytes when for Section Extension=11 + TODO: expert_info for value 0, which is reserved! + */ + guint32 extlen; + proto_item *extlen_ti = proto_tree_add_item_ret_uint(extension_tree, hf_oran_extlen, tvb, offset, 1, ENC_BIG_ENDIAN, &extlen); + proto_item_append_text(extlen_ti, " (%u bytes)", extlen*4); + offset++; + + switch (exttype) { + case 1: /* Beamforming Weights Extension type */ + { + /* bfwCompHdr (2 subheaders - bfwIqWidth and bfwCompMeth)*/ + guint32 bfwcomphdr_iq_width, bfwcomphdr_comp_meth; + proto_tree_add_item_ret_uint(extension_tree, hf_oran_bfwCompHdr_iqWidth, tvb, offset, 1, ENC_BIG_ENDIAN, &bfwcomphdr_iq_width); + proto_tree_add_item_ret_uint(extension_tree, hf_oran_bfwCompHdr_compMeth, tvb, offset, 1, ENC_BIG_ENDIAN, &bfwcomphdr_comp_meth); + offset++; + + /* Look up width of samples. */ + guint8 iq_width = 0; + switch (bfwcomphdr_iq_width) { + case 0: + iq_width = 16; + break; + case 1: + iq_width = 1; + break; + case 15: + iq_width = 15; + break; + default: + /* TODO: error!!!!! */ + break; + } + + /* bfwCompParam */ + switch (bfwcomphdr_comp_meth) { + case 0: /* no compression */ + /* absent */ + break; + case 1: /* block fl. point */ + case 2: /* block scaling */ + case 3: /* u-law */ + case 4: /* beamspace */ + default: + /* TODO: not handled */ + 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 + TODO: 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 / num_bf_weights; + gint bit_offset = offset*8; + for (guint n=0; n < num_trx; n++) { + /* Create 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 %u: (", n); + proto_tree *bfw_tree = proto_item_add_subtree(bfw_ti, ett_oran_bfw); + + /* Get these raw, cast them to float and add them as items instead... */ + for (guint m=0; m < num_bf_weights; m++) { + /* Get bits, and convert to float. */ + guint32 bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + gfloat value = scale_to_float(bits); + /* 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); + } + + /* Leave a gap between I and Q values */ + proto_item_append_text(bfw_ti, " "); + for (guint m=0; m < num_bf_weights; m++) { + /* Get bits, and convert to float. */ + guint32 bits = tvb_get_bits(tvb, bit_offset, iq_width, ENC_BIG_ENDIAN); + gfloat value = scale_to_float(bits); + /* 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); + } + + proto_item_append_text(bfw_ti, ")"); + proto_item_set_len(bfw_ti, (bit_offset+7)/8 - bfw_offset); + } + + /* pad */ + break; + } + default: + /* TODO: Support other extension types. */ + break; + } + + /* Set length of extension header. */ + proto_item_set_len(extension_ti, extlen*4); + proto_item_append_text(extension_ti, " (%s)", val_to_str_const(exttype, exttype_vals, "Unknown")); + } + + return offset; +} + + +/* Control plane dissector */ +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); + + addPcOrRtcid(tvb, oran_tree, &offset, "ecpriRtcid"); + addSeqid(tvb, oran_tree, &offset); + + proto_item *sectionHeading; + gint section_tree_offset = offset; + proto_tree *section_type_tree = proto_tree_add_subtree(oran_tree, tvb, offset, 2, ett_oran_section_type, §ionHeading, "C-Plane Section Type "); + + guint32 direction = 0; + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_data_direction, tvb, offset, 1, ENC_NA, &direction); + proto_tree_add_item(section_type_tree, hf_oran_payload_version, tvb, offset, 1, ENC_NA); + proto_tree_add_item(section_type_tree, hf_oran_filter_index, tvb, offset, 1, ENC_NA); + offset += 1; + + guint ref_a_offset = 0; + guint32 frameId = 0; + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_frame_id, tvb, offset, 1, ENC_NA, &frameId); + offset += 1; + + guint32 subframeId = 0; + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_subframe_id, tvb, offset, 2, ENC_NA, &subframeId); + guint32 slotId = 0; + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_slot_id, tvb, offset, 2, ENC_BIG_ENDIAN, &slotId); + guint32 startSymbolId = 0; + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_start_symbol_id, tvb, offset, 2, ENC_NA, &startSymbolId); + offset += 2; + + char id[16]; + g_snprintf(id, 16, "%d-%d-%d", frameId, subframeId, slotId); + proto_item *pi = proto_tree_add_string(section_type_tree, hf_oran_refa, tvb, ref_a_offset, 3, id); + PROTO_ITEM_SET_GENERATED(pi); + + guint32 nSections = 0; + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_numberOfSections, tvb, offset, 1, ENC_NA, &nSections); + offset += 1; + + guint32 sectionType = 0; + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_sectionType, tvb, offset, 1, ENC_NA, §ionType); + offset += 1; + + proto_item *iq_width_item = NULL; + guint bit_width = 0; + + guint32 scs, slots_per_subframe; + proto_item *ti; + + switch (sectionType) { + case SEC_C_UNUSED_RB: + + proto_tree_add_item(section_type_tree, hf_oran_timeOffset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + proto_tree_add_item(section_type_tree, hf_oran_frameStructure_fft, tvb, offset, 1, ENC_NA); + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_frameStructure_subcarrier_spacing, tvb, offset, 1, ENC_NA, &scs); + /* slots_per_subframe = 1 << scs; */ + offset += 1; + + proto_tree_add_item(section_type_tree, hf_oran_cpLength, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + proto_tree_add_item(section_type_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + break; + + case SEC_C_NORMAL: + iq_width_item = proto_tree_add_item_ret_uint(section_type_tree, hf_oran_udCompHdrIqWidth , tvb, offset, 1, ENC_NA, &bit_width); + proto_item_append_text(iq_width_item, " (%d bits)", bit_width == 0 ? 16 : bit_width); + + proto_tree_add_item(section_type_tree, hf_oran_udCompHdrMeth, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(section_type_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + break; + + case SEC_C_PRACH: + proto_tree_add_item(section_type_tree, hf_oran_timeOffset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + proto_tree_add_item(section_type_tree, hf_oran_frameStructure_fft, tvb, offset, 1, ENC_NA); + proto_tree_add_item_ret_uint(section_type_tree, hf_oran_frameStructure_subcarrier_spacing, tvb, offset, 1, ENC_NA, &scs); + slots_per_subframe = 1 << scs; + ti = proto_tree_add_uint(section_type_tree, hf_oran_slot_within_frame, tvb, 0, 0, (slots_per_subframe*subframeId) + slotId); + PROTO_ITEM_SET_GENERATED(ti); + offset += 1; + + proto_tree_add_item(section_type_tree, hf_oran_cpLength, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + iq_width_item = proto_tree_add_item_ret_uint(section_type_tree, hf_oran_udCompHdrIqWidth, tvb, offset, 1, ENC_NA, &bit_width); + proto_item_append_text(iq_width_item, " (%d bits)", bit_width + 1); + + proto_tree_add_item(section_type_tree, hf_oran_udCompHdrMeth, tvb, offset, 1, ENC_NA); + offset += 1; + break; + + default: + break; + }; + + /* Set actual length of section. */ + proto_item_set_len(section_type_tree, offset - section_tree_offset); + + proto_item_append_text(sectionHeading, "%d, %s, Frame: %d, Subframe: %d, Slot: %d, StartSymbol: %d", + sectionType, val_to_str(direction, data_direction, "Unknown"), frameId, subframeId, slotId, startSymbolId); + write_pdu_label_and_info(protocol_item, NULL, pinfo, ", Type: %d %s", sectionType, rval_to_str(sectionType, section_types_short, "Unknown")); + + 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); + } + + return tvb_captured_length(tvb); +} + +/* User plane dissector */ +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); + + addPcOrRtcid(tvb, oran_tree, &offset, "ecpriPcid"); + addSeqid(tvb, oran_tree, &offset); + + proto_item *timingHeader; + + proto_tree *timing_header_tree = proto_tree_add_subtree(oran_tree, tvb, offset, 4, ett_oran_u_timing, &timingHeader, "Timing header"); + guint32 direction; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_data_direction, tvb, offset, 1, ENC_NA, &direction); + proto_tree_add_item(timing_header_tree, hf_oran_payload_version, tvb, offset, 1, ENC_NA); + proto_tree_add_item(timing_header_tree, hf_oran_filter_index, tvb, offset, 1, ENC_NA); + offset += 1; + + gint ref_a_offset = offset; + guint32 frameId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_frame_id, tvb, offset, 1, ENC_NA, &frameId); + offset += 1; + + guint32 subframeId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_subframe_id, tvb, offset, 2, ENC_NA, &subframeId); + guint32 slotId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_slot_id, tvb, offset, 2, ENC_BIG_ENDIAN, &slotId); + guint32 startSymbolId = 0; + proto_tree_add_item_ret_uint(timing_header_tree, hf_oran_start_symbol_id, tvb, offset, 2, ENC_NA, &startSymbolId); + offset += 2; + + char id[16]; + g_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, StartSymbol: %d", + val_to_str(direction, data_direction, "Unknown"), frameId, subframeId, slotId, startSymbolId); + + guint sample_bit_width; + gint compression; + gboolean includeUdCompHeader; + + if (direction == DIR_UPLINK) { + sample_bit_width = sample_bit_width_uplink; + compression = iqCompressionUplink; + includeUdCompHeader = includeUdCompHeaderUplink; + } else { + sample_bit_width = sample_bit_width_downlink; + compression = iqCompressionDownlink; + includeUdCompHeader = includeUdCompHeaderDownlink; + } + + guint nBytesForSamples = (sample_bit_width * 12 * 2) / 8; + guint nBytesPerPrb = nBytesForSamples; + if (compression != COMP_NONE) + nBytesPerPrb++; /* 1 extra byte reserved/exponent */ + guint bytesLeft; + + guint number_of_sections = 0; + do { + proto_item *sectionHeading; + proto_tree *section_tree = proto_tree_add_subtree(oran_tree, tvb, offset, 2, ett_oran_u_section, §ionHeading, "Section"); + + guint32 sectionId = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_section_id, tvb, offset, 3, ENC_BIG_ENDIAN, §ionId); + proto_tree_add_item(section_tree, hf_oran_rb, tvb, offset, 3, ENC_NA); + proto_tree_add_item(section_tree, hf_oran_symInc, tvb, offset, 3, ENC_NA); + guint32 startPrbu = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_startPrbu, tvb, offset, 3, ENC_BIG_ENDIAN, &startPrbu); + offset += 3; + + guint32 numPrbu = 0; + proto_tree_add_item_ret_uint(section_tree, hf_oran_numPrbu, tvb, offset, 1, ENC_NA, &numPrbu); + offset += 1; + + if (includeUdCompHeader) { + proto_tree_add_item(section_tree, hf_oran_udCompHdrMeth, tvb, offset, 1, ENC_NA); + proto_tree_add_item(section_tree, hf_oran_udCompHdrIqWidth, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(section_tree, hf_oran_rsvd8, tvb, offset, 1, ENC_NA); + offset += 1; + } + + write_section_info(sectionHeading, pinfo, protocol_item, sectionId, startPrbu, numPrbu); + + for (guint i = 0; i < numPrbu; ++i) { + proto_item *prbHeading; + proto_tree *rb_tree = proto_tree_add_subtree(section_tree, tvb, offset, nBytesPerPrb, ett_oran_u_prb, &prbHeading, "PRB"); + if (compression != COMP_NONE) { + proto_tree_add_item(rb_tree, hf_oran_rsvd4, tvb, offset, 1, ENC_NA); + proto_tree_add_item(rb_tree, hf_oran_exponent, tvb, offset, 1, ENC_NA); + offset += 1; + } + + /* FIXME - add udCompParam for COMP_NONE or COMP_MODULATION, figure out correct length + Maybe even decode the samples themselves. + */ + + proto_tree_add_item(rb_tree, hf_oran_iq_user_data, tvb, offset, nBytesForSamples, ENC_NA); + offset += nBytesForSamples; + + proto_item_set_len(sectionHeading, nBytesPerPrb * numPrbu + 4); /* 4 bytes for section header */ + proto_item_append_text(prbHeading, " %d", startPrbu + i); + } + bytesLeft = tvb_captured_length(tvb) - offset; + number_of_sections++; + } while (bytesLeft > 4 + nBytesPerPrb); /* FIXME: bad heuristic */ + + proto_item *ti = proto_tree_add_uint(oran_tree, hf_oran_numberOfSections, tvb, 0, 0, number_of_sections); + PROTO_ITEM_SET_GENERATED(ti); + + return tvb_captured_length(tvb); +} + +static int +dissect_oran(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + 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: + return 0; + } +} + +/* Register the protocol with Wireshark. */ +void +proto_register_oran(void) +{ + /* Setup list of header fields See Section 1.5 of README.dissector for + * details. */ + static hf_register_info hf[] = { + + /* Section 3.1.2.1.6 */ + { &hf_oran_cu_port_id, + { "CU Port ID", "oran_fh_cus.cu_port_id", + FT_UINT8, BASE_DEC, + NULL, 0xc0, + NULL, HFILL } + }, + + /* Section 3.1.2.1.6 */ + { &hf_oran_bandsector_id, + { "BandSector ID", "oran_fh_cus.bandsector_id", + FT_UINT8, BASE_DEC, + NULL, 0x3f, + NULL, HFILL } + }, + + /* Section 3.1.2.1.6 */ + { &hf_oran_cc_id, + { "CC ID", "oran_fh_cus.cc_id", + FT_UINT8, BASE_DEC, + NULL, 0xf0, + NULL, HFILL } + }, + + /* Section 3.1.2.1.6 */ + { &hf_oran_ru_port_id, + { "RU Port ID", "oran_fh_cus.ru_port_id", + FT_UINT8, BASE_DEC, + NULL, 0x0f, + NULL, HFILL } + }, + + /* Section 3.1.2.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.2.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 indi" + "cate the last message of a subsequence.", + HFILL } + }, + + /* Section 3.1.2.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), 0x80, + "This parameter indicates 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, + "This parameter defines the 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, + "This parameter defines 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, + "This parameter is 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_UINT16, BASE_DEC, + NULL, 0xf000, + "This parameter is 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, + "This parameter is the 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_UINT16, BASE_DEC, + NULL, 0x003f, + "This parameter identifies 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, + "This parameter indicates 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, + "This parameter determines the characteristics of U-plane data to " + "be transferred or received from a beam with one pattern id.", + HFILL}}, + + /* Section 5.4.4.11 */ + {&hf_oran_numberOfUEs, + {"Number Of UEs", "oran_fh_cus.numberOfUEs", + FT_UINT8, BASE_DEC, + NULL, 0x00, + "This parameter 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, + "This parameter defines 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 5.4.4.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 5.4.4.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 5.4.4.14 */ + {&hf_oran_cpLength, + {"CP Length", "oran_fh_cus.cpLength", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "This parameter defines the length CP_length of the Cyclic Prefix " + "(CP) as follows, based on Ts (=1/30.72MHz as specified in 3GPP " + "TS38.211 section 4.1) and \u03bc as defined inTable 16. (\"NA\" for \u03bc " + "shall be replaced by \"0\" in the following:) CP_length = cpLength " + "* Ts * 2-\u03bc", + HFILL}}, + + /* Section 5.4.5.1 */ + {&hf_oran_section_id, + {"Section ID", "oran_fh_cus.sectionId", + FT_UINT24, BASE_DEC, + NULL, 0xfff000, + "This parameter identifies individual sections within the C-Plane " + "message. The purpose of section ID is mapping of U-Plane messages " + "to the corresponding C-Plane message (and Section Type) associated " + "with the data. Two C-Plane sections with same Section ID " + "may be combined and mapped to a common section in a corresponding " + "U-Plane message containing a combined payload for both sections " + "(e.g., for supporting mixed CSI RS and PDSCH). This case is " + "applicable when usage of reMask is complimentary (or orthogonal) " + "and different beam directions (i.e. beamIds) are given the resource " + "elements. NOTE: In case of two sections with same Section ID " + "are combined, both sections shall have same rb, startPrbc, numPrbc " + "and numSymbol IE fields' content.", + HFILL}}, + + /* Section 5.4.5.2 */ + {&hf_oran_rb, + {"RB Indicator", "oran_fh_cus.rb", + FT_UINT24, BASE_DEC, + VALS(rb), 0x00800, + "This parameter is used to indicate if every RB is used or every " + "other RB is used. The starting RB is defined by startPrbc and " + "total number of used RBs is defined by numPrbc. Example: RB=1, " + "startPrb=1, numPrb=3, then the PRBs used are 1, 3, and 5.", + HFILL}}, + + /* Section 5.4.5.3 */ + {&hf_oran_symInc, + {"Symbol Number Increment Command", "oran_fh_cus.symInc", + FT_UINT24, BASE_DEC, + VALS(sym_inc), 0x00400, + "This parameter is used to indicate which symbol number is relevant " + "to the given sectionId. It is expected that for each C-Plane " + "message a symbol number is maintained and starts with the value " + "of startSymbolid. The same value is used for each section in " + "the message as long as symInc is zero. When symInc is one, the " + "maintained symbol number should be incremented by one, and that " + "new symbol number should be used for that section and each subsequent " + "section until the symInc bit is again detected to be one. " + "In this manner, multiple symbols may be handled by a single C-Plane " + "message.", + HFILL}}, + + /* Section 5.4.5.4 */ + {&hf_oran_startPrbc, + {"Starting PRB of Control Plane Section", "oran_fh_cus.startPrbc", + FT_UINT24, BASE_DEC, + NULL, 0x0003ff, + "This parameter is the starting PRB of a control section. For one " + "C-Plane message, there may be multiple U-Plane messages associated " + "with it and requiring defining from which PRB the control " + "commands are applicable.", + HFILL}}, + + /* Section 5.4.5.5 */ + {&hf_oran_reMask, + {"RE Mask", "oran_fh_cus.reMask", + FT_UINT16, BASE_HEX, + NULL, 0xfff0, + "This parameter defines 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 5.4.5.6 */ + {&hf_oran_numPrbc, + {"Number of Contiguous PRBs per Control Section", "oran_fh_cus.numPrbc", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "This parameter defines the PRBs where the control section is valid.", + HFILL}}, + + /* Section 5.4.5.7 */ + {&hf_oran_numSymbol, + {"Number of Symbols", "oran_fh_cus.numSymbol", + FT_UINT16, BASE_DEC, + NULL, 0x000f, + "This parameter 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 5.4.5.8 */ + {&hf_oran_ef, + {"Extension Flag", "oran_fh_cus.ef", + FT_BOOLEAN, 8, + NULL, 0x80, + "This parameter is 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 5.4.5.9 */ + {&hf_oran_beamId, + {"Beam ID", "oran_fh_cus.beamId", + FT_UINT16, BASE_DEC, + NULL, 0x7fff, + "This parameter 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.7 */ + {&hf_oran_extension, + {"extension", "oran_fh_cus.extension", + FT_STRING, BASE_NONE, + NULL, 0x0, + NULL, + HFILL}}, + + /* Section 5.4.7 */ + {&hf_oran_exttype, + {"extType", "oran_fh_cus.extType", + FT_UINT8, BASE_DEC, + VALS(exttype_vals), 0x7f, + NULL, + HFILL}}, + + /* Section 5.4.7 */ + {&hf_oran_extlen, + {"extLen", "oran_fh_cus.extLen", + FT_UINT8, 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_i, + {"bfwI", "oran_fh_cus.bfwI", + FT_FLOAT, BASE_NONE, + NULL, 0x0, + "This parameter is the 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, + "This parameter is the 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 5.4.5.10 */ + {&hf_oran_ueId, + {"UE ID", "oran_fh_cus.ueId", + FT_UINT16, BASE_HEX, + NULL, 0x0, + "This parameter provides a 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 5.4.5.11 */ + {&hf_oran_freqOffset, + {"Frequency Offset", "oran_fh_cus.freqOffset", + FT_UINT24, BASE_DEC, + NULL, 0x0, + "This parameter defines 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 5.4.5.12 */ + {&hf_oran_regularizationFactor, + {"Regularization Factor", "oran_fh_cus.regularizationFactor", + FT_INT16, BASE_DEC, + NULL, 0x0, + "This parameter 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 5.4.5.14 */ + {&hf_oran_laaMsgType, + {"LAA Message Type", "oran_fh_cus.laaMsgType", + FT_UINT8, BASE_DEC | BASE_RANGE_STRING, + RVALS(laaMsgTypes), 0xf0, + "This parameter 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 5.4.5.15 */ + {&hf_oran_laaMsgLen, + {"LAA Message Length", "oran_fh_cus.laaMsgLen", + FT_UINT8, BASE_DEC, + NULL, 0x0f, + "This parameter 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 5.4.5.16 */ + {&hf_oran_lbtHandle, + {"LBT Handle", "oran_fh_cus.lbtHandle", + FT_UINT16, BASE_HEX, + NULL, 0x0, + "This parameter 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 5.4.5.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 5.4.5.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 5.4.5.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 5.4.5.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 5.4.5.21 */ + {&hf_oran_txopSfnSfEnd, + {"TXOP SFN/SF End", "oran_fh_cus.txopSfnSfEnd", + FT_UINT16, BASE_DEC, + NULL, 0x0fff, + "SFN/SF by which the TXOP must end", + HFILL}}, + + /* Section 5.4.5.22 */ + {&hf_oran_lbtMode, + {"LBT Mode", "oran_fh_cus.lbtMode", + FT_UINT8, BASE_DEC, + NULL, 0x20, + "Part of multi-carrier support. Indicates whether full LBT process " + "is carried or partial LBT process is carried (multi carrier mode " + "B according to 3GPP TS 36.213 Section 15.1.5.2). 0 - full LBT " + "(regular LBT). 1 - Partial LBT (looking back 25usec prior to " + "transmission as indicated in 3GPP TS 36.213 section 15.1.5.2)", + HFILL}}, + + /* Section 5.4.5.23 */ + {&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 5.4.5.24 */ + {&hf_oran_lbtResult, + {"LBT Result", "oran_fh_cus.lbtResult", + FT_UINT8, BASE_DEC, + NULL, 0x80, + "LBT result of SFN/SF. 0 - SUCCESS - indicates that the channel was " + "successfully acquired. 1 - FAILURE - indicates failure to " + "acquire the channel by the end of SFN/SF", + HFILL}}, + + /* Section 5.4.5.25 */ + {&hf_oran_lteTxopSymbols, + {"LTE TXOP Symbols", "oran_fh_cus.lteTxopSymbols", + FT_UINT16, BASE_DEC, + NULL, 0x3fff, + "Actual LTE TXOP in symbols. Valid when LBT result = SUCCESS.", + HFILL}}, + + /* Section 5.4.5.26 */ + {&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 5.4.5.27 */ + {&hf_oran_reserved, + {"reserved for future use", "oran_fh_cus.reserved", + FT_UINT16, BASE_HEX, + NULL, 0x7fff, + "This parameter is reserved for future use. Transmitter shall send " + "value \"0\", while receiver shall ignore the value received.", + 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, + "This parameter 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, + "This parameter 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}}, + +#if 0 + /* FIXME Section 5.4.7.1.2 */ + { &hf_oran_bfwCompParam. + { "beamforming weight compression parameter", "oran_fh_cus.bfwCompParam", + various, | BASE_RANGE_STRING, + RVALS(bfw_comp_parms), 0x0, + "This parameter applies to the compression method specified by th" + "e associated sectionID's bfwCompMeth value.", + HFILL } }, +#endif + + /* Section 6.3.3.7 */ + {&hf_oran_symbolId, + {"Symbol Identifier", "oran_fh_cus.symbolId", + FT_UINT8, BASE_HEX, + NULL, 0x3f, + "This parameter identifies a symbol number within a slot", + HFILL}}, + + /* Section 6.3.3.11 */ + {&hf_oran_startPrbu, + {"Starting PRB of User Plane Section", "oran_fh_cus.startPrbu", + FT_UINT24, BASE_DEC, + NULL, 0x0003ff, + "This parameter is the starting PRB of a user plane section. For " + "one C-Plane message, there may be multiple U-Plane messages " + "associated with it and requiring defining from which PRB the contained " + "IQ data are applicable.", + HFILL}}, + + /* Section 6.3.3.12 */ + {&hf_oran_numPrbu, + {"Number of PRBs per User Plane Section", "oran_fh_cus.numPrbu", + FT_UINT8, BASE_DEC, + NULL, 0x0, + "This parameter defines the PRBs where the user plane section is " + "valid.", + HFILL}}, + + /* Section 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, + "This parameter defines the compression method for " + "the user data in every section in the C-Plane message.", + HFILL}}, + + /* Section 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, + "This parameter 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, + "This parameter applies to whatever compression method is specified " + "by the associated sectionID's compMeth value.", + HFILL}}, +#endif + + /* Section 6.3.3.15 */ + {&hf_oran_iSample, + {"In-phase Sample", "oran_fh_cus.iSample", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "This parameter is the In-phase sample value", + HFILL}}, + + /* Section 6.3.3.16 */ + {&hf_oran_qSample, + {"Quadrature Sample", "oran_fh_cus.qSample", + FT_UINT16, BASE_DEC, + NULL, 0x0, + "This parameter is the Quadrature sample value.", + HFILL}}, + + { &hf_oran_rsvd4, + { "Reserved", "oran_fh_cus.reserved4", + FT_UINT8, BASE_DEC, + NULL, 0xf0, + "Reserved for future use", HFILL } }, + + { &hf_oran_rsvd8, + { "Reserved", "oran_fh_cus.reserved8", + FT_UINT8, BASE_DEC, + NULL, 0x00, + "Reserved for future use", HFILL } }, + + { &hf_oran_rsvd16, + { "Reserved", "oran_fh_cus.reserved16", + FT_UINT16, BASE_DEC, + NULL, 0x00, + "Reserved for future use", HFILL } }, + + { &hf_oran_exponent, + { "Exponent", "oran_fh_cus.exponent", + FT_UINT8, BASE_DEC, + NULL, 0x0f, + "This parameter 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, + "This parameter is 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, STR_ASCII, + 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, STR_ASCII, + NULL, 0x0, + "This is a calculated field for the RefA ID, which provides a " + "reference in time.", + 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 + }; + + /* 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)); + + 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.iq_bitwidth_up", "IQ Bitwidth Uplink", + "The bit width of a sample in the Uplink", 10, &sample_bit_width_uplink); + prefs_register_enum_preference(oran_module, "oran.ud_comp_up", "Uplink User Data Compression", + "Uplink User Data Compression", &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.", &includeUdCompHeaderUplink); + + prefs_register_uint_preference(oran_module, "oran.iq_bitwidth_down", "IQ Bitwidth Downlink", + "The bit width of a sample in the Downlink", 10, &sample_bit_width_downlink); + prefs_register_enum_preference(oran_module, "oran.ud_comp_down", "Downlink User Data Compression", + "Downlink User Data Compression", &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.", &includeUdCompHeaderDownlink); + + prefs_register_uint_preference(oran_module, "oran.num_bf_weights", "Number of BF Weights per Antenna", + "Number of BF Weights per Antenna - should be signalled over M-Plane", 10, &num_bf_weights); +} + +/* 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) +{ + create_dissector_handle(dissect_oran, proto_oran); +} + +/* +* 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: +*/