# include "config.h"
#endif
+#include <string.h>
+
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>
/* TODO:
- - Update to latest version of 36.323
- Complete ROHC support for RTP and extend to other profiles (including ROHCv2)
- - Support for decryption
+ - Support for deciphering
- Verify MAC authentication bytes
- - Call LTE RRC dissector for uncompressed, signalling payloads
*/
/* Initialize the protocol and registered fields. */
int proto_pdcp_lte = -1;
-static int hf_pdcp_lte_configuration = -1;
+extern int proto_rlc_lte;
+/* Configuration (info known outside of PDU) */
+static int hf_pdcp_lte_configuration = -1;
static int hf_pdcp_lte_direction = -1;
+static int hf_pdcp_lte_ueid = -1;
+static int hf_pdcp_lte_channel_type = -1;
+static int hf_pdcp_lte_channel_id = -1;
static int hf_pdcp_lte_rohc = -1;
static int hf_pdcp_lte_rohc_compression = -1;
static int hf_pdcp_lte_rohc_mode = -1;
static int hf_pdcp_lte_no_header_pdu = -1;
static int hf_pdcp_lte_plane = -1;
static int hf_pdcp_lte_seqnum_length = -1;
-
static int hf_pdcp_lte_cid_inclusion_info = -1;
static int hf_pdcp_lte_large_cid_present = -1;
+/* PDCP header fields */
static int hf_pdcp_lte_seq_num_5 = -1;
static int hf_pdcp_lte_seq_num_7 = -1;
static int hf_pdcp_lte_reserved3 = -1;
static int hf_pdcp_lte_bitmap = -1;
static int hf_pdcp_lte_bitmap_not_received = -1;
+/* Robust Header Compression Fields */
static int hf_pdcp_lte_rohc_padding = -1;
static int hf_pdcp_lte_rohc_r_0_crc = -1;
static int hf_pdcp_lte_rohc_feedback = -1;
static int hf_pdcp_lte_rohc_ts = -1;
static int hf_pdcp_lte_rohc_m = -1;
-static int hf_pdcp_lte_uor2_sn = -1;
-static int hf_pdcp_lte_uor2_x = -1;
+static int hf_pdcp_lte_rohc_uor2_sn = -1;
+static int hf_pdcp_lte_rohc_uor2_x = -1;
+
+static int hf_pdcp_lte_rohc_add_cid = -1;
+static int hf_pdcp_lte_rohc_large_cid = -1;
-static int hf_pdcp_lte_add_cid = -1;
-static int hf_pdcp_lte_large_cid = -1;
+static int hf_pdcp_lte_rohc_uo0_sn = -1;
+static int hf_pdcp_lte_rohc_uo0_crc = -1;
-static int hf_pdcp_lte_uo0_sn = -1;
-static int hf_pdcp_lte_uo0_crc = -1;
+static int hf_pdcp_lte_rohc_r0_sn = -1;
+static int hf_pdcp_lte_rohc_r0_crc_sn = -1;
+static int hf_pdcp_lte_rohc_r0_crc_crc = -1;
-static int hf_pdcp_lte_r0_sn = -1;
-static int hf_pdcp_lte_r0_crc_sn = -1;
-static int hf_pdcp_lte_r0_crc_crc = -1;
+static int hf_pdcp_lte_rohc_feedback_code = -1;
+static int hf_pdcp_lte_rohc_feedback_size = -1;
+static int hf_pdcp_lte_rohc_feedback_feedback1 = -1;
+static int hf_pdcp_lte_rohc_feedback_feedback2 = -1;
+static int hf_pdcp_lte_rohc_feedback_ack_type = -1;
+static int hf_pdcp_lte_rohc_feedback_mode = -1;
+static int hf_pdcp_lte_rohc_feedback_sn = -1;
+static int hf_pdcp_lte_rohc_feedback_option = -1;
+static int hf_pdcp_lte_rohc_feedback_length = -1;
+static int hf_pdcp_lte_rohc_feedback_crc = -1;
+static int hf_pdcp_lte_rohc_feedback_option_sn = -1;
+static int hf_pdcp_lte_rohc_feedback_option_clock = -1;
+
+static int hf_pdcp_lte_rohc_ip_id = -1;
+static int hf_pdcp_lte_rohc_udp_checksum = -1;
+static int hf_pdcp_lte_rohc_payload = -1;
+
+/* Sequence Analysis */
+static int hf_pdcp_lte_sequence_analysis = -1;
+static int hf_pdcp_lte_sequence_analysis_ok = -1;
+static int hf_pdcp_lte_sequence_analysis_previous_frame = -1;
+static int hf_pdcp_lte_sequence_analysis_expected_sn = -1;
+
+static int hf_pdcp_lte_sequence_analysis_repeated = -1;
+static int hf_pdcp_lte_sequence_analysis_skipped = -1;
-static int hf_pdcp_lte_feedback_code = -1;
-static int hf_pdcp_lte_feedback_size = -1;
-static int hf_pdcp_lte_feedback_feedback1 = -1;
-static int hf_pdcp_lte_feedback_feedback2 = -1;
-static int hf_pdcp_lte_feedback_ack_type = -1;
-static int hf_pdcp_lte_feedback_mode = -1;
-static int hf_pdcp_lte_feedback_sn = -1;
-static int hf_pdcp_lte_feedback_option = -1;
-static int hf_pdcp_lte_feedback_length = -1;
-static int hf_pdcp_lte_feedback_crc = -1;
-static int hf_pdcp_lte_feedback_option_sn = -1;
-static int hf_pdcp_lte_feedback_option_clock = -1;
-static int hf_pdcp_lte_ip_id = -1;
-static int hf_pdcp_lte_udp_checksum = -1;
-static int hf_pdcp_lte_payload = -1;
/* Protocol subtree. */
static int ett_pdcp = -1;
static int ett_pdcp_configuration = -1;
static int ett_pdcp_packet = -1;
+static int ett_pdcp_lte_sequence_analysis = -1;
static int ett_pdcp_rohc = -1;
static int ett_pdcp_rohc_static_ipv4 = -1;
static int ett_pdcp_rohc_static_udp = -1;
{ 0, NULL }
};
+static const value_string logical_channel_vals[] = {
+ { Channel_DCCH, "DCCH"},
+ { Channel_BCCH, "BCCH"},
+ { Channel_CCCH, "CCCH"},
+ { Channel_PCCH, "PCCH"},
+ { 0, NULL}
+};
static const value_string rohc_mode_vals[] = {
{ UNIDIRECTIONAL, "Unidirectional" },
};
-/* TODO: add more */
+/* Values taken from:
+ http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.txt */
static const value_string rohc_profile_vals[] = {
- { 0, "Uncompressed" },
- { 1, "RTP" },
- { 2, "UDP" },
- { 3, "ESP/IP" },
- { 0, NULL }
+ { 0x0000, "ROHC uncompressed" }, /* [RFC5795] */
+ { 0x0001, "ROHC RTP" }, /* [RFC3095] */
+ { 0x0101, "ROHCv2 RTP" }, /* [RFC5225] */
+ { 0x0002, "ROHC UDP" }, /* [RFC3095] */
+ { 0x0102, "ROHCv2 UDP" }, /* [RFC5225] */
+ { 0x0003, "ROHC ESP" }, /* [RFC3095] */
+ { 0x0103, "ROHCv2 ESP" }, /* [RFC5225] */
+ { 0x0004, "ROHC IP" }, /* [RFC3843] */
+ { 0x0104, "ROHCv2 IP" }, /* [RFC5225] */
+ { 0x0005, "ROHC LLA" }, /* [RFC4362] */
+ { 0x0105, "ROHC LLA with R-mode" }, /* [RFC3408] */
+ { 0x0006, "ROHC TCP" }, /* [RFC4996] */
+ { 0x0007, "ROHC RTP/UDP-Lite" }, /* [RFC4019] */
+ { 0x0107, "ROHCv2 RTP/UDP-Lite" }, /* [RFC5225] */
+ { 0x0008, "ROHC UDP-Lite" }, /* [RFC4019] */
+ { 0x0108, "ROHCv2 UDP-Lite" }, /* [RFC5225] */
+ { 0, NULL }
};
static const value_string pdu_type_vals[] = {
};
-dissector_handle_t ip_handle = 0;
+static dissector_handle_t ip_handle;
/* Preference variables */
static gboolean global_pdcp_show_feedback_option_tag_length = FALSE;
static gboolean global_pdcp_dissect_user_plane_as_ip = FALSE;
static gboolean global_pdcp_dissect_signalling_plane_as_rrc = FALSE;
+static gboolean global_pdcp_check_sequence_numbers = FALSE;
static gboolean global_pdcp_dissect_rohc = FALSE;
+
+/**************************************************/
+/* Sequence number analysis */
+
+/* Channel key */
+typedef struct
+{
+ guint16 ueId;
+ LogicalChannelType channelType;
+ guint16 channelId;
+ guint8 direction;
+} pdcp_channel_hash_key;
+
+/* Channel state */
+typedef struct
+{
+ guint16 previousSequenceNumber;
+ guint32 previousFrameNum;
+} pdcp_channel_status;
+
+/* The sequence analysis channel hash table.
+ Maps key -> status */
+static GHashTable *pdcp_sequence_analysis_channel_hash = NULL;
+
+/* Equal keys */
+static gint pdcp_channel_equal(gconstpointer v, gconstpointer v2)
+{
+ const pdcp_channel_hash_key* val1 = v;
+ const pdcp_channel_hash_key* val2 = v2;
+
+ /* All fields must match */
+ return (memcmp(val1, val2, sizeof(pdcp_channel_hash_key)) == 0);
+}
+
+/* Compute a hash value for a given key. */
+static guint pdcp_channel_hash_func(gconstpointer v)
+{
+ const pdcp_channel_hash_key* val1 = v;
+
+ /* TODO: use multipliers */
+ return val1->ueId + val1->channelType + val1->channelId + val1->direction;
+}
+
+/* Hash table functions for frame reports */
+
+/* TODO: copied from packet-rlc-lte.c. extern, or add to lib? */
+/* Equal keys */
+static gint pdcp_frame_equal(gconstpointer v, gconstpointer v2)
+{
+ return (v == v2);
+}
+
+/* Compute a hash value for a given key. */
+static guint pdcp_frame_hash_func(gconstpointer v)
+{
+ return GPOINTER_TO_UINT(v);
+}
+
+
+/* Info to attach to frame when first read, recording what to show about sequence */
+typedef struct
+{
+ gboolean sequenceExpectedCorrect;
+ guint16 sequenceExpected;
+ guint32 previousFrameNum;
+
+ guint16 firstSN;
+ guint16 lastSN;
+
+ enum { SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing} state;
+} pdcp_sequence_report_in_frame;
+
+/* The sequence analysis frame report hash table instance itself */
+static GHashTable *pdcp_lte_frame_sequence_analysis_report_hash = NULL;
+
+
+/* Add to the tree values associated with sequence analysis for this frame */
+static void addChannelSequenceInfo(pdcp_sequence_report_in_frame *p,
+ pdcp_lte_info *p_pdcp_lte_info,
+ guint16 sequenceNumber,
+ packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
+{
+ proto_tree *seqnum_tree;
+ proto_item *seqnum_ti;
+ proto_item *ti;
+
+ /* Create subtree */
+ seqnum_ti = proto_tree_add_string_format(tree,
+ hf_pdcp_lte_sequence_analysis,
+ tvb, 0, 0,
+ "", "Sequence Analysis");
+ seqnum_tree = proto_item_add_subtree(seqnum_ti,
+ ett_pdcp_lte_sequence_analysis);
+ PROTO_ITEM_SET_GENERATED(seqnum_ti);
+
+
+ /* Previous channel frame */
+ if (p->previousFrameNum != 0) {
+ proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_previous_frame,
+ tvb, 0, 0, p->previousFrameNum);
+ }
+
+ /* Expected sequence number */
+ ti = proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_expected_sn,
+ tvb, 0, 0, p->sequenceExpected);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* Make sure we have recognised SN length */
+ switch (p_pdcp_lte_info->seqnum_length) {
+ case PDCP_SN_LENGTH_5_BITS:
+ case PDCP_SN_LENGTH_7_BITS:
+ case PDCP_SN_LENGTH_12_BITS:
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ switch (p->state) {
+ case SN_OK:
+ ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
+ tvb, 0, 0, TRUE);
+ PROTO_ITEM_SET_GENERATED(ti);
+ proto_item_append_text(seqnum_ti, " - OK");
+ break;
+
+ case SN_Missing:
+ ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
+ tvb, 0, 0, FALSE);
+ PROTO_ITEM_SET_GENERATED(ti);
+ ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_skipped,
+ tvb, 0, 0, TRUE);
+ PROTO_ITEM_SET_GENERATED(ti);
+ if (p->lastSN != p->firstSN) {
+ expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
+ "PDCP SNs (%u to %u) missing for %s on UE %u",
+ p->firstSN, p->lastSN,
+ val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
+ p_pdcp_lte_info->ueid);
+ proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
+ p->firstSN, p->lastSN);
+ }
+ else {
+ expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
+ "PDCP SN (%u) missing for %s on UE %u",
+ p->firstSN,
+ val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
+ p_pdcp_lte_info->ueid);
+ proto_item_append_text(seqnum_ti, " - SN missing (%u)",
+ p->firstSN);
+ }
+ break;
+
+ case SN_Repeated:
+ ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
+ tvb, 0, 0, FALSE);
+ PROTO_ITEM_SET_GENERATED(ti);
+ ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_repeated,
+ tvb, 0, 0, TRUE);
+ PROTO_ITEM_SET_GENERATED(ti);
+ expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
+ "PDCP SN (%u) repeated for %s for UE %u",
+ p->firstSN,
+ val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
+ p_pdcp_lte_info->ueid);
+ proto_item_append_text(seqnum_ti, "- SN %u Repeated",
+ p->firstSN);
+ break;
+
+ default:
+ /* Incorrect sequence number */
+ expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
+ "Wrong Sequence Number for %s on UE %u - got %u, expected %u",
+ val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
+ p_pdcp_lte_info->ueid, sequenceNumber, p->sequenceExpected);
+ break;
+ }
+}
+
+
+/* Update the channel status and set report for this frame */
+static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
+ pdcp_lte_info *p_pdcp_lte_info,
+ guint16 sequenceNumber,
+ proto_tree *tree)
+{
+ pdcp_channel_hash_key channel_key;
+ pdcp_channel_hash_key *p_channel_key;
+ pdcp_channel_status *p_channel_status;
+ pdcp_sequence_report_in_frame *p_report_in_frame = NULL;
+ gboolean createdChannel = FALSE;
+ guint16 expectedSequenceNumber = 0;
+ guint16 snLimit = 0;
+
+ /* If find stat_report_in_frame already, use that and get out */
+ if (pinfo->fd->flags.visited) {
+ p_report_in_frame = (pdcp_sequence_report_in_frame*)g_hash_table_lookup(pdcp_lte_frame_sequence_analysis_report_hash,
+ &pinfo->fd->num);
+ if (p_report_in_frame != NULL) {
+ addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info,
+ sequenceNumber,
+ pinfo, tree, tvb);
+ return;
+ }
+ else {
+ /* Give up - we must have tried already... */
+ return;
+ }
+ }
+
+
+ /**************************************************/
+ /* Create or find an entry for this channel state */
+ memset(&channel_key, 0, sizeof(channel_key));
+ channel_key.ueId = p_pdcp_lte_info->ueid;
+ channel_key.channelType = p_pdcp_lte_info->channelType;
+ channel_key.channelId = p_pdcp_lte_info->channelId;
+ channel_key.direction = p_pdcp_lte_info->direction;
+
+ /* Do the table lookup */
+ p_channel_status = (pdcp_channel_status*)g_hash_table_lookup(pdcp_sequence_analysis_channel_hash, &channel_key);
+
+ /* Create table entry if necessary */
+ if (p_channel_status == NULL) {
+ createdChannel = TRUE;
+
+ /* Allocate a new value and duplicate key contents */
+ p_channel_status = se_alloc0(sizeof(pdcp_channel_status));
+ p_channel_key = se_memdup(&channel_key, sizeof(pdcp_channel_hash_key));
+
+ /* Add entry */
+ g_hash_table_insert(pdcp_sequence_analysis_channel_hash, p_channel_key, p_channel_status);
+ }
+
+ /* Create space for frame state_report */
+ p_report_in_frame = se_alloc(sizeof(pdcp_sequence_report_in_frame));
+
+ switch (p_pdcp_lte_info->seqnum_length) {
+ case PDCP_SN_LENGTH_5_BITS:
+ snLimit = 32;
+ break;
+ case PDCP_SN_LENGTH_7_BITS:
+ snLimit = 128;
+ break;
+ case PDCP_SN_LENGTH_12_BITS:
+ snLimit = 4096;
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ /* Work out expected sequence number */
+ if (!createdChannel) {
+ expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
+ }
+
+ /* Set report for this frame */
+ /* For PDCP, sequence number is always expectedSequence number */
+ p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
+
+ /* For wrong sequence number... */
+ if (!p_report_in_frame->sequenceExpectedCorrect) {
+
+ /* Frames are not missing if we get an earlier sequence number again */
+ if (((snLimit + expectedSequenceNumber - sequenceNumber) % snLimit) > 15) {
+ p_report_in_frame->state = SN_Missing;
+ p_report_in_frame->firstSN = expectedSequenceNumber;
+ p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
+
+ p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+ p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+
+ /* Update channel status to remember *this* frame */
+ p_channel_status->previousFrameNum = pinfo->fd->num;
+ p_channel_status->previousSequenceNumber = sequenceNumber;
+ }
+ else {
+ /* An SN has been repeated */
+ p_report_in_frame->state = SN_Repeated;
+ p_report_in_frame->firstSN = sequenceNumber;
+
+ p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+ p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+ }
+ }
+ else {
+ /* SN was OK */
+ p_report_in_frame->state = SN_OK;
+ p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+ p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+
+ /* Update channel status to remember *this* frame */
+ p_channel_status->previousFrameNum = pinfo->fd->num;
+ p_channel_status->previousSequenceNumber = sequenceNumber;
+ }
+
+ /* Associate with this frame number */
+ g_hash_table_insert(pdcp_lte_frame_sequence_analysis_report_hash, &pinfo->fd->num, p_report_in_frame);
+
+ /* Add state report for this frame into tree */
+ addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info, sequenceNumber,
+ pinfo, tree, tvb);
+}
+
+
+/* Write the given formatted text to:
+ - the info column
+ - the top-level RLC PDU item */
+static void write_pdu_label_and_info(proto_item *pdu_ti,
+ packet_info *pinfo, const char *format, ...)
+{
+ #define MAX_INFO_BUFFER 256
+ static char info_buffer[MAX_INFO_BUFFER];
+
+ va_list ap;
+
+ va_start(ap, format);
+ g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
+ va_end(ap);
+
+ /* Add to indicated places */
+ col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
+ proto_item_append_text(pdu_ti, "%s", info_buffer);
+}
+
+
+
+/***************************************************************/
+
+
/* Dissect a Large-CID field.
Return following offset */
static int dissect_large_cid(proto_tree *tree,
if ((first_octet & 0x80) == 0) {
/* One byte */
- proto_tree_add_uint(tree, hf_pdcp_lte_large_cid, tvb, offset, 1,
+ proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 1,
first_octet);
return offset+1;
}
else {
/* Two bytes */
guint16 bytes = tvb_get_ntohs(tvb, offset) & 0x7fff;
- proto_tree_add_uint(tree, hf_pdcp_lte_large_cid, tvb, offset, 2,
+ proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 2,
bytes);
return offset+2;
}
proto_item *root_ti;
int tree_start_offset = offset;
guint8 rx;
- guint8 contributing_csrcs;
+ /*guint8 contributing_csrcs;*/
guint16 sequence_number;
guint32 timestamp;
guint8 tis=0, tss=0;
/* V | P | RX | CC */
rx = tvb_get_guint8(tvb, offset) & 0x10;
proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_rx, tvb, offset, 1, FALSE);
- contributing_csrcs = tvb_get_guint8(tvb, offset) & 0x0f;
+ /*contributing_csrcs = tvb_get_guint8(tvb, offset) & 0x0f;*/
proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_cc, tvb, offset, 1, FALSE);
offset += 1;
-static int dissect_pdcp_irdyn_packet(proto_tree *tree _U_,
+static int dissect_pdcp_irdyn_packet(proto_tree *tree,
proto_item *root_item,
- tvbuff_t *tvb _U_,
+ tvbuff_t *tvb,
int offset,
- struct pdcp_lte_info *p_pdcp_info _U_,
+ struct pdcp_lte_info *p_pdcp_info,
packet_info *pinfo)
{
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " IRDYN");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " IRDYN");
proto_item_append_text(root_item, " (IRDYN)");
/* Large CID */
{
unsigned char dynamic_chain_present;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " IR");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " IR");
proto_item_append_text(root_item, " (IR)");
/* Is dynamic chain present? */
tvbuff_t *tvb,
int offset,
struct pdcp_lte_info *p_pdcp_info _U_,
- packet_info *pinfo _U_)
+ packet_info *pinfo)
{
guint8 sn;
/* TODO: profile-specific */
sn = tvb_get_guint8(tvb, offset);
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_feedback1, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback1, tvb, offset, 1, FALSE);
offset++;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
return offset;
}
tvbuff_t *tvb,
int offset,
int size,
- struct pdcp_lte_info *p_pdcp_info _U_,
- packet_info *pinfo _U_)
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
{
proto_item *ti;
guint8 ack_type;
}
/* Feedback2 hidden filter */
- ti = proto_tree_add_item(tree, hf_pdcp_lte_feedback_feedback2, tvb, offset, -1, FALSE);
+ ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback2, tvb, offset, -1, FALSE);
PROTO_ITEM_SET_HIDDEN(ti);
/* Ack-type */
first_octet = tvb_get_guint8(tvb, offset);
ack_type = (first_octet & 0xc0) >> 6;
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_ack_type, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_ack_type, tvb, offset, 1, FALSE);
/* TODO: expert info on NACK? */
/* Mode */
mode = (first_octet & 0x30) >> 4;
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_mode, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_mode, tvb, offset, 1, FALSE);
/* Show ACK-TYPE(Mode) in info column */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- full_mode_name = val_to_str(mode, rohc_mode_vals, "Error");
+ full_mode_name = val_to_str(mode, rohc_mode_vals, "Error");
- col_append_fstr(pinfo->cinfo, COL_INFO, " %s(%c)",
- val_to_str(ack_type, feedback_ack_vals, "Unknown"),
- full_mode_name[0]);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s(%c)",
+ val_to_str(ack_type, feedback_ack_vals, "Unknown"),
+ full_mode_name[0]);
/* 11 bits of SN */
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_sn, tvb, offset, 2, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_sn, tvb, offset, 2, FALSE);
sn = tvb_get_ntohs(tvb, offset) & 0x7ff;
offset += 2;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
/* Loop over any remaining feedback options */
size_remaining = size - 2;
/* Preference setting controls showing option and lengths */
if (global_pdcp_show_feedback_option_tag_length) {
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_option, tvb, offset, 1, FALSE);
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_length, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_length, tvb, offset, 1, FALSE);
}
offset++;
size_remaining--;
case 1:
/* CRC */
one_byte_value = tvb_get_guint8(tvb, offset);
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_crc, tvb, offset, 1, FALSE);
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " CRC=%u ", one_byte_value);
- }
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_crc, tvb, offset, 1, FALSE);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " CRC=%u ", one_byte_value);
break;
case 2:
/* REJECT: TODO */
case 4:
/* SN */
one_byte_value = tvb_get_guint8(tvb, offset);
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_option_sn, tvb, offset, 1, FALSE);
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u ", one_byte_value);
- }
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_sn, tvb, offset, 1, FALSE);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u ", one_byte_value);
break;
case 5:
/* Clock */
one_byte_value = tvb_get_guint8(tvb, offset);
- proto_tree_add_item(tree, hf_pdcp_lte_feedback_option_clock, tvb, offset, 1, FALSE);
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " Clock=%u ", one_byte_value);
- }
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_clock, tvb, offset, 1, FALSE);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " Clock=%u ", one_byte_value);
break;
case 6:
/* Jitter: TODO */
proto_item *feedback_ti;
proto_tree *feedback_tree;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " Feedback");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " Feedback");
proto_item_append_text(root_item, " (Feedback)");
/* Create feedback tree root */
/* Code */
code = tvb_get_guint8(tvb, offset) & 0x07;
- ti = proto_tree_add_item(feedback_tree, hf_pdcp_lte_feedback_code, tvb, offset, 1, FALSE);
+ ti = proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_code, tvb, offset, 1, FALSE);
offset++;
/* Optional length field */
size = code;
}
else {
- proto_tree_add_item(feedback_tree, hf_pdcp_lte_feedback_size, tvb, offset, 1, FALSE);
+ proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_size, tvb, offset, 1, FALSE);
size = tvb_get_guint8(tvb, offset);
offset++;
}
}
else if ((size > 1) && ((tvb_get_guint8(tvb, offset) & 0xc0) == 0xc0)) {
/* Add-CID here! */
- proto_tree_add_item(feedback_tree, hf_pdcp_lte_add_cid, tvb, offset, 1, FALSE);
+ proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
offset++;
if (size == 2) {
proto_item *root_item,
tvbuff_t *tvb,
int offset,
- struct pdcp_lte_info *p_pdcp_info _U_,
+ struct pdcp_lte_info *p_pdcp_info,
packet_info *pinfo)
{
guint8 sn;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " R-0");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " R-0");
proto_item_append_text(root_item, " (R-0)");
/* 6 bits of sn */
sn = tvb_get_guint8(tvb, offset) & 0x3f;
- proto_tree_add_item(tree, hf_pdcp_lte_r0_sn, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_sn, tvb, offset, 1, FALSE);
offset++;
/* Large CID */
offset = dissect_large_cid(tree, tvb, offset);
}
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
return offset;
}
{
guint8 sn;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " R-0-CRC");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " R-0-CRC");
proto_item_append_text(root_item, " (R-0-CRC)");
proto_tree_add_item(tree, hf_pdcp_lte_rohc_r_0_crc, tvb, offset, -1, FALSE);
/* Conclude SN */
sn = (sn << 1) + ((tvb_get_guint8(tvb, offset) & 0x80) >> 7);
- proto_tree_add_uint(tree, hf_pdcp_lte_r0_crc_sn, tvb, offset, 1, sn);
+ proto_tree_add_uint(tree, hf_pdcp_lte_rohc_r0_crc_sn, tvb, offset, 1, sn);
/* 7 bit CRC */
- proto_tree_add_item(tree, hf_pdcp_lte_r0_crc_crc, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_crc_crc, tvb, offset, 1, FALSE);
offset++;
/* Show SN in info column */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
return offset;
}
{
guint8 sn;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " U0-0");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " U0-0");
proto_item_append_text(root_item, " (UO-0)");
/* SN */
sn = (tvb_get_guint8(tvb, offset) & 0x78) >> 3;
- proto_tree_add_item(tree, hf_pdcp_lte_uo0_sn, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_sn, tvb, offset, 1, FALSE);
/* CRC (3 bits) */
- proto_tree_add_item(tree, hf_pdcp_lte_uo0_crc, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_crc, tvb, offset, 1, FALSE);
offset++;
}
/* Show SN in info column */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
return offset;
}
struct pdcp_lte_info *p_pdcp_info,
packet_info *pinfo)
{
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " R-1");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " R-1");
proto_item_append_text(root_item, " (R-1)");
/* TODO: octet before large-cid */
T = tvb_get_guint8(tvb, ++offset) >> 7;
proto_tree_add_item(tree, hf_pdcp_lte_rohc_type1_t, tvb, offset, 1, FALSE);
if (T) {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " R-1-TS");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " R-1-TS");
proto_item_append_text(root_item, " (R-1-TS)");
}
else {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " R-1-ID");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " R-1-ID");
proto_item_append_text(root_item, " (R-1-ID)");
}
struct pdcp_lte_info *p_pdcp_info,
packet_info *pinfo)
{
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " UO-1");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " UO-1");
proto_item_append_text(root_item, " (UO-1)");
/* TODO: octet before large-cid */
T = tvb_get_guint8(tvb, ++offset) >> 5;
proto_tree_add_item(tree, hf_pdcp_lte_rohc_type0_t, tvb, offset, 1, FALSE);
if (T) {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " UO-1-TS");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " UO-1-TS");
proto_item_append_text(root_item, " (UO-1-TS)");
}
else {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " UO-1-ID");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " UO-1-ID");
proto_item_append_text(root_item, " (UO-1-ID)");
}
{
guint8 ts;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " U0R-2");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " U0R-2");
proto_item_append_text(root_item, " (UOR-2)");
/* TS straddles CID */
proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, FALSE);
/* SN (6 bits) */
- proto_tree_add_item(tree, hf_pdcp_lte_uor2_sn, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_sn, tvb, offset, 1, FALSE);
offset++;
/* X (one bit) */
- proto_tree_add_item(tree, hf_pdcp_lte_uor2_x, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_x, tvb, offset, 1, FALSE);
/* TODO: CRC */
offset++;
proto_tree_add_item(tree, hf_pdcp_lte_rohc_type2_t, tvb, offset, 1, FALSE);
if (T) {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-TS");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-TS");
proto_item_append_text(root_item, " (UOR-2-TS)");
}
else {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-ID");
- }
+ col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-ID");
proto_item_append_text(root_item, " (UOR-2-ID)");
}
p_pdcp_info->plane);
PROTO_ITEM_SET_GENERATED(ti);
+ /* UEId */
+ if (p_pdcp_info->ueid != 0) {
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_ueid, tvb, 0, 0,
+ p_pdcp_info->ueid);
+ PROTO_ITEM_SET_GENERATED(ti);
+ }
+
+ /* Channel type */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_type, tvb, 0, 0,
+ p_pdcp_info->channelType);
+ PROTO_ITEM_SET_GENERATED(ti);
+ if (p_pdcp_info->channelId != 0) {
+ /* Channel type */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_id, tvb, 0, 0,
+ p_pdcp_info->channelId);
+ PROTO_ITEM_SET_GENERATED(ti);
+ }
+
+
/* User-plane-specific fields */
if (p_pdcp_info->plane == USER_PLANE) {
PROTO_ITEM_SET_GENERATED(configuration_ti);
/* Show plane in info column */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
- val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
+ val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
}
{
case Channel_CCCH:
if (p_pdcp_info->direction == DIRECTION_UPLINK) {
- rrc_handle = find_dissector("lte-rrc.ul.ccch");
+ rrc_handle = find_dissector("lte_rrc.ul_ccch");
}
else {
- rrc_handle = find_dissector("lte-rrc.dl.ccch");
+ rrc_handle = find_dissector("lte_rrc.dl_ccch");
}
break;
case Channel_PCCH:
break;
}
break;
+ case Channel_DCCH:
+ if (p_pdcp_info->direction == DIRECTION_UPLINK) {
+ rrc_handle = find_dissector("lte_rrc.ul_dcch");
+ }
+ else {
+ rrc_handle = find_dissector("lte_rrc.dl_dcch");
+ }
+ break;
+
default:
break;
}
+/* Forwad declarations */
+static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+/* Heuristic dissection */
+static gboolean global_pdcp_lte_heur = FALSE;
+
+/* Heuristic dissector looks for supported framing protocol (see wiki page) */
+static gboolean dissect_pdcp_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree)
+{
+ gint offset = 0;
+ struct pdcp_lte_info *p_pdcp_lte_info;
+ tvbuff_t *pdcp_tvb;
+ guint8 tag = 0;
+ gboolean infoAlreadySet = FALSE;
+ gboolean seqnumLengthTagPresent = FALSE;
+
+ /* This is a heuristic dissector, which means we get all the UDP
+ * traffic not sent to a known dissector and not claimed by
+ * a heuristic dissector called before us!
+ */
+
+ if (!global_pdcp_lte_heur) {
+ return FALSE;
+ }
+
+ /* Do this again on re-dissection to re-discover offset of actual PDU */
+
+ /* Needs to be at least as long as:
+ - the signature string
+ - fixed header bytes
+ - tag for data
+ - at least one byte of PDCP PDU payload */
+ if ((size_t)tvb_length_remaining(tvb, offset) < (strlen(PDCP_LTE_START_STRING)+3+2)) {
+ return FALSE;
+ }
+
+ /* OK, compare with signature string */
+ if (tvb_strneql(tvb, offset, PDCP_LTE_START_STRING, strlen(PDCP_LTE_START_STRING)) != 0) {
+ return FALSE;
+ }
+ offset += (gint)strlen(PDCP_LTE_START_STRING);
+
+
+ /* If redissecting, use previous info struct (if available) */
+ p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
+ if (p_pdcp_lte_info == NULL) {
+ /* Allocate new info struct for this frame */
+ p_pdcp_lte_info = se_alloc0(sizeof(struct pdcp_lte_info));
+ infoAlreadySet = FALSE;
+ }
+ else {
+ infoAlreadySet = TRUE;
+ }
+
+
+ /* Read fixed fields */
+ p_pdcp_lte_info->no_header_pdu = tvb_get_guint8(tvb, offset++);
+ p_pdcp_lte_info->plane = tvb_get_guint8(tvb, offset++);
+ p_pdcp_lte_info->rohc_compression = tvb_get_guint8(tvb, offset++);
+
+ /* Read optional fields */
+ while (tag != PDCP_LTE_PAYLOAD_TAG) {
+ /* Process next tag */
+ tag = tvb_get_guint8(tvb, offset++);
+ switch (tag) {
+ case PDCP_LTE_SEQNUM_LENGTH_TAG:
+ p_pdcp_lte_info->seqnum_length = tvb_get_guint8(tvb, offset);
+ offset++;
+ seqnumLengthTagPresent = TRUE;
+ break;
+ case PDCP_LTE_DIRECTION_TAG:
+ p_pdcp_lte_info->direction = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_LOG_CHAN_TYPE_TAG:
+ p_pdcp_lte_info->channelType = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_BCCH_TRANSPORT_TYPE_TAG:
+ p_pdcp_lte_info->BCCHTransport = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_ROHC_IP_VERSION_TAG:
+ p_pdcp_lte_info->rohc_ip_version = tvb_get_ntohs(tvb, offset);
+ offset += 2;
+ break;
+ case PDCP_LTE_ROHC_CID_INC_INFO_TAG:
+ p_pdcp_lte_info->cid_inclusion_info = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_ROHC_LARGE_CID_PRES_TAG:
+ p_pdcp_lte_info->large_cid_present = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_ROHC_MODE_TAG:
+ p_pdcp_lte_info->mode = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_ROHC_RND_TAG:
+ p_pdcp_lte_info->rnd = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_ROHC_UDP_CHECKSUM_PRES_TAG:
+ p_pdcp_lte_info->udp_checkum_present = tvb_get_guint8(tvb, offset);
+ offset++;
+ break;
+ case PDCP_LTE_ROHC_PROFILE_TAG:
+ p_pdcp_lte_info->profile = tvb_get_ntohs(tvb, offset);
+ offset += 2;
+ break;
+
+ case PDCP_LTE_PAYLOAD_TAG:
+ /* Have reached data, so get out of loop */
+ continue;
+
+ default:
+ /* It must be a recognised tag */
+ return FALSE;
+ }
+ }
+
+ if ((p_pdcp_lte_info->plane == USER_PLANE) && (seqnumLengthTagPresent == FALSE)) {
+ /* Conditional field is not present */
+ return FALSE;
+ }
+
+ if (!infoAlreadySet) {
+ /* Store info in packet */
+ p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
+ }
+
+ /**************************************/
+ /* OK, now dissect as PDCP LTE */
+
+ /* Create tvb that starts at actual PDCP PDU */
+ pdcp_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset);
+ dissect_pdcp_lte(pdcp_tvb, pinfo, tree);
+ return TRUE;
+}
+
+
/******************************/
/* Main dissection function. */
static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
gint rohc_offset;
struct pdcp_lte_info *p_pdcp_info;
guint8 base_header_byte;
- guint8 udp_checksum_needed = TRUE;
+ gboolean udp_checksum_needed = TRUE;
+ gboolean ip_id_needed = TRUE;
/* Append this protocol name rather than replace. */
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_add_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
/* Create pdcp tree. */
if (tree) {
}
/* Show ROHC mode */
- if (p_pdcp_info->rohc_compression &&
- check_col(pinfo->cinfo, COL_INFO)) {
-
+ if (p_pdcp_info->rohc_compression) {
col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
}
/* Handle PDCP header (if present) */
if (!p_pdcp_info->no_header_pdu) {
+ /* TODO: shouldn't need to initialise this one!! */
+ guint16 seqnum = 0;
+ gboolean seqnum_set = FALSE;
+
/*****************************/
/* Signalling plane messages */
if (p_pdcp_info->plane == SIGNALING_PLANE) {
guint32 data_length;
/* 5-bit sequence number */
+ seqnum = tvb_get_guint8(tvb, offset) & 0x1f;
+ seqnum_set = TRUE;
proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_5, tvb, offset, 1, FALSE);
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%u",
- tvb_get_guint8(tvb, offset) & 0x1f);
- }
+ write_pdu_label_and_info(root_ti, pinfo, " sn=%-2u ", seqnum);
offset++;
-
/* RRC data is all but last 4 bytes.
Call lte-rrc dissector (according to direction and channel type) */
if (global_pdcp_dissect_signalling_plane_as_rrc) {
proto_tree_add_item(pdcp_tree, hf_pdcp_lte_mac, tvb, offset, 4, FALSE);
offset += 4;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
- mac, data_length);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
+ mac, data_length);
- return;
}
else if (p_pdcp_info->plane == USER_PLANE) {
/**********************************/
/* User-plane messages */
- guint16 seqnum;
gboolean pdu_type = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
/* Data/Control flag */
/* Number of sequence number bits depends upon config */
if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_7_BITS) {
seqnum = tvb_get_guint8(tvb, offset) & 0x7f;
+ seqnum_set = TRUE;
proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_7, tvb, offset, 1, FALSE);
offset++;
}
/* 12-bit sequence number */
seqnum = tvb_get_ntohs(tvb, offset) & 0x0fff;
+ seqnum_set = TRUE;
proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_12, tvb, offset, 2, FALSE);
offset += 2;
}
return;
}
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%u", seqnum);
- }
+ write_pdu_label_and_info(root_ti, pinfo, " (SN=%u)", seqnum);
}
else {
/*******************************/
guint not_received = 0;
guint sn;
proto_tree *bitmap_tree;
- proto_item *bitmap_ti;
+ proto_item *bitmap_ti = NULL;
/* First-Missing-Sequence SN */
fms = tvb_get_ntohs(tvb, offset) & 0x0fff;
- sn = fms;
+ sn = (fms + 1) % 4096;
proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms, tvb,
offset, 2, FALSE);
offset += 2;
/* Bitmap tree */
- bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
- offset, -1, FALSE);
- bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_rohc_report_bitmap);
-
-
- /* For each byte... */
- for ( ; tvb_length_remaining(tvb, offset); offset++) {
- guint bit_offset = 0;
- /* .. look for error (0) in each bit */
- for ( ; bit_offset < 8; bit_offset++) {
- if ((tvb_get_guint8(tvb, offset) >> (7-bit_offset) & 0x1) == 0) {
- proto_tree_add_boolean_format_value(bitmap_tree, hf_pdcp_lte_bitmap_not_received, tvb, offset, 1, TRUE,
- " (SN=%u)", sn);
- not_received++;
+ if (tvb_length_remaining(tvb, offset) > 0) {
+ bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
+ offset, -1, FALSE);
+ bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_rohc_report_bitmap);
+
+
+ /* For each byte... */
+ for ( ; tvb_length_remaining(tvb, offset); offset++) {
+ guint bit_offset = 0;
+ /* .. look for error (0) in each bit */
+ for ( ; bit_offset < 8; bit_offset++) {
+ if ((tvb_get_guint8(tvb, offset) >> (7-bit_offset) & 0x1) == 0) {
+ proto_tree_add_boolean_format_value(bitmap_tree, hf_pdcp_lte_bitmap_not_received, tvb, offset, 1, TRUE,
+ " (SN=%u)", sn);
+ not_received++;
+ }
+ sn = (sn + 1) % 4096;
}
- sn = (sn + 1) % 4096;
}
}
- proto_item_append_text(bitmap_ti, " (not-received=%u)", not_received);
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO,
- " Status Report (fms=%u) not-received=%u",
- fms, not_received);
+ if (bitmap_ti != NULL) {
+ proto_item_append_text(bitmap_ti, " (not-received=%u)", not_received);
}
+ write_pdu_label_and_info(root_ti, pinfo, " Status Report (fms=%u) not-received=%u",
+ fms, not_received);
}
return;
}
else {
/* Invalid plane setting...! */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " - INVALID PLANE (%u)",
- p_pdcp_info->plane);
- }
+ write_pdu_label_and_info(root_ti, pinfo, " - INVALID PLANE (%u)",
+ p_pdcp_info->plane);
return;
}
+
+ /* For now, only do sequence analysis if RLC wasn't present in the frame */
+ /* This can be fixed once RLC does re-assembly... */
+ if (global_pdcp_check_sequence_numbers && seqnum_set &&
+ (p_get_proto_data(pinfo->fd, proto_rlc_lte) == NULL)) {
+
+ checkChannelSequenceInfo(pinfo, tvb, p_pdcp_info,
+ (guint16)seqnum, pdcp_tree);
+ }
+
}
else {
/* Show that its a no-header PDU */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_str(pinfo->cinfo, COL_INFO, " No-Header ");
- }
+ write_pdu_label_and_info(root_ti, pinfo, " No-Header ");
}
/* If not compressed with ROHC, show as user-plane data */
if (!p_pdcp_info->rohc_compression) {
-
- if (global_pdcp_dissect_user_plane_as_ip && (ip_handle != 0)) {
- tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset, -1, -1);
- call_dissector_only(ip_handle, payload_tvb, pinfo, pdcp_tree);
- }
- else {
- if (tvb_length_remaining(tvb, offset) > 0) {
- if (p_pdcp_info->plane == USER_PLANE) {
- proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, tvb, offset, -1, FALSE);
+ if (tvb_length_remaining(tvb, offset) > 0) {
+ if (p_pdcp_info->plane == USER_PLANE) {
+ if (global_pdcp_dissect_user_plane_as_ip) {
+ tvbuff_t *payload_tvb = tvb_new_subset_remaining(tvb, offset);
+ call_dissector_only(ip_handle, payload_tvb, pinfo, pdcp_tree);
}
else {
- if (global_pdcp_dissect_signalling_plane_as_rrc) {
- /* Get appropriate dissector handle */
- dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
-
- if (rrc_handle != 0) {
- /* Call RRC dissector if have one */
- tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
- tvb_length_remaining(tvb, offset),
- tvb_length_remaining(tvb, offset));
- call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
- }
- else {
- /* Just show data */
- proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
- tvb_length_remaining(tvb, offset), FALSE);
- }
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, tvb, offset, -1, FALSE);
+ }
+ }
+ else {
+ if (global_pdcp_dissect_signalling_plane_as_rrc) {
+ /* Get appropriate dissector handle */
+ dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
+
+ if (rrc_handle != 0) {
+ /* Call RRC dissector if have one */
+ tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
+ tvb_length_remaining(tvb, offset),
+ tvb_length_remaining(tvb, offset));
+ call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
}
else {
- proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset, -1, FALSE);
+ /* Just show data */
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
+ tvb_length_remaining(tvb, offset), FALSE);
}
}
-
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, "(%u bytes data)",
- tvb_length_remaining(tvb, offset));
+ else {
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset, -1, FALSE);
}
}
+
+ write_pdu_label_and_info(root_ti, pinfo, "(%u bytes data)",
+ tvb_length_remaining(tvb, offset));
}
return;
}
/* ROHC packets */
/***************************/
- if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
- col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
- val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unkown"));
- }
+ col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
+ val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unkown"));
/* Only attempt ROHC if configured to */
if (!global_pdcp_dissect_rohc) {
return;
}
-
+
/* Create pdcp tree. */
if (pdcp_tree) {
rohc_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_rohc, tvb, offset, -1, FALSE);
!p_pdcp_info->large_cid_present)
{
if (((tvb_get_guint8(tvb, offset) >> 4) & 0x0f) == 0x0e) {
- proto_tree_add_item(rohc_tree, hf_pdcp_lte_add_cid, tvb, offset, 1, FALSE);
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
offset++;
}
else {
/* Assume CID value of 0 if field absent */
- proto_item *ti = proto_tree_add_uint(rohc_tree, hf_pdcp_lte_add_cid, tvb, offset, 0, 0);
+ proto_item *ti = proto_tree_add_uint(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 0, 0);
PROTO_ITEM_SET_GENERATED(ti);
}
}
/* IR (1111110) */
if ((base_header_byte & 0xfe) == 0xfc) {
offset = dissect_pdcp_ir_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ udp_checksum_needed = FALSE;
+ ip_id_needed = FALSE;
}
/* IRDYN (11111000) */
else if (base_header_byte == 0xf8) {
offset = dissect_pdcp_irdyn_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
udp_checksum_needed = FALSE;
+ ip_id_needed = FALSE;
}
/* Feedback (begins with 11110) */
/* UO-1 if !(ipv4 && rand) */
if (!((p_pdcp_info->rohc_ip_version == 4) &&
(!p_pdcp_info->rnd))) {
- offset = dissect_pdcp_uo_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
- return;
- }
- else {
+
+ dissect_pdcp_uo_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ } else {
/* Whether its UO-1-ID or UO-1-TS depends upon T bit */
dissect_pdcp_uo_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
- return;
- }
+ }
- return;
+ return;
}
}
if (!((p_pdcp_info->rohc_ip_version == 4) &&
(!p_pdcp_info->rnd))) {
- offset = dissect_pdcp_uor_2_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ dissect_pdcp_uor_2_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
}
else {
/* Whether its UOR-2-ID or UOR-2-TS depends upon T bit */
/* Fields beyond base header */
+ /* These 2 fields not present for IR, IR-DYN frames */
+
/* IP-ID */
- if (p_pdcp_info->rnd) {
- proto_tree_add_item(rohc_tree, hf_pdcp_lte_ip_id, tvb, offset, 2, FALSE);
+ if (p_pdcp_info->rnd && ip_id_needed) {
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_ip_id, tvb, offset, 2, FALSE);
offset += 2;
}
/* UDP Checksum */
if (p_pdcp_info->udp_checkum_present && udp_checksum_needed) {
- proto_tree_add_item(rohc_tree, hf_pdcp_lte_udp_checksum, tvb, offset, 2, FALSE);
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_udp_checksum, tvb, offset, 2, FALSE);
offset += 2;
}
/* Payload */
if (tvb_reported_length_remaining(tvb, offset) > 0) {
- proto_tree_add_item(rohc_tree, hf_pdcp_lte_payload, tvb, offset, -1, FALSE);
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_payload, tvb, offset, -1, FALSE);
+ }
+}
+
+/* Initializes the hash table and the mem_chunk area each time a new
+ * file is loaded or re-loaded in wireshark */
+static void
+pdcp_lte_init_protocol(void)
+{
+ /* Destroy any existing hashes. */
+ if (pdcp_sequence_analysis_channel_hash) {
+ g_hash_table_destroy(pdcp_sequence_analysis_channel_hash);
}
+ if (pdcp_lte_frame_sequence_analysis_report_hash) {
+ g_hash_table_destroy(pdcp_lte_frame_sequence_analysis_report_hash);
+ }
+
+
+ /* Now create them over */
+ pdcp_sequence_analysis_channel_hash = g_hash_table_new(pdcp_channel_hash_func, pdcp_channel_equal);
+ pdcp_lte_frame_sequence_analysis_report_hash = g_hash_table_new(pdcp_frame_hash_func, pdcp_frame_equal);
}
+
+
void proto_register_pdcp(void)
{
static hf_register_info hf[] =
{ &hf_pdcp_lte_configuration,
{ "Configuration",
"pdcp-lte.configuration", FT_STRING, BASE_NONE, NULL, 0x0,
- "Configuation info passed into dissector", HFILL
+ "Configuration info passed into dissector", HFILL
}
},
{ &hf_pdcp_lte_rohc_compression,
{ "ROHC Compression",
- "pdcp-lte.rohc", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
- "ROHC Mode", HFILL
+ "pdcp-lte.rohc.compression", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_mode,
- { "ROHC mode",
+ { "ROHC Mode",
"pdcp-lte.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
- "ROHC Mode", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_rnd,
{ &hf_pdcp_lte_rohc_udp_checksum_present,
{ "UDP Checksum", /* TODO: true/false vals? */
"pdcp-lte.rohc.checksum-present", FT_UINT8, BASE_DEC, NULL, 0x0,
- "UDP Checksum_present", HFILL
+ "UDP Checksum present", HFILL
}
},
-
-
{ &hf_pdcp_lte_direction,
{ "Direction",
"pdcp-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
"Direction of message", HFILL
}
},
+ { &hf_pdcp_lte_ueid,
+ { "UE",
+ "pdcp-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
+ "UE Identifier", HFILL
+ }
+ },
+ { &hf_pdcp_lte_channel_type,
+ { "Channel type",
+ "pdcp-lte.channel-type", FT_UINT8, BASE_DEC, VALS(logical_channel_vals), 0x0,
+ NULL, HFILL
+ }
+ },
+ { &hf_pdcp_lte_channel_id,
+ { "Channel Id",
+ "pdcp-lte.channel-id", FT_UINT8, BASE_DEC, 0, 0x0,
+ NULL, HFILL
+ }
+ },
{ &hf_pdcp_lte_rohc_profile,
{ "ROHC profile",
"pdcp-lte.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
{ &hf_pdcp_lte_no_header_pdu,
{ "No Header PDU",
"pdcp-lte.no-header_pdu", FT_UINT8, BASE_DEC, NULL, 0x0,
- "No Header PDU", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_plane,
{ "Plane",
"pdcp-lte.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
- "No Header PDU", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_seqnum_length,
{ &hf_pdcp_lte_cid_inclusion_info,
{ "CID Inclusion Info",
"pdcp-lte.cid-inclusion-info", FT_UINT8, BASE_DEC, NULL, 0x0,
- "CID Inclusion Info", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_large_cid_present,
{ "Large CID Present",
"pdcp-lte.large-cid-present", FT_UINT8, BASE_DEC, NULL, 0x0,
- "Large CID Present", HFILL
+ NULL, HFILL
}
},
},
{ &hf_pdcp_lte_signalling_data,
{ "Signalling Data",
- "pdcp-lte.signalling-data", FT_BYTES, BASE_HEX, NULL, 0x0,
- "Signalling Data", HFILL
+ "pdcp-lte.signalling-data", FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_mac,
{ "MAC",
"pdcp-lte.mac", FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
- "MAC", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_data_control,
{ "PDU Type",
"pdcp-lte.pdu-type", FT_UINT8, BASE_HEX, VALS(pdu_type_vals), 0x80,
- "PDU type", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_user_plane_data,
{ "User-Plane Data",
- "pdcp-lte.user-data", FT_BYTES, BASE_HEX, NULL, 0x0,
- "User-Plane Data", HFILL
+ "pdcp-lte.user-data", FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_control_pdu_type,
{ "Control PDU Type",
"pdcp-lte.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
- "Control PDU type", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_fms,
}
},
+
+ { &hf_pdcp_lte_sequence_analysis,
+ { "Sequence Analysis",
+ "pdcp-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
+ NULL, HFILL
+ }
+ },
+ { &hf_pdcp_lte_sequence_analysis_ok,
+ { "OK",
+ "pdcp-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
+ NULL, HFILL
+ }
+ },
+ { &hf_pdcp_lte_sequence_analysis_previous_frame,
+ { "Previous frame for channel",
+ "pdcp-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
+ NULL, HFILL
+ }
+ },
+ { &hf_pdcp_lte_sequence_analysis_expected_sn,
+ { "Expected SN",
+ "pdcp-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
+ NULL, HFILL
+ }
+ },
+ { &hf_pdcp_lte_sequence_analysis_skipped,
+ { "Skipped frames",
+ "pdcp-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
+ NULL, HFILL
+ }
+ },
+ { &hf_pdcp_lte_sequence_analysis_repeated,
+ { "Repeated frame",
+ "pdcp-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
+ NULL, HFILL
+ }
+ },
+
{ &hf_pdcp_lte_rohc,
{ "ROHC Message",
"pdcp-lte.rohc", FT_NONE, BASE_NONE, NULL, 0,
- "ROHC Message", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_r_0_crc,
{ "R-0-CRC Packet",
"pdcp-lte.r-0-crc", FT_NONE, BASE_NONE, NULL, 0,
- "R-0-CRC Packet", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_feedback,
"Feedback Packet", HFILL
}
},
-
{ &hf_pdcp_lte_rohc_type0_t,
{ "T",
"pdcp-lte.rohc.t0.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x20,
"Indicates whether frame type is TS (1) or ID (0)", HFILL
}
},
-
{ &hf_pdcp_lte_rohc_d,
{ "D",
- "pdcp-lte.rohc.t2.t", FT_UINT8, BASE_HEX, NULL, 0x01,
+ "pdcp-lte.rohc.d", FT_UINT8, BASE_HEX, NULL, 0x01,
"Indicates whether Dynamic chain is present", HFILL
}
},
{ &hf_pdcp_lte_rohc_static_ipv4,
{ "Static IPv4 chain",
"pdcp-lte.rohc.static.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
- "Static IPv4 chain", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_ip_version,
{ "IP Version",
"pdcp-lte.rohc.ip-version", FT_UINT8, BASE_HEX, NULL, 0xf0,
- "IP Version", HFILL
+ NULL, HFILL
}
},
/* TODO: create/use value_string */
{ &hf_pdcp_lte_rohc_ip_protocol,
{ "IP Protocol",
"pdcp-lte.rohc.ip-protocol", FT_UINT8, BASE_DEC, VALS(ip_protocol_vals), 0x0,
- "IP Protocol", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_ip_src,
{ "IP Source address",
- "pdcp-lte.rohc.ip-src", FT_IPv4, BASE_DEC, NULL, 0x0,
- "IP Source address", HFILL
+ "pdcp-lte.rohc.ip-src", FT_IPv4, BASE_NONE, NULL, 0x0,
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_ip_dst,
{ "IP Destination address",
- "pdcp-lte.rohc.ip-dst", FT_IPv4, BASE_DEC, NULL, 0x0,
- "IP Destination address", HFILL
+ "pdcp-lte.rohc.ip-dst", FT_IPv4, BASE_NONE, NULL, 0x0,
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_static_udp,
{ "Static UDP chain",
"pdcp-lte.rohc.static.udp", FT_NONE, BASE_NONE, NULL, 0x0,
- "Static UDP chain", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_static_udp_src_port,
{ "Static UDP source port",
"pdcp-lte.rohc.static.udp.src-port", FT_UINT16, BASE_DEC, NULL, 0x0,
- "Static UDP source port", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_static_udp_dst_port,
{ "Static UDP destination port",
"pdcp-lte.rohc.static.udp.dst-port", FT_UINT16, BASE_DEC, NULL, 0x0,
- "Static UDP destination port", HFILL
+ NULL, HFILL
}
},
-
-
{ &hf_pdcp_lte_rohc_static_rtp,
{ "Static RTP chain",
"pdcp-lte.rohc.static.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
- "Static RTP chain", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_static_rtp_ssrc,
{ &hf_pdcp_lte_rohc_dynamic_ipv4,
{ "Dynamic IPv4 chain",
"pdcp-lte.rohc.dynamic.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
- "Dynamic IPv4 chain", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_ipv4_tos,
{ &hf_pdcp_lte_rohc_dynamic_ipv4_rnd,
{ "Random IP-ID field",
"pdcp-lte.rohc.ip.rnd", FT_UINT8, BASE_HEX, NULL, 0x40,
- "Random IP-ID field", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_ipv4_nbo,
{ "Network Byte Order IP-ID field",
"pdcp-lte.rohc.ip.nbo", FT_UINT8, BASE_HEX, NULL, 0x20,
- "Network Byte Order IP-ID field", HFILL
+ NULL, HFILL
}
},
-
{ &hf_pdcp_lte_rohc_dynamic_udp,
{ "Dynamic UDP chain",
"pdcp-lte.rohc.dynamic.udp", FT_NONE, BASE_NONE, NULL, 0x0,
- "Dynamic UDP chain", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_udp_checksum,
{ "UDP Checksum",
"pdcp-lte.rohc.dynamic.udp.checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
- "UDP Checksum", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_udp_seqnum,
{ "UDP Sequence Number",
"pdcp-lte.rohc.dynamic.udp.seqnum", FT_UINT16, BASE_HEX, NULL, 0x0,
- "UDP Sequence Number", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_rtp,
{ "Dynamic RTP chain",
"pdcp-lte.rohc.dynamic.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
- "Dynamic RTP chain", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_rtp_rx,
{ "RX",
"pdcp-lte.rohc.dynamic.rtp.rx", FT_UINT8, BASE_DEC, NULL, 0x10,
- "RX", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_rtp_cc,
"Dynamic RTP chain Timestamp", HFILL
}
},
-
{ &hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
{ "Reserved",
"pdcp-lte.rohc.dynamic.rtp.reserved3", FT_UINT8, BASE_HEX, NULL, 0xc0,
{ &hf_pdcp_lte_rohc_dynamic_rtp_x,
{ "X",
"pdcp-lte.rohc.dynamic.rtp.x", FT_UINT8, BASE_DEC, NULL, 0x10,
- "X", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_rtp_mode,
{ "Mode",
"pdcp-lte.rohc.dynamic.rtp.mode", FT_UINT8, BASE_HEX, VALS(rohc_mode_vals), 0x0c,
- "Mode", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_dynamic_rtp_tis,
{ &hf_pdcp_lte_rohc_ts,
{ "TS",
"pdcp-lte.rohc.ts", FT_UINT8, BASE_DEC, NULL, 0x0,
- "TS", HFILL
+ NULL, HFILL
}
},
{ &hf_pdcp_lte_rohc_m,
{ "M",
"pdcp-lte.rohc.m", FT_UINT8, BASE_DEC, NULL, 0x40,
- "M", HFILL
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_uor2_sn,
+ { &hf_pdcp_lte_rohc_uor2_sn,
{ "SN",
"pdcp-lte.rohc.uor2.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
- "SN", HFILL
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_uor2_x,
+ { &hf_pdcp_lte_rohc_uor2_x,
{ "X",
"pdcp-lte.rohc.uor2.x", FT_UINT8, BASE_DEC, NULL, 0x80,
- "X", HFILL
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_add_cid,
+ { &hf_pdcp_lte_rohc_add_cid,
{ "Add-CID",
- "pdcp-lte.add-cid", FT_UINT8, BASE_DEC, NULL, 0x0f,
- "Add-CID", HFILL
+ "pdcp-lte.rohc.add-cid", FT_UINT8, BASE_DEC, NULL, 0x0f,
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_large_cid,
+ { &hf_pdcp_lte_rohc_large_cid,
{ "Large-CID",
- "pdcp-lte.large-cid", FT_UINT16, BASE_DEC, NULL, 0x07ff,
- "Large-CID", HFILL
+ "pdcp-lte.rohc.large-cid", FT_UINT16, BASE_DEC, NULL, 0x07ff,
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_uo0_sn,
+ { &hf_pdcp_lte_rohc_uo0_sn,
{ "SN",
"pdcp-lte.rohc.uo0.sn", FT_UINT8, BASE_DEC, NULL, 0x78,
- "SN", HFILL
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_uo0_crc,
+ { &hf_pdcp_lte_rohc_uo0_crc,
{ "CRC",
"pdcp-lte.rohc.uo0.crc", FT_UINT8, BASE_DEC, NULL, 0x07,
"3-bit CRC", HFILL
}
},
- { &hf_pdcp_lte_r0_sn,
+ { &hf_pdcp_lte_rohc_r0_sn,
{ "SN",
"pdcp-lte.rohc.r0.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
- "SN", HFILL
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_r0_crc_sn,
+ { &hf_pdcp_lte_rohc_r0_crc_sn,
{ "SN",
"pdcp-lte.rohc.r0-crc.sn", FT_UINT16, BASE_DEC, NULL, 0x0,
- "SN", HFILL
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_r0_crc_crc,
+ { &hf_pdcp_lte_rohc_r0_crc_crc,
{ "CRC7",
"pdcp-lte.rohc.r0-crc.crc", FT_UINT8, BASE_DEC, NULL, 0x7f,
"CRC 7", HFILL
}
},
-
- { &hf_pdcp_lte_feedback_code,
+ { &hf_pdcp_lte_rohc_feedback_code,
{ "Code",
- "pdcp-lte.feedback-code", FT_UINT8, BASE_DEC, NULL, 0x07,
+ "pdcp-lte.rohc.feedback-code", FT_UINT8, BASE_DEC, NULL, 0x07,
"Feedback options length (if > 0)", HFILL
}
},
- { &hf_pdcp_lte_feedback_size,
+ { &hf_pdcp_lte_rohc_feedback_size,
{ "Size",
- "pdcp-lte.feedback-size", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "pdcp-lte.rohc.feedback-size", FT_UINT8, BASE_DEC, NULL, 0x0,
"Feedback options length", HFILL
}
},
- { &hf_pdcp_lte_feedback_feedback1,
+ { &hf_pdcp_lte_rohc_feedback_feedback1,
{ "FEEDBACK-1 (SN)",
- "pdcp-lte.feedback.feedback1", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "pdcp-lte.rohc.feedback.feedback1", FT_UINT8, BASE_DEC, NULL, 0x0,
"Feedback-1", HFILL
}
},
- { &hf_pdcp_lte_feedback_feedback2,
+ { &hf_pdcp_lte_rohc_feedback_feedback2,
{ "FEEDBACK-2",
- "pdcp-lte.feedback.feedback2", FT_NONE, BASE_NONE, NULL, 0x0,
- "Feedback-2", HFILL
+ "pdcp-lte.rohc.feedback.feedback2", FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_feedback_ack_type,
+ { &hf_pdcp_lte_rohc_feedback_ack_type,
{ "Acktype",
- "pdcp-lte.feedback-acktype", FT_UINT8, BASE_DEC, VALS(feedback_ack_vals), 0xc0,
+ "pdcp-lte.rohc.feedback-acktype", FT_UINT8, BASE_DEC, VALS(feedback_ack_vals), 0xc0,
"Feedback-2 ack type", HFILL
}
},
- { &hf_pdcp_lte_feedback_mode,
+ { &hf_pdcp_lte_rohc_feedback_mode,
{ "mode",
- "pdcp-lte.feedback-mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x30,
+ "pdcp-lte.rohc.feedback-mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x30,
"Feedback mode", HFILL
}
},
- { &hf_pdcp_lte_feedback_sn,
+ { &hf_pdcp_lte_rohc_feedback_sn,
{ "SN",
- "pdcp-lte.feedback-sn", FT_UINT16, BASE_DEC, NULL, 0x0fff,
- "Feedback mode", HFILL
+ "pdcp-lte.rohc.feedback-sn", FT_UINT16, BASE_DEC, NULL, 0x0fff,
+ "Feedback sequence number", HFILL
}
},
- { &hf_pdcp_lte_feedback_option,
+ { &hf_pdcp_lte_rohc_feedback_option,
{ "Option",
- "pdcp-lte.feedback-option", FT_UINT8, BASE_DEC, VALS(feedback_option_vals), 0xf0,
- "Feedback mode", HFILL
+ "pdcp-lte.rohc.feedback-option", FT_UINT8, BASE_DEC, VALS(feedback_option_vals), 0xf0,
+ "Feedback option", HFILL
}
},
- { &hf_pdcp_lte_feedback_length,
+ { &hf_pdcp_lte_rohc_feedback_length,
{ "Length",
- "pdcp-lte.feedback-length", FT_UINT8, BASE_DEC, NULL, 0x0f,
+ "pdcp-lte.rohc.feedback-length", FT_UINT8, BASE_DEC, NULL, 0x0f,
"Feedback length", HFILL
}
},
- { &hf_pdcp_lte_feedback_crc,
+ { &hf_pdcp_lte_rohc_feedback_crc,
{ "CRC",
- "pdcp-lte.feedback-crc", FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
+ "pdcp-lte.rohc.feedback-crc", FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
"Feedback CRC", HFILL
}
},
- { &hf_pdcp_lte_feedback_option_sn,
+ { &hf_pdcp_lte_rohc_feedback_option_sn,
{ "SN",
- "pdcp-lte.feedback-option-sn", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "pdcp-lte.rohc.feedback-option-sn", FT_UINT8, BASE_DEC, NULL, 0x0,
"Feedback Option SN", HFILL
}
},
- { &hf_pdcp_lte_feedback_option_clock,
+ { &hf_pdcp_lte_rohc_feedback_option_clock,
{ "Clock",
- "pdcp-lte.feedback-option-clock", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "pdcp-lte.rohc.feedback-option-clock", FT_UINT8, BASE_DEC, NULL, 0x0,
"Feedback Option Clock", HFILL
}
},
- { &hf_pdcp_lte_ip_id,
+ { &hf_pdcp_lte_rohc_ip_id,
{ "IP-ID",
- "pdcp-lte.ip-id", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
- "IP-ID", HFILL
+ "pdcp-lte.rohc.ip-id", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_udp_checksum,
+ { &hf_pdcp_lte_rohc_udp_checksum,
{ "UDP Checksum",
- "pdcp-lte.udp-checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
- "UDP Checksum", HFILL
+ "pdcp-lte.rohc.udp-checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
+ NULL, HFILL
}
},
- { &hf_pdcp_lte_payload,
+ { &hf_pdcp_lte_rohc_payload,
{ "Payload",
- "pdcp-lte.payload", FT_BYTES, BASE_HEX, NULL, 0x0,
- "Payload", HFILL
+ "pdcp-lte.rohc.payload", FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL
}
},
&ett_pdcp,
&ett_pdcp_configuration,
&ett_pdcp_packet,
+ &ett_pdcp_lte_sequence_analysis,
&ett_pdcp_rohc,
&ett_pdcp_rohc_static_ipv4,
&ett_pdcp_rohc_static_udp,
"Show unciphered Signalling-Plane data as RRC",
&global_pdcp_dissect_signalling_plane_as_rrc);
+ /* Check for missing sequence numbers */
+ prefs_register_bool_preference(pdcp_lte_module, "check_sequence_numbers",
+ "Do sequence number analysis",
+ "Do sequence number analysis",
+ &global_pdcp_check_sequence_numbers);
+
/* Attempt to dissect ROHC headers */
prefs_register_bool_preference(pdcp_lte_module, "dissect_rohc",
"Attempt to decode ROHC data",
"Show ROHC feedback option tag & length",
"Show ROHC feedback option tag & length",
&global_pdcp_show_feedback_option_tag_length);
+
+ prefs_register_bool_preference(pdcp_lte_module, "heuristic_pdcp_lte_over_udp",
+ "Try Heuristic LTE-PDCP over UDP framing",
+ "When enabled, use heuristic dissector to find PDCP-LTE frames sent with "
+ "UDP framing",
+ &global_pdcp_lte_heur);
+
+ register_init_routine(&pdcp_lte_init_protocol);
}
void proto_reg_handoff_pdcp_lte(void)
{
+ /* Add as a heuristic UDP dissector */
+ heur_dissector_add("udp", dissect_pdcp_lte_heur, proto_pdcp_lte);
+
ip_handle = find_dissector("ip");
}