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-lbtrm.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-lbtrm.c')
-rw-r--r-- | epan/dissectors/packet-lbtrm.c | 1919 |
1 files changed, 1919 insertions, 0 deletions
diff --git a/epan/dissectors/packet-lbtrm.c b/epan/dissectors/packet-lbtrm.c new file mode 100644 index 0000000..633be10 --- /dev/null +++ b/epan/dissectors/packet-lbtrm.c @@ -0,0 +1,1919 @@ +/* packet-lbtrm.c + * Routines for LBT-RM Packet dissection + * + * Copyright (c) 2005-2014 Informatica Corporation. All Rights Reserved. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/expert.h> +#include <epan/uat.h> +#include <epan/tap.h> +#include <epan/conversation.h> +#include <epan/to_str.h> +#include <wsutil/pint.h> +#include "packet-lbm.h" +#include "packet-lbtrm.h" + +void proto_register_lbtrm(void); +void proto_reg_handoff_lbtrm(void); + +/* Protocol handle */ +static int proto_lbtrm = -1; + +/* Dissector handle */ +static dissector_handle_t lbtrm_dissector_handle; + +/* Tap handle */ +static int lbtrm_tap_handle = -1; + +/*----------------------------------------------------------------------------*/ +/* LBT-RM transport management. */ +/*----------------------------------------------------------------------------*/ + +static const address lbtrm_null_address = ADDRESS_INIT_NONE; + +static lbtrm_transport_t * lbtrm_transport_unicast_find(const address * source_address, guint16 source_port, guint32 session_id, guint32 frame) +{ + lbtrm_transport_t * transport = NULL; + conversation_t * conv = NULL; + wmem_tree_t * session_tree = NULL; + + conv = find_conversation(frame, source_address, &lbtrm_null_address, CONVERSATION_UDP, source_port, 0, 0); + if (conv != NULL) + { + if (frame > conv->last_frame) + { + conv->last_frame = frame; + } + session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm); + if (session_tree != NULL) + { + transport = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id); + } + } + return (transport); +} + +static void lbtrm_transport_unicast_add(const address * source_address, guint16 source_port, guint32 session_id, guint32 frame, lbtrm_transport_t * transport) +{ + conversation_t * conv = NULL; + wmem_tree_t * session_tree = NULL; + lbtrm_transport_t * transport_entry = NULL; + + conv = find_conversation(frame, source_address, &lbtrm_null_address, CONVERSATION_UDP, source_port, 0, 0); + if (conv == NULL) + { + conv = conversation_new(frame, source_address, &lbtrm_null_address, CONVERSATION_UDP, source_port, 0, 0); + } + session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm); + if (session_tree == NULL) + { + session_tree = wmem_tree_new(wmem_file_scope()); + conversation_add_proto_data(conv, proto_lbtrm, (void *) session_tree); + } + transport_entry = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id); + if (transport_entry == NULL) + { + wmem_tree_insert32(session_tree, session_id, (void *) transport); + } +} + +static lbtrm_transport_t * lbtrm_transport_find(const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port, guint32 frame) +{ + lbtrm_transport_t * entry = NULL; + wmem_tree_t * session_tree = NULL; + conversation_t * conv = NULL; + + conv = find_conversation(frame, source_address, multicast_group, CONVERSATION_UDP, source_port, dest_port, 0); + if (conv != NULL) + { + if (frame > conv->last_frame) + { + conv->last_frame = frame; + } + session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm); + if (session_tree != NULL) + { + entry = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id); + } + } + return (entry); +} + +lbtrm_transport_t * lbtrm_transport_add(const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port, guint32 frame) +{ + lbtrm_transport_t * entry; + conversation_t * conv = NULL; + wmem_tree_t * session_tree = NULL; + + conv = find_conversation(frame, source_address, multicast_group, CONVERSATION_UDP, source_port, dest_port, 0); + if (conv == NULL) + { + conv = conversation_new(frame, source_address, multicast_group, CONVERSATION_UDP, source_port, dest_port, 0); + } + if (frame > conv->last_frame) + { + conv->last_frame = frame; + } + session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm); + if (session_tree == NULL) + { + session_tree = wmem_tree_new(wmem_file_scope()); + conversation_add_proto_data(conv, proto_lbtrm, (void *) session_tree); + } + entry = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id); + if (entry != NULL) + { + return (entry); + } + entry = wmem_new(wmem_file_scope(), lbtrm_transport_t); + copy_address_wmem(wmem_file_scope(), &(entry->source_address), source_address); + entry->source_port = source_port; + entry->session_id = session_id; + copy_address_wmem(wmem_file_scope(), &(entry->multicast_group), multicast_group); + entry->dest_port = dest_port; + entry->channel = lbm_channel_assign(LBM_CHANNEL_TRANSPORT_LBTRM); + entry->frame = wmem_tree_new(wmem_file_scope()); + entry->last_frame = NULL; + entry->last_data_frame = NULL; + entry->last_sm_frame = NULL; + entry->last_nak_frame = NULL; + entry->last_ncf_frame = NULL; + entry->data_sqn = wmem_tree_new(wmem_file_scope()); + entry->sm_sqn = wmem_tree_new(wmem_file_scope()); + entry->data_high_sqn = 0; + entry->sm_high_sqn = 0; + wmem_tree_insert32(session_tree, session_id, (void *) entry); + lbtrm_transport_unicast_add(source_address, source_port, session_id, frame, entry); + return (entry); +} + +static lbm_transport_sqn_t * lbtrm_transport_sqn_find(lbtrm_transport_t * transport, guint8 type, guint32 sqn) +{ + lbm_transport_sqn_t * sqn_entry = NULL; + + switch (type) + { + case LBTRM_PACKET_TYPE_DATA: + sqn_entry = (lbm_transport_sqn_t *) wmem_tree_lookup32(transport->data_sqn, sqn); + break; + case LBTRM_PACKET_TYPE_SM: + sqn_entry = (lbm_transport_sqn_t *) wmem_tree_lookup32(transport->sm_sqn, sqn); + break; + case LBTRM_PACKET_TYPE_NAK: + case LBTRM_PACKET_TYPE_NCF: + default: + sqn_entry = NULL; + break; + } + return (sqn_entry); +} + +static lbm_transport_sqn_t * lbtrm_transport_sqn_add(lbtrm_transport_t * transport, lbm_transport_frame_t * frame) +{ + wmem_tree_t * sqn_list = NULL; + lbm_transport_sqn_t * sqn_entry = NULL; + + switch (frame->type) + { + case LBTRM_PACKET_TYPE_DATA: + sqn_list = transport->data_sqn; + break; + case LBTRM_PACKET_TYPE_SM: + sqn_list = transport->sm_sqn; + break; + case LBTRM_PACKET_TYPE_NAK: + case LBTRM_PACKET_TYPE_NCF: + default: + return (NULL); + break; + } + + /* Add the sqn. */ + sqn_entry = lbm_transport_sqn_add(sqn_list, frame); + return (sqn_entry); +} + +static lbm_transport_frame_t * lbtrm_transport_frame_find(lbtrm_transport_t * transport, guint32 frame) +{ + return ((lbm_transport_frame_t *) wmem_tree_lookup32(transport->frame, frame)); +} + +static lbm_transport_frame_t * lbtrm_transport_frame_add(lbtrm_transport_t * transport, guint8 type, guint32 frame, guint32 sqn, gboolean retransmission) +{ + lbm_transport_sqn_t * dup_sqn_entry = NULL; + lbm_transport_frame_t * frame_entry = NULL; + + /* Locate the frame. */ + frame_entry = lbtrm_transport_frame_find(transport, frame); + if (frame_entry != NULL) + { + return (frame_entry); + } + frame_entry = lbm_transport_frame_add(transport->frame, type, frame, sqn, retransmission); + if (transport->last_frame != NULL) + { + frame_entry->previous_frame = transport->last_frame->frame; + transport->last_frame->next_frame = frame; + } + transport->last_frame = frame_entry; + switch (type) + { + case LBTRM_PACKET_TYPE_DATA: + if (transport->last_data_frame != NULL) + { + frame_entry->previous_type_frame = transport->last_data_frame->frame; + transport->last_data_frame->next_type_frame = frame; + /* Ideally, this frame's sqn is 1 more than the highest data sqn seen */ + if (frame_entry->sqn <= transport->data_high_sqn) + { + dup_sqn_entry = lbtrm_transport_sqn_find(transport, type, frame_entry->sqn); + if (!frame_entry->retransmission) + { + /* Out of order */ + if (dup_sqn_entry != NULL) + { + frame_entry->duplicate = TRUE; + } + if (frame_entry->sqn != transport->data_high_sqn) + { + frame_entry->ooo_gap = transport->data_high_sqn - frame_entry->sqn; + } + } + } + else + { + if (!frame_entry->retransmission) + { + if (frame_entry->sqn != (transport->data_high_sqn + 1)) + { + /* Gap */ + frame_entry->sqn_gap = frame_entry->sqn - (transport->last_data_frame->sqn + 1); + } + } + } + } + if ((frame_entry->sqn > transport->data_high_sqn) && !frame_entry->retransmission) + { + transport->data_high_sqn = frame_entry->sqn; + } + transport->last_data_frame = frame_entry; + break; + case LBTRM_PACKET_TYPE_SM: + if (transport->last_sm_frame != NULL) + { + frame_entry->previous_type_frame = transport->last_sm_frame->frame; + transport->last_sm_frame->next_type_frame = frame; + /* Ideally, this frame's sqn is 1 more than the highest SM sqn seen */ + if (frame_entry->sqn <= transport->sm_high_sqn) + { + /* Out of order */ + dup_sqn_entry = lbtrm_transport_sqn_find(transport, type, frame_entry->sqn); + if (dup_sqn_entry != NULL) + { + frame_entry->duplicate = TRUE; + } + if (frame_entry->sqn != transport->sm_high_sqn) + { + frame_entry->ooo_gap = transport->sm_high_sqn - frame_entry->sqn; + } + } + else + { + if (frame_entry->sqn != (transport->sm_high_sqn + 1)) + { + /* Gap */ + frame_entry->sqn_gap = frame_entry->sqn - (transport->sm_high_sqn + 1); + } + } + } + if (frame_entry->sqn > transport->sm_high_sqn) + { + transport->sm_high_sqn = frame_entry->sqn; + } + transport->last_sm_frame = frame_entry; + break; + case LBTRM_PACKET_TYPE_NAK: + if (transport->last_nak_frame != NULL) + { + frame_entry->previous_type_frame = transport->last_nak_frame->frame; + transport->last_nak_frame->next_type_frame = frame; + } + transport->last_nak_frame = frame_entry; + break; + case LBTRM_PACKET_TYPE_NCF: + if (transport->last_ncf_frame != NULL) + { + frame_entry->previous_type_frame = transport->last_ncf_frame->frame; + transport->last_ncf_frame->next_type_frame = frame; + } + transport->last_ncf_frame = frame_entry; + break; + } + + /* Add the sqn. */ + (void)lbtrm_transport_sqn_add(transport, frame_entry); + return (frame_entry); +} + +static char * lbtrm_transport_source_string_format(wmem_allocator_t *pool, const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port) +{ + /* Returns a packet-scoped string. */ + return (wmem_strdup_printf(pool, "LBTRM:%s:%" PRIu16 ":%08x:%s:%" PRIu16, address_to_str(pool, source_address), source_port, session_id, + address_to_str(pool, multicast_group), dest_port)); +} + +char * lbtrm_transport_source_string(const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port) +{ + /* Returns a file-scoped string. */ + return lbtrm_transport_source_string_format(wmem_file_scope(), source_address, source_port, session_id, multicast_group, dest_port); +} + +static char * lbtrm_transport_source_string_transport(wmem_allocator_t *pool, lbtrm_transport_t * transport) +{ + /* Returns a pool-scoped string. */ + return (lbtrm_transport_source_string_format(pool, &(transport->source_address), transport->source_port, transport->session_id, &(transport->multicast_group), transport->dest_port)); +} + +/*----------------------------------------------------------------------------*/ +/* Packet definitions. */ +/*----------------------------------------------------------------------------*/ + +/* LBT-RM main header */ +typedef struct +{ + lbm_uint8_t ver_type; + lbm_uint8_t next_hdr; + lbm_uint16_t ucast_port; + lbm_uint32_t session_id; +} lbtrm_hdr_t; +#define O_LBTRM_HDR_T_VER_TYPE OFFSETOF(lbtrm_hdr_t, ver_type) +#define L_LBTRM_HDR_T_VER_TYPE SIZEOF(lbtrm_hdr_t, ver_type) +#define O_LBTRM_HDR_T_NEXT_HDR OFFSETOF(lbtrm_hdr_t, next_hdr) +#define L_LBTRM_HDR_T_NEXT_HDR SIZEOF(lbtrm_hdr_t, next_hdr) +#define O_LBTRM_HDR_T_UCAST_PORT OFFSETOF(lbtrm_hdr_t, ucast_port) +#define L_LBTRM_HDR_T_UCAST_PORT SIZEOF(lbtrm_hdr_t, ucast_port) +#define O_LBTRM_HDR_T_SESSION_ID OFFSETOF(lbtrm_hdr_t, session_id) +#define L_LBTRM_HDR_T_SESSION_ID SIZEOF(lbtrm_hdr_t, session_id) +#define L_LBTRM_HDR_T (gint) (sizeof(lbtrm_hdr_t)) + +#define LBTRM_VERSION 0x00 +#define LBTRM_HDR_VER(x) (x >> 4) +#define LBTRM_HDR_TYPE(x) (x & 0x0F) +#define LBTRM_HDR_VER_MASK 0xF0 +#define LBTRM_HDR_TYPE_MASK 0x0F + +/* LBT-RM data header */ +typedef struct +{ + lbm_uint32_t sqn; + lbm_uint32_t trail_sqn; + lbm_uint8_t flags_fec_type; + lbm_uint8_t flags_tgsz; + lbm_uint16_t fec_symbol; +} lbtrm_data_hdr_t; +#define O_LBTRM_DATA_HDR_T_SQN OFFSETOF(lbtrm_data_hdr_t, sqn) +#define L_LBTRM_DATA_HDR_T_SQN SIZEOF(lbtrm_data_hdr_t, sqn) +#define O_LBTRM_DATA_HDR_T_TRAIL_SQN OFFSETOF(lbtrm_data_hdr_t, trail_sqn) +#define L_LBTRM_DATA_HDR_T_TRAIL_SQN SIZEOF(lbtrm_data_hdr_t, trail_sqn) +#define O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE OFFSETOF(lbtrm_data_hdr_t, flags_fec_type) +#define L_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE SIZEOF(lbtrm_data_hdr_t, flags_fec_type) +#define O_LBTRM_DATA_HDR_T_FLAGS_TGSZ OFFSETOF(lbtrm_data_hdr_t, flags_tgsz) +#define L_LBTRM_DATA_HDR_T_FLAGS_TGSZ SIZEOF(lbtrm_data_hdr_t, flags_tgsz) +#define O_LBTRM_DATA_HDR_T_FEC_SYMBOL OFFSETOF(lbtrm_data_hdr_t, fec_symbol) +#define L_LBTRM_DATA_HDR_T_FEC_SYMBOL SIZEOF(lbtrm_data_hdr_t, fec_symbol) +#define L_LBTRM_DATA_HDR_T (gint) (sizeof(lbtrm_data_hdr_t)) + +#define LBTRM_DATA_UNICAST_NAKS_FLAG 0x80 +#define LBTRM_MULTICAST_NAKS_FLAG 0x40 +#define LBTRM_DATA_RETRANSMISSION_FLAG 0x20 +#define LBTRM_LATE_JOIN_FLAG 0x10 +#define LBTRM_FEC_TYPE_MASK 0xF +#define LBTRM_DATA_FLAGS(x) (x >> 4) +#define LBTRM_DATA_FLAGS_MASK 0xF0 + +/* LBT-RM Session Message header */ +typedef struct +{ + lbm_uint32_t sm_sqn; + lbm_uint32_t lead_sqn; + lbm_uint32_t trail_sqn; + lbm_uint8_t flags_fec_type; + lbm_uint8_t flags_tgsz; + lbm_uint16_t reserved; +} lbtrm_sm_hdr_t; +#define O_LBTRM_SM_HDR_T_SM_SQN OFFSETOF(lbtrm_sm_hdr_t, sm_sqn) +#define L_LBTRM_SM_HDR_T_SM_SQN SIZEOF(lbtrm_sm_hdr_t, sm_sqn) +#define O_LBTRM_SM_HDR_T_LEAD_SQN OFFSETOF(lbtrm_sm_hdr_t, lead_sqn) +#define L_LBTRM_SM_HDR_T_LEAD_SQN SIZEOF(lbtrm_sm_hdr_t, lead_sqn) +#define O_LBTRM_SM_HDR_T_TRAIL_SQN OFFSETOF(lbtrm_sm_hdr_t, trail_sqn) +#define L_LBTRM_SM_HDR_T_TRAIL_SQN SIZEOF(lbtrm_sm_hdr_t, trail_sqn) +#define O_LBTRM_SM_HDR_T_FLAGS_FEC_TYPE OFFSETOF(lbtrm_sm_hdr_t, flags_fec_type) +#define L_LBTRM_SM_HDR_T_FLAGS_FEC_TYPE SIZEOF(lbtrm_sm_hdr_t, flags_fec_type) +#define O_LBTRM_SM_HDR_T_FLAGS_TGSZ OFFSETOF(lbtrm_sm_hdr_t, flags_tgsz) +#define L_LBTRM_SM_HDR_T_FLAGS_TGSZ SIZEOF(lbtrm_sm_hdr_t, flags_tgsz) +#define O_LBTRM_SM_HDR_T_RESERVED OFFSETOF(lbtrm_sm_hdr_t, reserved) +#define L_LBTRM_SM_HDR_T_RESERVED SIZEOF(lbtrm_sm_hdr_t, reserved) +#define L_LBTRM_SM_HDR_T (gint) (sizeof(lbtrm_sm_hdr_t)) + +#define LBTRM_SM_UNICAST_NAKS_FLAG 0x80 +#define LBTRM_SM_FLAGS(x) (x >> 4) +#define LBTRM_SM_FLAGS_MASK 0xF0 + +/* LBT-RM NAK header */ +typedef struct +{ + lbm_uint16_t num_naks; + lbm_uint16_t format; +} lbtrm_nak_hdr_t; +#define O_LBTRM_NAK_HDR_T_NUM_NAKS OFFSETOF(lbtrm_nak_hdr_t, num_naks) +#define L_LBTRM_NAK_HDR_T_NUM_NAKS SIZEOF(lbtrm_nak_hdr_t, num_naks) +#define O_LBTRM_NAK_HDR_T_FORMAT OFFSETOF(lbtrm_nak_hdr_t, format) +#define L_LBTRM_NAK_HDR_T_FORMAT SIZEOF(lbtrm_nak_hdr_t, format) +#define L_LBTRM_NAK_HDR_T (gint) (sizeof(lbtrm_nak_hdr_t)) + +#define LBTRM_NAK_SELECTIVE_FORMAT 0x0 +#define LBTRM_NAK_PARITY_FORMAT 0x1 +#define LBTRM_NAK_HDR_FORMAT(x) (x & 0xF) +#define LBTRM_NAK_HDR_FORMAT_MASK 0x0F + +/* LBT-RM NAK Confirmation */ +typedef struct +{ + lbm_uint32_t trail_sqn; + lbm_uint16_t num_ncfs; + lbm_uint8_t reserved; + lbm_uint8_t reason_format; +} lbtrm_ncf_hdr_t; +#define O_LBTRM_NCF_HDR_T_TRAIL_SQN OFFSETOF(lbtrm_ncf_hdr_t, trail_sqn) +#define L_LBTRM_NCF_HDR_T_TRAIL_SQN SIZEOF(lbtrm_ncf_hdr_t, trail_sqn) +#define O_LBTRM_NCF_HDR_T_NUM_NCFS OFFSETOF(lbtrm_ncf_hdr_t, num_ncfs) +#define L_LBTRM_NCF_HDR_T_NUM_NCFS SIZEOF(lbtrm_ncf_hdr_t, num_ncfs) +#define O_LBTRM_NCF_HDR_T_RESERVED OFFSETOF(lbtrm_ncf_hdr_t, reserved) +#define L_LBTRM_NCF_HDR_T_RESERVED SIZEOF(lbtrm_ncf_hdr_t, reserved) +#define O_LBTRM_NCF_HDR_T_REASON_FORMAT OFFSETOF(lbtrm_ncf_hdr_t, reason_format) +#define L_LBTRM_NCF_HDR_T_REASON_FORMAT SIZEOF(lbtrm_ncf_hdr_t, reason_format) +#define L_LBTRM_NCF_HDR_T (gint) (sizeof(lbtrm_ncf_hdr_t)) + +#define LBTRM_NCF_SELECTIVE_FORMAT 0x0 +#define LBTRM_NCF_PARITY_FORMAT 0x1 +#define LBTRM_NCF_HDR_REASON(x) ((x & 0xF0) >> 4) +#define LBTRM_NCF_HDR_FORMAT(x) (x & 0xF) +#define LBTRM_NCF_HDR_REASON_MASK 0xF0 +#define LBTRM_NCF_HDR_FORMAT_MASK 0x0F + +/* LBT-RM option header */ +typedef struct +{ + lbm_uint8_t next_hdr; + lbm_uint8_t hdr_len; + lbm_uint16_t res; +} lbtrm_basic_opt_t; +#define O_LBTRM_BASIC_OPT_T_NEXT_HDR OFFSETOF(lbtrm_basic_opt_t, next_hdr) +#define L_LBTRM_BASIC_OPT_T_NEXT_HDR SIZEOF(lbtrm_basic_opt_t, next_hdr) +#define O_LBTRM_BASIC_OPT_T_HDR_LEN OFFSETOF(lbtrm_basic_opt_t, hdr_len) +#define L_LBTRM_BASIC_OPT_T_HDR_LEN SIZEOF(lbtrm_basic_opt_t, hdr_len) +#define O_LBTRM_BASIC_OPT_T_RES OFFSETOF(lbtrm_basic_opt_t, res) +#define L_LBTRM_BASIC_OPT_T_RES SIZEOF(lbtrm_basic_opt_t, res) +#define L_LBTRM_BASIC_OPT_T (gint) (sizeof(lbtrm_basic_opt_t)) + +#define LBTRM_NHDR_DATA 0x0 + +/*----------------------------------------------------------------------------*/ +/* Value translation tables. */ +/*----------------------------------------------------------------------------*/ + +static const value_string lbtrm_packet_type[] = +{ + { LBTRM_PACKET_TYPE_DATA, "DATA" }, + { LBTRM_PACKET_TYPE_SM, "SM" }, + { LBTRM_PACKET_TYPE_NAK, "NAK" }, + { LBTRM_PACKET_TYPE_NCF, "NCF" }, + { 0x0, NULL } +}; + +static const value_string lbtrm_nak_format[] = +{ + { LBTRM_NAK_SELECTIVE_FORMAT, "Selective" }, + { LBTRM_NAK_PARITY_FORMAT, "Parity" }, + { 0x0, NULL } +}; + +static const value_string lbtrm_ncf_format[] = +{ + { LBTRM_NCF_SELECTIVE_FORMAT, "Selective" }, + { LBTRM_NCF_PARITY_FORMAT, "Parity" }, + { 0x0, NULL } +}; + +static const value_string lbtrm_ncf_reason[] = +{ + { LBTRM_NCF_REASON_NO_RETRY, "Do not retry" }, + { LBTRM_NCF_REASON_IGNORED, "NAK Ignored" }, + { LBTRM_NCF_REASON_RX_DELAY, "Retransmit Delay" }, + { LBTRM_NCF_REASON_SHED, "NAK Shed" }, + { 0x0, NULL } +}; + +static const value_string lbtrm_next_header[] = +{ + { LBTRM_NHDR_DATA, "Data" }, + { 0x0, NULL } +}; + +/*----------------------------------------------------------------------------*/ +/* Preferences. */ +/*----------------------------------------------------------------------------*/ + +/* Preferences default values. */ +#define LBTRM_DEFAULT_DPORT_LOW 14400 +#define LBTRM_DEFAULT_DPORT_HIGH 14400 +#define LBTRM_DEFAULT_SPORT_HIGH 14399 +#define LBTRM_DEFAULT_SPORT_LOW 14390 +#define LBTRM_DEFAULT_MC_ADDRESS_LOW "224.10.10.10" +#define LBTRM_DEFAULT_MC_ADDRESS_HIGH "224.10.10.14" +#define MIM_DEFAULT_INCOMING_DPORT 14401 +#define MIM_DEFAULT_OUTGOING_DPORT 14401 +#define MIM_DEFAULT_MC_INCOMING_ADDRESS "224.10.10.21" +#define MIM_DEFAULT_MC_OUTGOING_ADDRESS "224.10.10.21" + +/* Global preferences variables (altered by the preferences dialog). */ +static const char * global_lbtrm_mc_address_low = LBTRM_DEFAULT_MC_ADDRESS_LOW; +static const char * global_lbtrm_mc_address_high = LBTRM_DEFAULT_MC_ADDRESS_HIGH; +static guint32 global_lbtrm_dest_port_low = LBTRM_DEFAULT_DPORT_LOW; +static guint32 global_lbtrm_dest_port_high = LBTRM_DEFAULT_DPORT_HIGH; +static guint32 global_lbtrm_src_port_low = LBTRM_DEFAULT_SPORT_LOW; +static guint32 global_lbtrm_src_port_high = LBTRM_DEFAULT_SPORT_HIGH; +static guint32 global_mim_incoming_dest_port = MIM_DEFAULT_INCOMING_DPORT; +static guint32 global_mim_outgoing_dest_port = MIM_DEFAULT_OUTGOING_DPORT; +static const char * global_mim_incoming_mc_address = MIM_DEFAULT_MC_INCOMING_ADDRESS; +static const char * global_mim_outgoing_mc_address = MIM_DEFAULT_MC_OUTGOING_ADDRESS; +static gboolean global_lbtrm_expert_separate_naks = FALSE; +static gboolean global_lbtrm_expert_separate_ncfs = FALSE; +static gboolean global_lbtrm_use_tag = FALSE; +static gboolean global_lbtrm_sequence_analysis = FALSE; + +/* Local preferences variables (used by the dissector). */ +static guint32 lbtrm_mc_address_low_host = 0; +static guint32 lbtrm_mc_address_high_host = 0; +static guint32 lbtrm_dest_port_low = LBTRM_DEFAULT_DPORT_LOW; +static guint32 lbtrm_dest_port_high = LBTRM_DEFAULT_DPORT_HIGH; +static guint32 lbtrm_src_port_low = LBTRM_DEFAULT_SPORT_LOW; +static guint32 lbtrm_src_port_high = LBTRM_DEFAULT_SPORT_HIGH; +static guint32 mim_incoming_dest_port = MIM_DEFAULT_INCOMING_DPORT; +static guint32 mim_outgoing_dest_port = MIM_DEFAULT_OUTGOING_DPORT; +static guint32 mim_incoming_mc_address_host = 0; +static guint32 mim_outgoing_mc_address_host = 0; +static gboolean lbtrm_expert_separate_naks = FALSE; +static gboolean lbtrm_expert_separate_ncfs = FALSE; +static gboolean lbtrm_use_tag = FALSE; +static gboolean lbtrm_sequence_analysis = FALSE; + +/*----------------------------------------------------------------------------*/ +/* Tag management. */ +/*----------------------------------------------------------------------------*/ +typedef struct +{ + char * name; + char * mc_address_low; + guint32 mc_address_low_val_h; + char * mc_address_high; + guint32 mc_address_high_val_h; + guint32 dport_low; + guint32 dport_high; + guint32 sport_low; + guint32 sport_high; + guint32 mim_incoming_dport; + guint32 mim_outgoing_dport; + char * mim_mc_incoming_address; + guint32 mim_mc_incoming_address_val_h; + char * mim_mc_outgoing_address; + guint32 mim_mc_outgoing_address_val_h; +} lbtrm_tag_entry_t; + +static lbtrm_tag_entry_t * lbtrm_tag_entry = NULL; +static guint lbtrm_tag_count = 0; + +UAT_CSTRING_CB_DEF(lbtrm_tag, name, lbtrm_tag_entry_t) +UAT_IPV4_MC_CB_DEF(lbtrm_tag, mc_address_low, lbtrm_tag_entry_t) +UAT_IPV4_MC_CB_DEF(lbtrm_tag, mc_address_high, lbtrm_tag_entry_t) +UAT_DEC_CB_DEF(lbtrm_tag, dport_low, lbtrm_tag_entry_t) +UAT_DEC_CB_DEF(lbtrm_tag, dport_high, lbtrm_tag_entry_t) +UAT_DEC_CB_DEF(lbtrm_tag, sport_low, lbtrm_tag_entry_t) +UAT_DEC_CB_DEF(lbtrm_tag, sport_high, lbtrm_tag_entry_t) +UAT_DEC_CB_DEF(lbtrm_tag, mim_incoming_dport, lbtrm_tag_entry_t) +UAT_DEC_CB_DEF(lbtrm_tag, mim_outgoing_dport, lbtrm_tag_entry_t) +UAT_IPV4_MC_CB_DEF(lbtrm_tag, mim_mc_incoming_address, lbtrm_tag_entry_t) +UAT_IPV4_MC_CB_DEF(lbtrm_tag, mim_mc_outgoing_address, lbtrm_tag_entry_t) +static uat_field_t lbtrm_tag_array[] = +{ + UAT_FLD_CSTRING(lbtrm_tag, name, "Tag name", "Tag name"), + UAT_FLD_IPV4_MC(lbtrm_tag, mc_address_low, "Multicast address low", "Multicast address low"), + UAT_FLD_IPV4_MC(lbtrm_tag, mc_address_high, "Multicast address high", "Multicast address high"), + UAT_FLD_DEC(lbtrm_tag, dport_low, "Destination port low", "Destination port low"), + UAT_FLD_DEC(lbtrm_tag, dport_high, "Destination port high", "Destination port high"), + UAT_FLD_DEC(lbtrm_tag, sport_low, "Source port low", "Source port low"), + UAT_FLD_DEC(lbtrm_tag, sport_high, "Source port high", "Source port high"), + UAT_FLD_DEC(lbtrm_tag, mim_incoming_dport, "MIM incoming destination port", "MIM incoming destination port"), + UAT_FLD_DEC(lbtrm_tag, mim_outgoing_dport, "MIM outgoing destination port", "MIM outgoing destination port"), + UAT_FLD_IPV4_MC(lbtrm_tag, mim_mc_incoming_address, "MIM incoming multicast address", "MIM incoming multicast address"), + UAT_FLD_IPV4_MC(lbtrm_tag, mim_mc_outgoing_address, "MIM outgoing multicast address", "MIM outgoing multicast address"), + UAT_END_FIELDS +}; + +/*----------------------------------------------------------------------------*/ +/* UAT callback functions. */ +/*----------------------------------------------------------------------------*/ +static bool lbtrm_tag_update_cb(void * record, char * * error_string) +{ + lbtrm_tag_entry_t * tag = (lbtrm_tag_entry_t *)record; + + if (tag->name == NULL) + { + *error_string = g_strdup("Tag name can't be empty"); + return FALSE; + } + else + { + g_strstrip(tag->name); + if (tag->name[0] == 0) + { + *error_string = g_strdup("Tag name can't be empty"); + return FALSE; + } + } + return TRUE; +} + +static void * lbtrm_tag_copy_cb(void * destination, const void * source, size_t length _U_) +{ + const lbtrm_tag_entry_t * src = (const lbtrm_tag_entry_t *)source; + lbtrm_tag_entry_t * dest = (lbtrm_tag_entry_t *)destination; + + dest->name = g_strdup(src->name); + dest->mc_address_low = g_strdup(src->mc_address_low); + dest->mc_address_low_val_h = src->mc_address_low_val_h; + dest->mc_address_high = g_strdup(src->mc_address_high); + dest->mc_address_high_val_h = src->mc_address_high_val_h; + dest->dport_low = src->dport_low; + dest->dport_high = src->dport_high; + dest->sport_low = src->sport_low; + dest->sport_high = src->sport_high; + dest->mim_incoming_dport = src->mim_incoming_dport; + dest->mim_outgoing_dport = src->mim_outgoing_dport; + dest->mim_mc_incoming_address = g_strdup(src->mim_mc_incoming_address); + dest->mim_mc_incoming_address_val_h = src->mim_mc_incoming_address_val_h; + dest->mim_mc_outgoing_address = g_strdup(src->mim_mc_outgoing_address); + dest->mim_mc_outgoing_address_val_h = src->mim_mc_outgoing_address_val_h; + return (dest); +} + +static void lbtrm_tag_free_cb(void * record) +{ + lbtrm_tag_entry_t * tag = (lbtrm_tag_entry_t *)record; + + if (tag->name != NULL) + { + g_free(tag->name); + tag->name = NULL; + } + if (tag->mc_address_low != NULL) + { + g_free(tag->mc_address_low); + tag->mc_address_low = NULL; + } + if (tag->mc_address_high != NULL) + { + g_free(tag->mc_address_high); + tag->mc_address_high = NULL; + } + if (tag->mim_mc_incoming_address != NULL) + { + g_free(tag->mim_mc_incoming_address); + tag->mim_mc_incoming_address = NULL; + } + if (tag->mim_mc_outgoing_address != NULL) + { + g_free(tag->mim_mc_outgoing_address); + tag->mim_mc_outgoing_address = NULL; + } +} + +static char * lbtrm_tag_find(packet_info * pinfo) +{ + guint idx; + lbtrm_tag_entry_t * tag = NULL; + guint32 dest_addr_h; + + if (!lbtrm_use_tag) + { + return (NULL); + } + + dest_addr_h = pntoh32(pinfo->dst.data); + for (idx = 0; idx < lbtrm_tag_count; ++idx) + { + tag = &(lbtrm_tag_entry[idx]); + /* Is the destination a multicast address? */ + if (IN_MULTICAST(dest_addr_h)) + { + /* Check the MC address. */ + if ((dest_addr_h >= tag->mc_address_low_val_h) && (dest_addr_h <= tag->mc_address_high_val_h)) + { + /* It's in the LBT-RM multicast range. Check the ports. */ + if ((pinfo->destport >= tag->dport_low) && (pinfo->destport <= tag->dport_high)) + { + /* Must be one of ours. */ + return (tag->name); + } + } + else if ((dest_addr_h == tag->mim_mc_incoming_address_val_h) || (dest_addr_h == tag->mim_mc_outgoing_address_val_h)) + { + /* Might be MIM. Check the port. */ + if (((dest_addr_h == tag->mim_mc_incoming_address_val_h) && (pinfo->destport == tag->mim_incoming_dport)) + || ((dest_addr_h == tag->mim_mc_outgoing_address_val_h) && (pinfo->destport == tag->mim_outgoing_dport))) + { + /* Must be one of ours. */ + return (tag->name); + } + } + /* Not ours. */ + continue; + } + else + { + /* Not multicast, might be a unicast UDP NAK. Check the destination port. */ + if ((pinfo->destport < tag->sport_low) || (pinfo->destport > tag->sport_high)) + { + /* Wrong port. */ + continue; + } + /* One of ours, so handle it. */ + return (tag->name); + } + } + /* Not one of ours. */ + return (NULL); +} + +/*----------------------------------------------------------------------------*/ +/* Handles of all types. */ +/*----------------------------------------------------------------------------*/ + +/* Dissector tree handles */ +static gint ett_lbtrm = -1; +static gint ett_lbtrm_hdr = -1; +static gint ett_lbtrm_data = -1; +static gint ett_lbtrm_data_flags_fec_type = -1; +static gint ett_lbtrm_sm = -1; +static gint ett_lbtrm_sm_flags_fec_type = -1; +static gint ett_lbtrm_nak = -1; +static gint ett_lbtrm_nak_list = -1; +static gint ett_lbtrm_ncf = -1; +static gint ett_lbtrm_ncf_list = -1; +static gint ett_lbtrm_transport = -1; +static gint ett_lbtrm_transport_sqn = -1; + +/* Dissector field handles */ +static int hf_lbtrm_channel = -1; +static int hf_lbtrm_tag = -1; +static int hf_lbtrm_hdr = -1; +static int hf_lbtrm_hdr_ver = -1; +static int hf_lbtrm_hdr_type = -1; +static int hf_lbtrm_hdr_next_hdr = -1; +static int hf_lbtrm_hdr_ucast_port = -1; +static int hf_lbtrm_hdr_session_id = -1; +static int hf_lbtrm_data = -1; +static int hf_lbtrm_data_sqn = -1; +static int hf_lbtrm_data_trail_sqn = -1; +static int hf_lbtrm_data_flags_fec_type = -1; +static int hf_lbtrm_data_flags_fec_type_ucast_naks = -1; +static int hf_lbtrm_data_flags_fec_type_rx = -1; +static int hf_lbtrm_data_flags_tgsz = -1; +static int hf_lbtrm_data_fec_symbol = -1; +static int hf_lbtrm_sm = -1; +static int hf_lbtrm_sm_sm_sqn = -1; +static int hf_lbtrm_sm_lead_sqn = -1; +static int hf_lbtrm_sm_trail_sqn = -1; +static int hf_lbtrm_sm_flags_fec_type = -1; +static int hf_lbtrm_sm_flags_fec_type_ucast_naks = -1; +static int hf_lbtrm_sm_flags_tgsz = -1; +static int hf_lbtrm_sm_reserved = -1; +static int hf_lbtrm_nak = -1; +static int hf_lbtrm_nak_num_naks = -1; +static int hf_lbtrm_nak_format = -1; +static int hf_lbtrm_nak_list = -1; +static int hf_lbtrm_nak_list_nak = -1; +static int hf_lbtrm_ncf = -1; +static int hf_lbtrm_ncf_trail_sqn = -1; +static int hf_lbtrm_ncf_num_ncfs = -1; +static int hf_lbtrm_ncf_reserved = -1; +static int hf_lbtrm_ncf_reason = -1; +static int hf_lbtrm_ncf_format = -1; +static int hf_lbtrm_ncf_list = -1; +static int hf_lbtrm_ncf_list_ncf = -1; +static int hf_lbtrm_analysis = -1; +static int hf_lbtrm_analysis_prev_frame = -1; +static int hf_lbtrm_analysis_prev_data_frame = -1; +static int hf_lbtrm_analysis_prev_sm_frame = -1; +static int hf_lbtrm_analysis_prev_nak_frame = -1; +static int hf_lbtrm_analysis_prev_ncf_frame = -1; +static int hf_lbtrm_analysis_next_frame = -1; +static int hf_lbtrm_analysis_next_data_frame = -1; +static int hf_lbtrm_analysis_next_sm_frame = -1; +static int hf_lbtrm_analysis_next_nak_frame = -1; +static int hf_lbtrm_analysis_next_ncf_frame = -1; +static int hf_lbtrm_analysis_sqn = -1; +static int hf_lbtrm_analysis_sqn_frame = -1; +static int hf_lbtrm_analysis_data_retransmission = -1; +static int hf_lbtrm_analysis_data_sqn_gap = -1; +static int hf_lbtrm_analysis_data_ooo_gap = -1; +static int hf_lbtrm_analysis_data_duplicate = -1; +static int hf_lbtrm_analysis_sm_sqn_gap = -1; +static int hf_lbtrm_analysis_sm_ooo_gap = -1; +static int hf_lbtrm_analysis_sm_duplicate = -1; + +/* Expert info handles */ +static expert_field ei_lbtrm_analysis_ncf = EI_INIT; +static expert_field ei_lbtrm_analysis_ncf_ncf = EI_INIT; +static expert_field ei_lbtrm_analysis_nak = EI_INIT; +static expert_field ei_lbtrm_analysis_nak_nak = EI_INIT; +static expert_field ei_lbtrm_analysis_sm = EI_INIT; +static expert_field ei_lbtrm_analysis_rx = EI_INIT; +static expert_field ei_lbtrm_analysis_invalid_value = EI_INIT; +static expert_field ei_lbtrm_analysis_data_rx = EI_INIT; +static expert_field ei_lbtrm_analysis_data_gap = EI_INIT; +static expert_field ei_lbtrm_analysis_data_ooo = EI_INIT; +static expert_field ei_lbtrm_analysis_data_dup = EI_INIT; +static expert_field ei_lbtrm_analysis_sm_gap = EI_INIT; +static expert_field ei_lbtrm_analysis_sm_ooo = EI_INIT; +static expert_field ei_lbtrm_analysis_sm_dup = EI_INIT; + +/*----------------------------------------------------------------------------*/ +/* LBT-RM data payload dissection functions. */ +/*----------------------------------------------------------------------------*/ +static int dissect_lbtrm_data_contents(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, const char * tag_name, guint64 channel) +{ + tvbuff_t * next_tvb; + + next_tvb = tvb_new_subset_remaining(tvb, offset); + return (lbmc_dissect_lbmc_packet(next_tvb, 0, pinfo, tree, tag_name, channel)); +} + +/*----------------------------------------------------------------------------*/ +/* LBT-RM NAK confirmation packet dissection functions. */ +/*----------------------------------------------------------------------------*/ +static int dissect_lbtrm_ncf_list(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, int ncf_count, int reason, lbm_lbtrm_tap_info_t * tap_info) +{ + proto_tree * ncf_tree = NULL; + proto_item * ncf_item = NULL; + lbm_uint32_t ncf; + int idx = 0; + int len = 0; + + ncf_item = proto_tree_add_item(tree, hf_lbtrm_ncf_list, tvb, offset + len, (int)(sizeof(lbm_uint32_t) * ncf_count), ENC_NA); + ncf_tree = proto_item_add_subtree(ncf_item, ett_lbtrm_ncf_list); + + for (idx = 0; idx < ncf_count; idx++) + { + proto_item * sep_ncf_item = NULL; + + ncf = tvb_get_ntohl(tvb, offset + len); + sep_ncf_item = proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_list_ncf, tvb, offset + len, sizeof(lbm_uint32_t), ENC_BIG_ENDIAN); + if (lbtrm_expert_separate_ncfs) + { + expert_add_info_format(pinfo, sep_ncf_item, &ei_lbtrm_analysis_ncf_ncf, "NCF 0x%08x %s", ncf, val_to_str(reason, lbtrm_ncf_reason, "Unknown (0x%02x)")); + } + tap_info->sqns[idx] = ncf; + len += 4; + } + return (len); +} + +static int dissect_lbtrm_ncf(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, lbm_lbtrm_tap_info_t * tap_info) +{ + int len = 0; + guint16 num_ncfs; + guint8 reason; + proto_tree * ncf_tree = NULL; + proto_item * ncf_item = NULL; + proto_item * reason_item = NULL; + + ncf_item = proto_tree_add_item(tree, hf_lbtrm_ncf, tvb, offset, -1, ENC_NA); + ncf_tree = proto_item_add_subtree(ncf_item, ett_lbtrm_ncf); + num_ncfs = tvb_get_ntohs(tvb, offset + O_LBTRM_NCF_HDR_T_NUM_NCFS); + reason = tvb_get_guint8(tvb, offset + O_LBTRM_NCF_HDR_T_REASON_FORMAT); + proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_trail_sqn, tvb, offset + O_LBTRM_NCF_HDR_T_TRAIL_SQN, L_LBTRM_NCF_HDR_T_TRAIL_SQN, ENC_BIG_ENDIAN); + proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_num_ncfs, tvb, offset + O_LBTRM_NCF_HDR_T_NUM_NCFS, L_LBTRM_NCF_HDR_T_NUM_NCFS, ENC_BIG_ENDIAN); + proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_reserved, tvb, offset + O_LBTRM_NCF_HDR_T_RESERVED, L_LBTRM_NCF_HDR_T_RESERVED, ENC_BIG_ENDIAN); + proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_reason, tvb, offset + O_LBTRM_NCF_HDR_T_REASON_FORMAT, L_LBTRM_NCF_HDR_T_REASON_FORMAT, ENC_BIG_ENDIAN); + proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_format, tvb, offset + O_LBTRM_NCF_HDR_T_REASON_FORMAT, L_LBTRM_NCF_HDR_T_REASON_FORMAT, ENC_BIG_ENDIAN); + len = L_LBTRM_NCF_HDR_T; + if (!lbtrm_expert_separate_ncfs) + { + expert_add_info_format(pinfo, reason_item, &ei_lbtrm_analysis_ncf, "NCF %s", val_to_str(LBTRM_NCF_HDR_REASON(reason), lbtrm_ncf_reason, "Unknown (0x%02x)")); + } + tap_info->ncf_reason = LBTRM_NCF_HDR_REASON(reason); + tap_info->num_sqns = num_ncfs; + tap_info->sqns = wmem_alloc_array(pinfo->pool, guint32, num_ncfs); + len += dissect_lbtrm_ncf_list(tvb, offset + len, pinfo, ncf_tree, num_ncfs, LBTRM_NCF_HDR_REASON(reason), tap_info); + proto_item_set_len(ncf_item, len); + return (len); +} + +/*----------------------------------------------------------------------------*/ +/* LBT-RM NAK packet dissection functions. */ +/*----------------------------------------------------------------------------*/ +static int dissect_lbtrm_nak_list(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, int nak_count, lbm_lbtrm_tap_info_t * tap_info) +{ + proto_tree * nak_tree = NULL; + proto_item * nak_item = NULL; + lbm_uint32_t nak; + int idx = 0; + int len = 0; + + nak_item = proto_tree_add_item(tree, hf_lbtrm_nak_list, tvb, offset + len, (int)(sizeof(lbm_uint32_t) * nak_count), ENC_NA); + nak_tree = proto_item_add_subtree(nak_item, ett_lbtrm_nak_list); + + for (idx = 0; idx < nak_count; idx++) + { + proto_item * sep_nak_item = NULL; + + nak = tvb_get_ntohl(tvb, offset + len); + sep_nak_item = proto_tree_add_item(nak_tree, hf_lbtrm_nak_list_nak, tvb, offset + len, sizeof(lbm_uint32_t), ENC_BIG_ENDIAN); + if (lbtrm_expert_separate_naks) + { + expert_add_info_format(pinfo, sep_nak_item, &ei_lbtrm_analysis_nak_nak, "NAK 0x%08x", nak); + } + tap_info->sqns[idx] = nak; + len += 4; + } + return (len); +} + +static int dissect_lbtrm_nak(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, lbm_lbtrm_tap_info_t * tap_info) +{ + int len = 0; + guint16 num_naks; + proto_tree * nak_tree = NULL; + proto_item * nak_item = NULL; + + nak_item = proto_tree_add_item(tree, hf_lbtrm_nak, tvb, offset, -1, ENC_NA); + nak_tree = proto_item_add_subtree(nak_item, ett_lbtrm_nak); + num_naks = tvb_get_ntohs(tvb, offset + O_LBTRM_NAK_HDR_T_NUM_NAKS); + proto_tree_add_item(nak_tree, hf_lbtrm_nak_num_naks, tvb, offset + O_LBTRM_NAK_HDR_T_NUM_NAKS, L_LBTRM_NAK_HDR_T_NUM_NAKS, ENC_BIG_ENDIAN); + proto_tree_add_item(nak_tree, hf_lbtrm_nak_format, tvb, offset + O_LBTRM_NAK_HDR_T_FORMAT, L_LBTRM_NAK_HDR_T_FORMAT, ENC_BIG_ENDIAN); + len = L_LBTRM_NAK_HDR_T; + if (!lbtrm_expert_separate_naks) + { + expert_add_info(pinfo, nak_item, &ei_lbtrm_analysis_nak); + } + tap_info->num_sqns = num_naks; + tap_info->sqns = wmem_alloc_array(pinfo->pool, guint32, num_naks); + len += dissect_lbtrm_nak_list(tvb, offset + len, pinfo, nak_tree, num_naks, tap_info); + proto_item_set_len(nak_item, len); + return (len); +} + +/*----------------------------------------------------------------------------*/ +/* LBT-RM session message packet dissection functions. */ +/*----------------------------------------------------------------------------*/ +static int dissect_lbtrm_sm(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, guint32 * sequence, lbm_lbtrm_tap_info_t * tap_info) +{ + proto_tree * sm_tree = NULL; + proto_item * sm_item = NULL; + static int * const flags[] = + { + &hf_lbtrm_sm_flags_fec_type_ucast_naks, + NULL + }; + proto_item * sm_sqn_item = NULL; + guint32 sqn; + + sm_item = proto_tree_add_item(tree, hf_lbtrm_sm, tvb, offset, L_LBTRM_SM_HDR_T, ENC_NA); + sm_tree = proto_item_add_subtree(sm_item, ett_lbtrm_sm); + sm_sqn_item = proto_tree_add_item(sm_tree, hf_lbtrm_sm_sm_sqn, tvb, offset + O_LBTRM_SM_HDR_T_SM_SQN, L_LBTRM_SM_HDR_T_SM_SQN, ENC_BIG_ENDIAN); + proto_tree_add_item(sm_tree, hf_lbtrm_sm_lead_sqn, tvb, offset + O_LBTRM_SM_HDR_T_LEAD_SQN, L_LBTRM_SM_HDR_T_LEAD_SQN, ENC_BIG_ENDIAN); + proto_tree_add_item(sm_tree, hf_lbtrm_sm_trail_sqn, tvb, offset + O_LBTRM_SM_HDR_T_TRAIL_SQN, L_LBTRM_SM_HDR_T_TRAIL_SQN, ENC_BIG_ENDIAN); + proto_tree_add_bitmask(sm_tree, tvb, offset + O_LBTRM_SM_HDR_T_FLAGS_FEC_TYPE, hf_lbtrm_sm_flags_fec_type, ett_lbtrm_sm_flags_fec_type, flags, ENC_BIG_ENDIAN); + proto_tree_add_item(sm_tree, hf_lbtrm_sm_flags_tgsz, tvb, offset + O_LBTRM_SM_HDR_T_FLAGS_TGSZ, L_LBTRM_SM_HDR_T_FLAGS_TGSZ, ENC_BIG_ENDIAN); + proto_tree_add_item(sm_tree, hf_lbtrm_sm_reserved, tvb, offset + O_LBTRM_SM_HDR_T_RESERVED, L_LBTRM_SM_HDR_T_RESERVED, ENC_BIG_ENDIAN); + sqn = tvb_get_ntohl(tvb, offset + O_LBTRM_SM_HDR_T_SM_SQN); + expert_add_info(pinfo, sm_sqn_item, &ei_lbtrm_analysis_sm); + if (sequence != NULL) + { + *sequence = sqn; + } + tap_info->sqn = sqn; + return (L_LBTRM_SM_HDR_T); +} + +/*----------------------------------------------------------------------------*/ +/* LBT-RM data packet dissection functions. */ +/*----------------------------------------------------------------------------*/ +static int dissect_lbtrm_data(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, guint32 * sequence, gboolean * retransmission, lbm_lbtrm_tap_info_t * tap_info) +{ + proto_tree * data_tree = NULL; + proto_item * data_item = NULL; + static int * const flags[] = + { + &hf_lbtrm_data_flags_fec_type_ucast_naks, + &hf_lbtrm_data_flags_fec_type_rx, + NULL + }; + proto_item * sqn_item = NULL; + guint8 flags_val; + guint32 sqn; + gboolean is_retransmission = FALSE; + + data_item = proto_tree_add_item(tree, hf_lbtrm_data, tvb, offset, L_LBTRM_DATA_HDR_T, ENC_NA); + data_tree = proto_item_add_subtree(data_item, ett_lbtrm_data); + sqn_item = proto_tree_add_item(data_tree, hf_lbtrm_data_sqn, tvb, offset + O_LBTRM_DATA_HDR_T_SQN, L_LBTRM_DATA_HDR_T_SQN, ENC_BIG_ENDIAN); + proto_tree_add_item(data_tree, hf_lbtrm_data_trail_sqn, tvb, offset + O_LBTRM_DATA_HDR_T_TRAIL_SQN, L_LBTRM_DATA_HDR_T_TRAIL_SQN, ENC_BIG_ENDIAN); + flags_val = tvb_get_guint8(tvb, offset + O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE); + proto_tree_add_bitmask(data_tree, tvb, offset + O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE, hf_lbtrm_data_flags_fec_type, ett_lbtrm_data_flags_fec_type, flags, ENC_BIG_ENDIAN); + proto_tree_add_item(data_tree, hf_lbtrm_data_flags_tgsz, tvb, offset + O_LBTRM_DATA_HDR_T_FLAGS_TGSZ, L_LBTRM_DATA_HDR_T_FLAGS_TGSZ, ENC_BIG_ENDIAN); + proto_tree_add_item(data_tree, hf_lbtrm_data_fec_symbol, tvb, offset + O_LBTRM_DATA_HDR_T_FEC_SYMBOL, L_LBTRM_DATA_HDR_T_FEC_SYMBOL, ENC_BIG_ENDIAN); + sqn = tvb_get_ntohl(tvb, offset + O_LBTRM_DATA_HDR_T_SQN); + if (sequence != NULL) + { + *sequence = sqn; + } + if ((flags_val & LBTRM_DATA_RETRANSMISSION_FLAG) != 0) + { + is_retransmission = TRUE; + expert_add_info_format(pinfo, sqn_item, &ei_lbtrm_analysis_rx, "RX 0x%08x", sqn); + } + if (retransmission != NULL) + { + *retransmission = is_retransmission; + } + tap_info->retransmission = is_retransmission; + tap_info->sqn = sqn; + return (L_LBTRM_DATA_HDR_T); +} + +/*----------------------------------------------------------------------------*/ +/* LBT-RM packet dissector. */ +/*----------------------------------------------------------------------------*/ +typedef struct +{ + proto_tree * tree; + tvbuff_t * tvb; + guint32 current_frame; +} lbtrm_sqn_frame_list_callback_data_t; + +static bool dissect_lbtrm_sqn_frame_list_callback(const void *key _U_, void * frame, void * user_data) +{ + lbtrm_sqn_frame_list_callback_data_t * cb_data = (lbtrm_sqn_frame_list_callback_data_t *) user_data; + proto_item * transport_item = NULL; + lbm_transport_sqn_frame_t * sqn_frame = (lbm_transport_sqn_frame_t *) frame; + + if (sqn_frame->frame != cb_data->current_frame) + { + if (sqn_frame->retransmission) + { + transport_item = proto_tree_add_uint_format_value(cb_data->tree, hf_lbtrm_analysis_sqn_frame, cb_data->tvb, 0, 0, sqn_frame->frame, "%" PRIu32 " (RX)", sqn_frame->frame); + } + else + { + transport_item = proto_tree_add_uint(cb_data->tree, hf_lbtrm_analysis_sqn_frame, cb_data->tvb, 0, 0, sqn_frame->frame); + } + proto_item_set_generated(transport_item); + } + return (FALSE); +} + +static int dissect_lbtrm(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data _U_) +{ + proto_tree * lbtrm_tree = NULL; + proto_item * lbtrm_item; + int offset = 0; + guint8 next_hdr = 0; + char * tag_name = NULL; + int dissected_len = 0; + int total_dissected_len = 0; + proto_tree * hdr_tree = NULL; + proto_item * hdr_item = NULL; + guint16 src_port = 0; + guint32 session_id = 0; + guint16 dest_port = 0; + lbtrm_transport_t * transport = NULL; + proto_tree * transport_tree = NULL; + proto_item * transport_item = NULL; + guint32 sequence = 0; + gboolean retransmission = FALSE; + guint8 packet_type = 0; + guint64 channel = LBM_CHANNEL_NO_CHANNEL; + guint8 ver_type = 0; + guint8 flags_fec_type = 0; + guint16 num_naks = 0; + guint16 num_ncfs = 0; + lbm_lbtrm_tap_info_t * tapinfo = NULL; + proto_item * header_type_item = NULL; + + col_add_str(pinfo->cinfo, COL_PROTOCOL, "LBT-RM"); + col_clear(pinfo->cinfo, COL_INFO); + if (lbtrm_use_tag) + { + tag_name = lbtrm_tag_find(pinfo); + } + if (tag_name != NULL) + { + col_add_fstr(pinfo->cinfo, COL_INFO, "[Tag: %s]", tag_name); + } + col_set_fence(pinfo->cinfo, COL_INFO); + + ver_type = tvb_get_guint8(tvb, O_LBTRM_HDR_T_VER_TYPE); + packet_type = LBTRM_HDR_TYPE(ver_type); + next_hdr = tvb_get_guint8(tvb, O_LBTRM_HDR_T_NEXT_HDR); + src_port = tvb_get_ntohs(tvb, O_LBTRM_HDR_T_UCAST_PORT); + session_id = tvb_get_ntohl(tvb, O_LBTRM_HDR_T_SESSION_ID); + if (tag_name != NULL) + { + lbtrm_item = proto_tree_add_protocol_format(tree, proto_lbtrm, tvb, offset, -1, "LBT-RM Protocol (Tag: %s): Version %u, Type %s: Source Unicast Port %" PRIu16 ", Session ID 0x%08x", + tag_name, LBTRM_HDR_VER(ver_type), val_to_str(packet_type, lbtrm_packet_type, "Unknown (0x%02x)"), + src_port, session_id); + } + else + { + lbtrm_item = proto_tree_add_protocol_format(tree, proto_lbtrm, tvb, offset, -1, "LBT-RM Protocol: Version %u, Type %s: Source Unicast Port %" PRIu16 ", Session ID 0x%08x", + LBTRM_HDR_VER(ver_type), val_to_str(packet_type, lbtrm_packet_type, "Unknown (0x%02x)"), + src_port, session_id); + } + lbtrm_tree = proto_item_add_subtree(lbtrm_item, ett_lbtrm); + + /* Addresses are in network order, ports in host order. */ + dest_port = pinfo->destport; + + if (PINFO_FD_VISITED(pinfo) == 0) + { + /* First time through - add the info. */ + /* Note that this won't handle the case when a NAK occurs in the capture before any other packets for that transport. Oh well. */ + if (packet_type == LBTRM_PACKET_TYPE_NAK) + { + transport = lbtrm_transport_unicast_find(&(pinfo->dst), src_port, session_id, pinfo->num); + } + else + { + transport = lbtrm_transport_add(&(pinfo->src), src_port, session_id, &(pinfo->dst), dest_port, pinfo->num); + } + } + else + { + if (packet_type == LBTRM_PACKET_TYPE_NAK) + { + transport = lbtrm_transport_unicast_find(&(pinfo->dst), src_port, session_id, pinfo->num); + } + else + { + transport = lbtrm_transport_find(&(pinfo->src), src_port, session_id, &(pinfo->dst), dest_port, pinfo->num); + } + } + if (transport != NULL) + { + proto_item * item = NULL; + + channel = transport->channel; + item = proto_tree_add_uint64(lbtrm_tree, hf_lbtrm_channel, tvb, 0, 0, channel); + proto_item_set_generated(item); + } + if (tag_name != NULL) + { + proto_item * item = NULL; + + item = proto_tree_add_string(lbtrm_tree, hf_lbtrm_tag, tvb, 0, 0, tag_name); + proto_item_set_generated(item); + } + tapinfo = wmem_new0(pinfo->pool, lbm_lbtrm_tap_info_t); + if (transport != NULL) + { + tapinfo->transport = lbtrm_transport_source_string_transport(pinfo->pool, transport); + } + tapinfo->type = packet_type; + + hdr_item = proto_tree_add_item(lbtrm_tree, hf_lbtrm_hdr, tvb, O_LBTRM_HDR_T_VER_TYPE, L_LBTRM_HDR_T, ENC_NA); + hdr_tree = proto_item_add_subtree(hdr_item, ett_lbtrm_hdr); + proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_ver, tvb, O_LBTRM_HDR_T_VER_TYPE, L_LBTRM_HDR_T_VER_TYPE, ENC_BIG_ENDIAN); + header_type_item = proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_type, tvb, O_LBTRM_HDR_T_VER_TYPE, L_LBTRM_HDR_T_VER_TYPE, ENC_BIG_ENDIAN); + /* Setup the INFO column for this packet. */ + switch (packet_type) + { + case LBTRM_PACKET_TYPE_DATA: + sequence = tvb_get_ntohl(tvb, L_LBTRM_HDR_T + O_LBTRM_DATA_HDR_T_SQN); + flags_fec_type = tvb_get_guint8(tvb, L_LBTRM_HDR_T + O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE); + if ((flags_fec_type & LBTRM_DATA_RETRANSMISSION_FLAG) != 0) + { + col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "DATA(RX) sqn 0x%x Port %" PRIu16 " ID 0x%08x", sequence, src_port, session_id); + } + else + { + col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "DATA sqn 0x%x Port %" PRIu16 " ID 0x%08x", sequence, src_port, session_id); + } + break; + case LBTRM_PACKET_TYPE_SM: + sequence = tvb_get_ntohl(tvb, L_LBTRM_HDR_T + O_LBTRM_SM_HDR_T_SM_SQN); + col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "SM sqn 0x%x Port %" PRIu16 " ID 0x%08x", sequence, src_port, session_id); + break; + case LBTRM_PACKET_TYPE_NAK: + num_naks = tvb_get_ntohs(tvb, L_LBTRM_HDR_T + O_LBTRM_NAK_HDR_T_NUM_NAKS); + col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "NAK %u naks Port %" PRIu16 " ID 0x%08x", num_naks, src_port, session_id); + break; + case LBTRM_PACKET_TYPE_NCF: + num_ncfs = tvb_get_ntohs(tvb, L_LBTRM_HDR_T + O_LBTRM_NCF_HDR_T_NUM_NCFS); + col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "NCF %u ncfs Port %" PRIu16 " ID 0x%08x", num_ncfs, src_port, session_id); + break; + default: + col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "Unknown (0x%02x)", packet_type); + expert_add_info_format(pinfo, header_type_item, &ei_lbtrm_analysis_invalid_value, "Unrecognized type 0x%02x", packet_type); + break; + } + + proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_next_hdr, tvb, O_LBTRM_HDR_T_NEXT_HDR, L_LBTRM_HDR_T_NEXT_HDR, ENC_BIG_ENDIAN); + proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_ucast_port, tvb, O_LBTRM_HDR_T_UCAST_PORT, L_LBTRM_HDR_T_UCAST_PORT, ENC_BIG_ENDIAN); + proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_session_id, tvb, O_LBTRM_HDR_T_SESSION_ID, L_LBTRM_HDR_T_SESSION_ID, ENC_BIG_ENDIAN); + total_dissected_len = L_LBTRM_HDR_T; + offset = L_LBTRM_HDR_T; + switch (packet_type) + { + case LBTRM_PACKET_TYPE_DATA: + dissected_len = dissect_lbtrm_data(tvb, offset, pinfo, lbtrm_tree, &sequence, &retransmission, tapinfo); + break; + case LBTRM_PACKET_TYPE_SM: + dissected_len = dissect_lbtrm_sm(tvb, offset, pinfo, lbtrm_tree, &sequence, tapinfo); + break; + case LBTRM_PACKET_TYPE_NAK: + dissected_len = dissect_lbtrm_nak(tvb, offset, pinfo, lbtrm_tree, tapinfo); + break; + case LBTRM_PACKET_TYPE_NCF: + dissected_len = dissect_lbtrm_ncf(tvb, offset, pinfo, lbtrm_tree, tapinfo); + break; + default: + return (total_dissected_len); + break; + } + total_dissected_len += dissected_len; + offset += dissected_len; + while (next_hdr != LBTRM_NHDR_DATA) + { + guint8 hdrlen = 0; + + next_hdr = tvb_get_guint8(tvb, offset + O_LBTRM_BASIC_OPT_T_NEXT_HDR); + hdrlen = tvb_get_guint8(tvb, offset + O_LBTRM_BASIC_OPT_T_HDR_LEN); + if (hdrlen == 0) + { + break; + } + offset += hdrlen; + total_dissected_len += hdrlen; + } + + if (lbtrm_sequence_analysis) + { + if (pinfo->fd->visited == 0) + { + if (transport != NULL) + { + lbtrm_transport_frame_add(transport, packet_type, pinfo->num, sequence, retransmission); + } + } + else + { + if (transport != NULL) + { + lbm_transport_frame_t * frame = NULL; + + /* Setup the tree */ + transport_item = proto_tree_add_item(lbtrm_tree, hf_lbtrm_analysis, tvb, 0, 0, ENC_NA); + proto_item_set_generated(transport_item); + transport_tree = proto_item_add_subtree(transport_item, ett_lbtrm_transport); + frame = lbtrm_transport_frame_find(transport, pinfo->num); + if (frame != NULL) + { + lbm_transport_sqn_t * sqn = NULL; + + if (frame->previous_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_frame, tvb, 0, 0, frame->previous_frame); + proto_item_set_generated(transport_item); + } + if (frame->next_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_frame, tvb, 0, 0, frame->next_frame); + proto_item_set_generated(transport_item); + } + switch (packet_type) + { + case LBTRM_PACKET_TYPE_DATA: + if (frame->previous_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_data_frame, tvb, 0, 0, frame->previous_type_frame); + proto_item_set_generated(transport_item); + } + if (frame->next_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_data_frame, tvb, 0, 0, frame->next_type_frame); + proto_item_set_generated(transport_item); + } + sqn = lbtrm_transport_sqn_find(transport, packet_type, sequence); + if (sqn != NULL) + { + if (sqn->frame_count > 1) + { + proto_tree * frame_tree = NULL; + proto_item * frame_tree_item = NULL; + lbtrm_sqn_frame_list_callback_data_t cb_data; + + frame_tree_item = proto_tree_add_item(transport_tree, hf_lbtrm_analysis_sqn, tvb, 0, 0, ENC_NA); + proto_item_set_generated(frame_tree_item); + frame_tree = proto_item_add_subtree(frame_tree_item, ett_lbtrm_transport_sqn); + cb_data.tree = frame_tree; + cb_data.tvb = tvb; + cb_data.current_frame = pinfo->num; + wmem_tree_foreach(sqn->frame, dissect_lbtrm_sqn_frame_list_callback, (void *) &cb_data); + } + } + if (frame->retransmission) + { + transport_item = proto_tree_add_boolean(transport_tree, hf_lbtrm_analysis_data_retransmission, tvb, 0, 0, TRUE); + proto_item_set_generated(transport_item); + expert_add_info(pinfo, transport_item, &ei_lbtrm_analysis_data_rx); + } + if (frame->sqn_gap != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_data_sqn_gap, tvb, 0, 0, frame->sqn_gap); + proto_item_set_generated(transport_item); + expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_data_gap, "Data sequence gap (%" PRIu32 ")", frame->sqn_gap); + } + if (frame->ooo_gap != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_data_ooo_gap, tvb, 0, 0, frame->ooo_gap); + proto_item_set_generated(transport_item); + expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_data_ooo, "Data sequence out of order gap (%" PRIu32 ")", frame->ooo_gap); + } + if (frame->duplicate) + { + transport_item = proto_tree_add_boolean(transport_tree, hf_lbtrm_analysis_data_duplicate, tvb, 0, 0, TRUE); + proto_item_set_generated(transport_item); + expert_add_info(pinfo, transport_item, &ei_lbtrm_analysis_data_dup); + } + break; + case LBTRM_PACKET_TYPE_SM: + if (frame->previous_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_sm_frame, tvb, 0, 0, frame->previous_type_frame); + proto_item_set_generated(transport_item); + } + if (frame->next_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_sm_frame, tvb, 0, 0, frame->next_type_frame); + proto_item_set_generated(transport_item); + } + sqn = lbtrm_transport_sqn_find(transport, packet_type, sequence); + if (sqn != NULL) + { + if (sqn->frame_count > 1) + { + proto_tree * frame_tree = NULL; + proto_item * frame_tree_item = NULL; + lbtrm_sqn_frame_list_callback_data_t cb_data; + + frame_tree_item = proto_tree_add_item(transport_tree, hf_lbtrm_analysis_sqn, tvb, 0, 0, ENC_NA); + proto_item_set_generated(frame_tree_item); + frame_tree = proto_item_add_subtree(frame_tree_item, ett_lbtrm_transport_sqn); + cb_data.tree = frame_tree; + cb_data.tvb = tvb; + cb_data.current_frame = pinfo->num; + wmem_tree_foreach(sqn->frame, dissect_lbtrm_sqn_frame_list_callback, (void *) &cb_data); + } + } + if (frame->sqn_gap != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_sm_sqn_gap, tvb, 0, 0, frame->sqn_gap); + proto_item_set_generated(transport_item); + expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_sm_gap, "SM sequence gap (%" PRIu32 ")", frame->sqn_gap); + } + if (frame->ooo_gap != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_sm_ooo_gap, tvb, 0, 0, frame->ooo_gap); + proto_item_set_generated(transport_item); + expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_sm_ooo, "SM sequence out of order gap (%" PRIu32 ")", frame->ooo_gap); + } + if (frame->duplicate) + { + transport_item = proto_tree_add_boolean(transport_tree, hf_lbtrm_analysis_sm_duplicate, tvb, 0, 0, TRUE); + proto_item_set_generated(transport_item); + expert_add_info(pinfo, transport_item, &ei_lbtrm_analysis_sm_dup); + } + break; + case LBTRM_PACKET_TYPE_NAK: + if (frame->previous_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_nak_frame, tvb, 0, 0, frame->previous_type_frame); + proto_item_set_generated(transport_item); + } + if (frame->next_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_nak_frame, tvb, 0, 0, frame->next_type_frame); + proto_item_set_generated(transport_item); + } + break; + case LBTRM_PACKET_TYPE_NCF: + if (frame->previous_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_ncf_frame, tvb, 0, 0, frame->previous_type_frame); + proto_item_set_generated(transport_item); + } + if (frame->next_type_frame != 0) + { + transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_ncf_frame, tvb, 0, 0, frame->next_type_frame); + proto_item_set_generated(transport_item); + } + break; + default: + break; + } + } + } + } + } + proto_item_set_len(lbtrm_item, total_dissected_len); + if ((packet_type == LBTRM_PACKET_TYPE_DATA) && (next_hdr == LBTRM_NHDR_DATA)) + { + total_dissected_len += dissect_lbtrm_data_contents(tvb, offset, pinfo, tree, tag_name, channel); + } + if (tapinfo->transport != NULL) + { + tap_queue_packet(lbtrm_tap_handle, pinfo, (void *) tapinfo); + } + return (total_dissected_len); +} + +static gboolean test_lbtrm_packet(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data) +{ + guint32 dest_addr_h; + gboolean valid_packet = FALSE; + guint8 ver_type = 0; + guint8 packet_type = 0; + guint8 packet_ver = 0; + guint8 next_hdr = 0; + + /* Must be a UDP packet. */ + if (pinfo->ptype != PT_UDP) + { + return (FALSE); + } + /* Destination address must be IPV4 and 4 bytes in length. */ + if ((pinfo->dst.type != AT_IPv4) || (pinfo->dst.len != 4)) + { + return (FALSE); + } + if (tvb_reported_length_remaining(tvb, 0) < L_LBTRM_HDR_T) + { + return (FALSE); + } + ver_type = tvb_get_guint8(tvb, O_LBTRM_HDR_T_VER_TYPE); + packet_type = LBTRM_HDR_TYPE(ver_type); + switch (packet_type) + { + case LBTRM_PACKET_TYPE_DATA: + case LBTRM_PACKET_TYPE_SM: + case LBTRM_PACKET_TYPE_NAK: + case LBTRM_PACKET_TYPE_NCF: + break; + default: + return (FALSE); + } + packet_ver = LBTRM_HDR_VER(ver_type); + if (packet_ver != LBTRM_VERSION) + { + return (FALSE); + } + next_hdr = tvb_get_guint8(tvb, O_LBTRM_HDR_T_NEXT_HDR); + if (next_hdr != LBTRM_NHDR_DATA) + { + return (FALSE); + } + if (lbtrm_use_tag) + { + if (lbtrm_tag_find(pinfo) != NULL) + { + valid_packet = TRUE; + } + } + else + { + dest_addr_h = pntoh32(pinfo->dst.data); + + /* Is the destination a multicast address? */ + if (IN_MULTICAST(dest_addr_h)) + { + /* Check the MC address. */ + if ((dest_addr_h >= lbtrm_mc_address_low_host) && (dest_addr_h <= lbtrm_mc_address_high_host)) + { + /* It's in the LBT-RM multicast range. Check the ports. */ + if ((pinfo->destport >= lbtrm_dest_port_low) && (pinfo->destport <= lbtrm_dest_port_high)) + { + /* Must be one of ours. */ + valid_packet = TRUE; + } + } + else if ((dest_addr_h == mim_incoming_mc_address_host) || (dest_addr_h == mim_outgoing_mc_address_host)) + { + /* Might be MIM. Check the port. */ + if (((dest_addr_h == mim_incoming_mc_address_host) && (pinfo->destport == mim_incoming_dest_port)) + || ((dest_addr_h == mim_outgoing_mc_address_host) && (pinfo->destport == mim_outgoing_dest_port))) + { + /* Must be one of ours. */ + valid_packet = TRUE; + } + } + } + else + { + /* Not multicast, might be a unicast UDP NAK. Check the destination port. */ + if ((pinfo->destport >= lbtrm_src_port_low) && (pinfo->destport <= lbtrm_src_port_high)) + { + valid_packet = TRUE; + } + } + } + if (valid_packet) + { + dissect_lbtrm(tvb, pinfo, tree, user_data); + return (TRUE); + } + return (FALSE); +} + +/* Register all the bits needed with the filtering engine */ +void proto_register_lbtrm(void) +{ + static hf_register_info hf[] = + { + { &hf_lbtrm_channel, + { "Channel ID", "lbtrm.channel", FT_UINT64, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_tag, + { "Tag", "lbtrm.tag", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_hdr, + { "Header", "lbtrm.hdr", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_hdr_ver, + { "Version", "lbtrm.hdr.ver", FT_UINT8, BASE_HEX, NULL, LBTRM_HDR_VER_MASK, NULL, HFILL } }, + { &hf_lbtrm_hdr_type, + { "Type", "lbtrm.hdr.type", FT_UINT8, BASE_HEX, VALS(lbtrm_packet_type), LBTRM_HDR_TYPE_MASK, NULL, HFILL } }, + { &hf_lbtrm_hdr_next_hdr, + { "Next Header", "lbtrm.hdr.next_hdr", FT_UINT8, BASE_HEX, VALS(lbtrm_next_header), 0x0, NULL, HFILL } }, + { &hf_lbtrm_hdr_ucast_port, + { "Source Unicast Port", "lbtrm.hdr.ucast_port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_hdr_session_id, + { "Session ID", "lbtrm.hdr.session_id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_data, + { "Data Header", "lbtrm.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_data_sqn, + { "Sequence Number", "lbtrm.data.sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_data_trail_sqn, + { "Trailing Edge Sequence Number", "lbtrm.data.trail_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_data_flags_fec_type, + { "FEC Flags", "lbtrm.data.flags_fec_type", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_data_flags_fec_type_ucast_naks, + { "Unicast NAKs", "lbtrm.data.flags_fec_type.ucast_naks", FT_BOOLEAN, L_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE * 8, TFS(&tfs_set_notset), LBTRM_DATA_UNICAST_NAKS_FLAG, "Set if NAKs are sent via unicast", HFILL } }, + { &hf_lbtrm_data_flags_fec_type_rx, + { "Retransmission", "lbtrm.data.flags_fec_type.rx", FT_BOOLEAN, L_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE * 8, TFS(&tfs_set_notset), LBTRM_DATA_RETRANSMISSION_FLAG, "Set if this is a retransmission", HFILL } }, + { &hf_lbtrm_data_flags_tgsz, + { "TGSZ Flags", "lbtrm.data.flags_tgsz", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_data_fec_symbol, + { "FEC Symbol", "lbtrm.data.fec_symbol", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_sm, + { "Session Message Header", "lbtrm.sm", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_sm_sm_sqn, + { "Sequence Number", "lbtrm.sm.sm_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_sm_lead_sqn, + { "Lead Sequence Number", "lbtrm.sm.lead_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_sm_trail_sqn, + { "Trail Sequence Number", "lbtrm.sm.trail_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_sm_flags_fec_type, + { "FEC Flags", "lbtrm.sm.flags_fec_type", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_sm_flags_fec_type_ucast_naks, + { "Unicast NAKs", "lbtrm.sm.flags_fec_type.ucast_naks", FT_BOOLEAN, 8, TFS(&tfs_present_not_present), LBTRM_SM_UNICAST_NAKS_FLAG, "Set if NAKs are sent via unicast", HFILL } }, + { &hf_lbtrm_sm_flags_tgsz, + { "TGSZ Flags", "lbtrm.sm.flags_tgsz", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_sm_reserved, + { "Reserved", "lbtrm.sm.reserved", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_nak, + { "NAK Header", "lbtrm.nak", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_nak_num_naks, + { "Number of NAKs", "lbtrm.nak.num_naks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_nak_format, + { "Format", "lbtrm.nak.format", FT_UINT8, BASE_HEX, VALS(lbtrm_nak_format), LBTRM_NAK_HDR_FORMAT_MASK, NULL, HFILL } }, + { &hf_lbtrm_nak_list, + { "NAK List", "lbtrm.nak.list", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_nak_list_nak, + { "NAK", "lbtrm.nak.list.nak", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_ncf, + { "NAK Confirmation Header", "lbtrm.ncf", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_ncf_trail_sqn, + { "Trailing Sequence Number", "lbtrm.ncf.trail_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_ncf_num_ncfs, + { "Number of Individual NCFs", "lbtrm.ncf.num_ncfs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_ncf_reserved, + { "Reserved", "lbtrm.ncf.reserved", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_ncf_reason, + { "Reason", "lbtrm.ncf.reason", FT_UINT8, BASE_HEX, VALS(lbtrm_ncf_reason), LBTRM_NCF_HDR_REASON_MASK, NULL, HFILL } }, + { &hf_lbtrm_ncf_format, + { "Format", "lbtrm.ncf.format", FT_UINT8, BASE_HEX, VALS(lbtrm_ncf_format), LBTRM_NCF_HDR_FORMAT_MASK, NULL, HFILL } }, + { &hf_lbtrm_ncf_list, + { "NCF List", "lbtrm.ncf.list", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_ncf_list_ncf, + { "NCF", "lbtrm.ncf.list.ncf", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis, + { "Transport Analysis", "lbtrm.transport", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_prev_frame, + { "Previous Transport frame", "lbtrm.transport.prev_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_prev_data_frame, + { "Previous Transport DATA frame", "lbtrm.transport.prev_data_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_prev_sm_frame, + { "Previous Transport SM frame", "lbtrm.transport.prev_sm_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_prev_nak_frame, + { "Previous Transport NAK frame", "lbtrm.transport.prev_nak_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_prev_ncf_frame, + { "Previous Transport NCF frame", "lbtrm.transport.prev_ncf_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_next_frame, + { "Next Transport frame", "lbtrm.transport.next_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_next_data_frame, + { "Next Transport DATA frame", "lbtrm.transport.next_data_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_next_sm_frame, + { "Next Transport SM frame", "lbtrm.transport.next_sm_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_next_nak_frame, + { "Next Transport NAK frame", "lbtrm.transport.next_nak_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_next_ncf_frame, + { "Next Transport NCF frame", "lbtrm.transport.next_ncf_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_sqn, + { "SQN Also in", "lbtrm.transport.sqn", FT_NONE, BASE_NONE, NULL, 0x0, "Sequence number also appears in these frames", HFILL } }, + { &hf_lbtrm_analysis_sqn_frame, + { "Frame", "lbtrm.transport.sqn.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_data_retransmission, + { "Frame is a Data Retransmission", "lbtrm.transport.data_retransmission", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_data_sqn_gap, + { "Gap in Data Sequence", "lbtrm.transport.data_sqn_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_data_ooo_gap, + { "Data Sequence Out of Order Gap", "lbtrm.transport.data_ooo_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_data_duplicate, + { "Duplicate Data frame", "lbtrm.transport.data_duplicate", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_sm_sqn_gap, + { "Gap in SM Sequence", "lbtrm.transport.sm_sqn_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_sm_ooo_gap, + { "SM Sequence Out of Order Gap", "lbtrm.transport.sm_ooo_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_lbtrm_analysis_sm_duplicate, + { "Duplicate SM frame", "lbtrm.transport.sm_duplicate", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + }; + static gint * ett[] = + { + &ett_lbtrm, + &ett_lbtrm_hdr, + &ett_lbtrm_data, + &ett_lbtrm_data_flags_fec_type, + &ett_lbtrm_sm, + &ett_lbtrm_sm_flags_fec_type, + &ett_lbtrm_nak, + &ett_lbtrm_nak_list, + &ett_lbtrm_ncf, + &ett_lbtrm_ncf_list, + &ett_lbtrm_transport, + &ett_lbtrm_transport_sqn + }; + static ei_register_info ei[] = + { + { &ei_lbtrm_analysis_ncf, { "lbtrm.analysis.ncf", PI_SEQUENCE, PI_NOTE, "NCF", EXPFILL } }, + { &ei_lbtrm_analysis_ncf_ncf, { "lbtrm.analysis.ncf.ncf", PI_SEQUENCE, PI_NOTE, "NCF", EXPFILL } }, + { &ei_lbtrm_analysis_nak, { "lbtrm.analysis.nak", PI_SEQUENCE, PI_WARN, "NAK", EXPFILL } }, + { &ei_lbtrm_analysis_nak_nak, { "lbtrm.analysis.nak.nak", PI_SEQUENCE, PI_WARN, "NAK", EXPFILL } }, + { &ei_lbtrm_analysis_sm, { "lbtrm.analysis.sm", PI_SEQUENCE, PI_CHAT, "SM", EXPFILL } }, + { &ei_lbtrm_analysis_rx, { "lbtrm.analysis.rx", PI_SEQUENCE, PI_NOTE, "RX", EXPFILL } }, + { &ei_lbtrm_analysis_invalid_value, { "lbtrm.analysis.invalid_value", PI_MALFORMED, PI_ERROR, "Invalid value", EXPFILL } }, + { &ei_lbtrm_analysis_data_rx, { "lbtrm.analysis.data.rx", PI_SEQUENCE, PI_NOTE, "Data RX", EXPFILL } }, + { &ei_lbtrm_analysis_data_gap, { "lbtrm.analysis.data.gap", PI_SEQUENCE, PI_NOTE, "Data sequence gap", EXPFILL } }, + { &ei_lbtrm_analysis_data_ooo, { "lbtrm.analysis.data.ooo", PI_SEQUENCE, PI_NOTE, "Data out of order", EXPFILL } }, + { &ei_lbtrm_analysis_data_dup, { "lbtrm.analysis.data.dup", PI_SEQUENCE, PI_NOTE, "Duplicate data", EXPFILL } }, + { &ei_lbtrm_analysis_sm_gap, { "lbtrm.analysis.sm.gap", PI_SEQUENCE, PI_NOTE, "SM sequence gap", EXPFILL } }, + { &ei_lbtrm_analysis_sm_ooo, { "lbtrm.analysis.sm.ooo", PI_SEQUENCE, PI_NOTE, "SM out of order", EXPFILL } }, + { &ei_lbtrm_analysis_sm_dup, { "lbtrm.analysis.sm.dup", PI_SEQUENCE, PI_NOTE, "Duplicate SM", EXPFILL } }, + }; + module_t * lbtrm_module; + guint32 addr; + uat_t * tag_uat; + expert_module_t * expert_lbtrm; + + proto_lbtrm = proto_register_protocol("LBT Reliable Multicast Protocol", + "LBT-RM", "lbtrm"); + + proto_register_field_array(proto_lbtrm, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_lbtrm = expert_register_protocol(proto_lbtrm); + expert_register_field_array(expert_lbtrm, ei, array_length(ei)); + + lbtrm_dissector_handle = register_dissector("lbtrm", dissect_lbtrm, proto_lbtrm); + + lbtrm_module = prefs_register_protocol_subtree("29West", proto_lbtrm, proto_reg_handoff_lbtrm); + ws_inet_pton4(LBTRM_DEFAULT_MC_ADDRESS_LOW, &addr); + lbtrm_mc_address_low_host = g_ntohl(addr); + prefs_register_string_preference(lbtrm_module, + "mc_address_low", + "Multicast address range low (default " LBTRM_DEFAULT_MC_ADDRESS_LOW ")", + "Set the low end of the LBT-RM multicast address range (context transport_lbtrm_multicast_address_low)", + &global_lbtrm_mc_address_low); + + ws_inet_pton4(LBTRM_DEFAULT_MC_ADDRESS_HIGH, &addr); + lbtrm_mc_address_high_host = g_ntohl(addr); + prefs_register_string_preference(lbtrm_module, + "mc_address_high", + "Multicast address range high (default " LBTRM_DEFAULT_MC_ADDRESS_HIGH ")", + "Set the high end of the LBT-RM multicast address range (context transport_lbtrm_multicast_address_high)", + &global_lbtrm_mc_address_high); + + prefs_register_uint_preference(lbtrm_module, + "dport_low", + "Destination port range low (default " MAKESTRING(LBTRM_DEFAULT_DPORT_LOW)")", + "Set the low end of the LBT-RM UDP destination port range (source transport_lbtrm_destination_port)", + 10, + &global_lbtrm_dest_port_low); + + prefs_register_uint_preference(lbtrm_module, + "dport_high", + "Destination port range high (default " MAKESTRING(LBTRM_DEFAULT_DPORT_HIGH)")", + "Set the high end of the LBT-RM UDP destination port range (source transport_lbtrm_destination_port)", + 10, + &global_lbtrm_dest_port_high); + + prefs_register_uint_preference(lbtrm_module, + "sport_low", + "Source port range low (default " MAKESTRING(LBTRM_DEFAULT_SPORT_LOW)")", + "Set the low end of the LBT-RM UDP source port range (context transport_lbtrm_source_port_low)", + 10, + &global_lbtrm_src_port_low); + + prefs_register_uint_preference(lbtrm_module, + "sport_high", + "Source port range high (default " MAKESTRING(LBTRM_DEFAULT_SPORT_HIGH)")", + "Set the high end of the LBT-RM UDP source port range (context transport_lbtrm_source_port_high)", + 10, + &global_lbtrm_src_port_high); + + ws_inet_pton4(MIM_DEFAULT_MC_INCOMING_ADDRESS, &addr); + mim_incoming_mc_address_host = g_ntohl(addr); + prefs_register_string_preference(lbtrm_module, + "mim_incoming_address", + "MIM incoming multicast address (default " MIM_DEFAULT_MC_INCOMING_ADDRESS ")", + "Set the incoming MIM multicast address (context mim_incoming_address)", + &global_mim_incoming_mc_address); + + ws_inet_pton4(MIM_DEFAULT_MC_OUTGOING_ADDRESS, &addr); + mim_outgoing_mc_address_host = g_ntohl(addr); + prefs_register_string_preference(lbtrm_module, + "mim_outgoing_address", + "MIM outgoing multicast address (default " MIM_DEFAULT_MC_OUTGOING_ADDRESS ")", + "Set the outgoing MIM multicast address (context mim_outgoing_address)", + &global_mim_outgoing_mc_address); + + prefs_register_uint_preference(lbtrm_module, + "mim_incoming_dport", + "MIM incoming port (default " MAKESTRING(MIM_DEFAULT_INCOMING_DPORT)")", + "Set the incoming MIM UDP port (context mim_incoming_destination_port)", + 10, + &global_mim_incoming_dest_port); + + prefs_register_uint_preference(lbtrm_module, + "mim_outgoing_dport", + "MIM outgoing port (default " MAKESTRING(MIM_DEFAULT_OUTGOING_DPORT)")", + "Set the outgoing MIM UDP port (context mim_outgoing_destination_port)", + 10, + &global_mim_outgoing_dest_port); + + lbtrm_expert_separate_naks = global_lbtrm_expert_separate_naks; + prefs_register_bool_preference(lbtrm_module, + "expert_separate_naks", + "Separate NAKs in Expert Info", + "Separate multiple NAKs from a single packet into distinct Expert Info entries", + &global_lbtrm_expert_separate_naks); + + lbtrm_expert_separate_ncfs = global_lbtrm_expert_separate_ncfs; + prefs_register_bool_preference(lbtrm_module, + "expert_separate_ncfs", + "Separate NCFs in Expert Info", + "Separate multiple NCFs from a single packet into distinct Expert Info entries", + &global_lbtrm_expert_separate_ncfs); + + lbtrm_sequence_analysis = global_lbtrm_sequence_analysis; + prefs_register_bool_preference(lbtrm_module, + "sequence_analysis", + "Perform sequence Number Analysis", + "Perform analysis on LBT-RM sequence numbers to determine out-of-order, gaps, loss, etc", + &global_lbtrm_sequence_analysis); + + lbtrm_use_tag = global_lbtrm_use_tag; + prefs_register_bool_preference(lbtrm_module, + "use_lbtrm_domain", + "Use LBT-RM tag table", + "Use table of LBT-RM tags to decode the packet instead of above values", + &global_lbtrm_use_tag); + tag_uat = uat_new("LBT-RM tag definitions", + sizeof(lbtrm_tag_entry_t), + "lbtrm_domains", + TRUE, + (void * *)&lbtrm_tag_entry, + &lbtrm_tag_count, + UAT_AFFECTS_DISSECTION, + NULL, + lbtrm_tag_copy_cb, + lbtrm_tag_update_cb, + lbtrm_tag_free_cb, + NULL, + NULL, + lbtrm_tag_array); + prefs_register_uat_preference(lbtrm_module, + "tnw_lbtrm_tags", + "LBT-RM Tags", + "A table to define LBT-RM tags", + tag_uat); +} + +/* The registration hand-off routine */ +void proto_reg_handoff_lbtrm(void) +{ + static gboolean already_registered = FALSE; + guint32 addr; + guint32 dest_addr_h_low; + guint32 dest_addr_h_high; + + if (!already_registered) + { + dissector_add_for_decode_as_with_preference("udp.port", lbtrm_dissector_handle); + heur_dissector_add("udp", test_lbtrm_packet, "LBT Reliable Multicast over UDP", "lbtrm_udp", proto_lbtrm, HEURISTIC_ENABLE); + lbtrm_tap_handle = register_tap("lbm_lbtrm"); + } + + /* Make sure the low MC address is <= the high MC address. If not, don't change them. */ + ws_inet_pton4(global_lbtrm_mc_address_low, &addr); + dest_addr_h_low = g_ntohl(addr); + ws_inet_pton4(global_lbtrm_mc_address_high, &addr); + dest_addr_h_high = g_ntohl(addr); + if (dest_addr_h_low <= dest_addr_h_high) + { + lbtrm_mc_address_low_host = dest_addr_h_low; + lbtrm_mc_address_high_host = dest_addr_h_high; + } + + /* Make sure the low destination port is <= the high destination port. If not, don't change them. */ + if (global_lbtrm_dest_port_low <= global_lbtrm_dest_port_high) + { + lbtrm_dest_port_low = global_lbtrm_dest_port_low; + lbtrm_dest_port_high = global_lbtrm_dest_port_high; + } + + /* Make sure the low source port is <= the high source port. If not, don't change them. */ + if (global_lbtrm_src_port_low <= global_lbtrm_src_port_high) + { + lbtrm_src_port_low = global_lbtrm_src_port_low; + lbtrm_src_port_high = global_lbtrm_src_port_high; + } + + /* Add the dissector hooks for the MIM MC groups. */ + ws_inet_pton4(global_mim_incoming_mc_address, &addr); + mim_incoming_mc_address_host = g_htonl(addr); + ws_inet_pton4(global_mim_outgoing_mc_address, &addr); + mim_outgoing_mc_address_host = g_htonl(addr); + + /* Add the dissector hooks for the MIM ports. */ + mim_incoming_dest_port = global_mim_incoming_dest_port; + mim_outgoing_dest_port = global_mim_outgoing_dest_port; + + lbtrm_expert_separate_naks = global_lbtrm_expert_separate_naks; + lbtrm_expert_separate_ncfs = global_lbtrm_expert_separate_ncfs; + + lbtrm_sequence_analysis = global_lbtrm_sequence_analysis; + + lbtrm_use_tag = global_lbtrm_use_tag; + + already_registered = TRUE; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |