From b2678b43d1329ff7e330312c37bf004b453a9550 Mon Sep 17 00:00:00 2001 From: Anders Broman Date: Thu, 15 Dec 2011 17:28:43 +0000 Subject: From Per Liedberg: RoHC dissection improvment. svn path=/trunk/; revision=40210 --- epan/dissectors/packet-pdcp-lte.c | 9 ++- epan/dissectors/packet-rohc.c | 149 +++++++++++++++++++++++++++++--------- epan/dissectors/packet-rohc.h | 24 +++++- 3 files changed, 143 insertions(+), 39 deletions(-) diff --git a/epan/dissectors/packet-pdcp-lte.c b/epan/dissectors/packet-pdcp-lte.c index 57c6142357..a1d624bebc 100644 --- a/epan/dissectors/packet-pdcp-lte.c +++ b/epan/dissectors/packet-pdcp-lte.c @@ -1913,7 +1913,8 @@ static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree guint8 base_header_byte; gboolean udp_checksum_needed = TRUE; gboolean ip_id_needed = TRUE; - rohc_info *p_rohc_info = NULL; + rohc_info *p_rohc_info = NULL; + guint8 cid; /* Append this protocol name rather than replace. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE"); @@ -2218,10 +2219,12 @@ static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree } /* Add-CID octet */ + cid = 0; if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) && !p_pdcp_info->large_cid_present) { if (((tvb_get_guint8(tvb, offset) >> 4) & 0x0f) == 0x0e) { + cid = tvb_get_guint8(tvb, offset) & 0x0f; proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; } @@ -2251,7 +2254,7 @@ static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree p_rohc_info->last_created_item = NULL; /*offset = dissect_pdcp_ir_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);*/ - offset = dissect_rohc_ir_packet(tvb, rohc_tree, pinfo, offset, 0, TRUE/* fool the ROCH dissector */, p_rohc_info); + offset = dissect_rohc_ir_packet(tvb, rohc_tree, pinfo, offset, cid, TRUE/* fool the ROCH dissector */, p_rohc_info); udp_checksum_needed = FALSE; ip_id_needed = FALSE; } @@ -2272,7 +2275,7 @@ static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree p_rohc_info->last_created_item = NULL; /*offset = dissect_pdcp_irdyn_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);*/ - offset = dissect_rohc_ir_dyn_packet(tvb, rohc_tree, pinfo, offset, 0, TRUE/* fool the ROCH dissector */, p_rohc_info); + offset = dissect_rohc_ir_dyn_packet(tvb, rohc_tree, pinfo, offset, cid, TRUE/* fool the ROCH dissector */, p_rohc_info); udp_checksum_needed = FALSE; ip_id_needed = FALSE; } diff --git a/epan/dissectors/packet-rohc.c b/epan/dissectors/packet-rohc.c index 4b8dbe2e72..c1bd4fc6cd 100644 --- a/epan/dissectors/packet-rohc.c +++ b/epan/dissectors/packet-rohc.c @@ -43,6 +43,12 @@ #include #include "packet-rohc.h" + + +static dissector_handle_t ip_handle; +static dissector_handle_t ipv6_handle; + + /* Initialize the protocol and registered fields */ static int proto_rohc = -1; @@ -124,10 +130,13 @@ static int ett_rohc_dynamic_ipv4 = -1; static int ett_rohc_dynamic_udp = -1; static int ett_rohc_dynamic_rtp = -1; -/* RTP profile and IPv4 hard wired for now */ +/* IPv4 hard wired for now */ static guint8 g_profile = 1; static guint8 g_version = 4; +static rohc_context *p_rohc_context = NULL; + + /* ROHC Profiles */ #define ROHC_PROFILE_UNCOMPRESSED 0 #define ROHC_PROFILE_RTP 1 @@ -247,7 +256,7 @@ get_self_describing_var_len_val(tvbuff_t *tvb, proto_tree *tree, int offset, int } static void -dissect_rohc_feedback_data(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset, gint16 feedback_data_len, rohc_info *p_rohc_info){ +dissect_rohc_feedback_data(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset, gint16 feedback_data_len, rohc_info *p_rohc_info, guint8 cid){ proto_item *ti; proto_tree *rohc_feedback_tree; @@ -257,7 +266,7 @@ dissect_rohc_feedback_data(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, if(feedback_data_len==1){ /* FEEDBACK-1 */ proto_item_append_text(p_rohc_info->last_created_item, " (type 1)"); - switch(p_rohc_info->profile){ + switch(p_rohc_context->profile[cid]){ case ROHC_PROFILE_RTP: /* 1 */ /* * 0 1 2 3 4 5 6 7 @@ -279,7 +288,7 @@ dissect_rohc_feedback_data(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, } /* FEEDBACK-2 */ proto_item_append_text(p_rohc_info->last_created_item, " (type 2)"); - switch(p_rohc_info->profile){ + switch(p_rohc_context->profile[cid]){ case ROHC_PROFILE_RTP: /* 1 */ ti = proto_tree_add_text(tree, tvb, offset, feedback_data_len, "RTP profile-specific information"); rohc_feedback_tree = proto_item_add_subtree(ti, ett_rohc_feedback); @@ -349,7 +358,8 @@ dissect_rohc_feedback_data(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, } static int -dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, proto_tree *tree, int offset, rohc_info *p_rohc_info){ +dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, proto_tree *tree, int offset, rohc_info *p_rohc_info, guint8 cid, + rohc_context *p_rohc_context){ proto_item *item, *root_ti; proto_tree *sub_tree=NULL, *dynamic_ipv4_tree, *dynamic_udp_tree, *dynamic_rtp_tree; @@ -365,7 +375,7 @@ dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, proto_tree *tree, int offset, guint64 ts_stride=0; #endif start_offset = offset; - switch(p_rohc_info->profile){ + switch(p_rohc_context->profile[cid]){ case ROHC_PROFILE_UNCOMPRESSED: item = proto_tree_add_text(tree, tvb, offset, 0, "Profile 0x0000 Uncompressed"); @@ -386,7 +396,7 @@ dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, proto_tree *tree, int offset, /* IP dynamic*/ /* for all profiles except uncompressed */ - if ( (p_rohc_info->profile != ROHC_PROFILE_UNCOMPRESSED) ) { + if ( (p_rohc_context->profile[cid] != ROHC_PROFILE_UNCOMPRESSED) ) { sub_tree = proto_item_add_subtree(item, ett_rohc_rtp_dynamic); switch(p_rohc_info->rohc_ip_version){ case 4: @@ -457,8 +467,8 @@ dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, proto_tree *tree, int offset, } /* UDP dynamic*/ - if ( (p_rohc_info->profile == ROHC_PROFILE_UDP) || - (p_rohc_info->profile == ROHC_PROFILE_RTP) ) { + if ( (p_rohc_context->profile[cid] == ROHC_PROFILE_UDP) || + (p_rohc_context->profile[cid] == ROHC_PROFILE_RTP) ) { /* 5.7.7.5. Initialization of UDP Header * Dynamic part: * @@ -475,7 +485,7 @@ dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, proto_tree *tree, int offset, } /* RTP dynamic*/ - if ( (p_rohc_info->profile == ROHC_PROFILE_RTP) ) { + if ( (p_rohc_context->profile[cid] == ROHC_PROFILE_RTP) ) { /* 5.7.7.6. Initialization of RTP Header * Dynamic part: * Checksum @@ -571,7 +581,8 @@ dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, proto_tree *tree, int offset, } static int -dissect_rohc_ir_rtp_udp_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset, gboolean d, rohc_info *p_rohc_info){ +dissect_rohc_ir_rtp_udp_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset, gboolean d, rohc_info *p_rohc_info, + guint8 cid, rohc_context *p_rohc_context){ proto_item *item, *ipv4_item, *udp_item, *rtp_item; proto_tree *sub_tree=NULL, *static_ipv4_tree, *static_udp_tree, *static_rtp_tree; @@ -579,7 +590,7 @@ dissect_rohc_ir_rtp_udp_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_i int start_offset, tree_start_offset; start_offset = offset; - switch(p_rohc_info->profile){ + switch(p_rohc_context->profile[cid]){ case ROHC_PROFILE_UNCOMPRESSED: item = proto_tree_add_text(tree, tvb, offset, 0, "Profile 0x0000 Uncompressed"); @@ -600,7 +611,7 @@ dissect_rohc_ir_rtp_udp_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_i /* IP static*/ /* for all profiles except uncompressed */ - if ( (p_rohc_info->profile != ROHC_PROFILE_UNCOMPRESSED) ) { + if ( (p_rohc_context->profile[cid] != ROHC_PROFILE_UNCOMPRESSED) ) { sub_tree = proto_item_add_subtree(item, ett_rohc_rtp_static); version = tvb_get_guint8(tvb,offset)>>4; proto_tree_add_item(sub_tree, hf_rohc_ip_version, tvb, offset, 1, ENC_BIG_ENDIAN); @@ -686,8 +697,8 @@ dissect_rohc_ir_rtp_udp_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_i } /* UDP static */ - if ((p_rohc_info->profile == ROHC_PROFILE_RTP) || - (p_rohc_info->profile == ROHC_PROFILE_UDP)) { + if ((p_rohc_context->profile[cid] == ROHC_PROFILE_RTP) || + (p_rohc_context->profile[cid] == ROHC_PROFILE_UDP)) { /* 5.7.7.5. Initialization of UDP Header [RFC-768]. * Static part */ @@ -710,9 +721,9 @@ dissect_rohc_ir_rtp_udp_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_i /* Add summary to root item */ proto_item_append_text(udp_item, " (%u -> %u)", source_port, dest_port); - if(p_rohc_info->profile == ROHC_PROFILE_UDP){ + if(p_rohc_context->profile[cid] == ROHC_PROFILE_UDP){ if(d==TRUE){ - offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, tree, offset, p_rohc_info); + offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, tree, offset, p_rohc_info, cid, p_rohc_context); } proto_item_set_len(item, offset - start_offset); return offset; @@ -736,7 +747,7 @@ dissect_rohc_ir_rtp_udp_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_i /* D: D = 1 indicates that the dynamic chain is present. */ if(d==TRUE){ - offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, tree, offset, p_rohc_info); + offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, tree, offset, p_rohc_info, cid, p_rohc_context); } } return offset; @@ -751,6 +762,52 @@ dissect_rohc_ir_packet(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int gboolean d = FALSE; guint8 oct, profile, val_len; gint16 feedback_data_len = 0; + guint16 i; + tvbuff_t *next_tvb; + /* This function is potentially called from both dissect_rohc and dissect_pdcp_lte + * This function allocates memory for the static ROHC context "p_rohc_context" if missing + * The cid value must have been dissected and valid + * offset must point to the IR octet see below ( | 1 1 1 1 1 1 0 | D | ) + * TODO: CRC validation + */ + /* + + 0 1 2 3 4 5 6 7 + --- --- --- --- --- --- --- --- + | Add-CID octet | if for small CIDs and CID != 0 + +---+---+---+---+---+---+---+---+ + | 1 1 1 1 1 1 0 | D | + +---+---+---+---+---+---+---+---+ + | | + / 0-2 octets of CID info / 1-2 octets if for large CIDs + | | + +---+---+---+---+---+---+---+---+ + | Profile | 1 octet + +---+---+---+---+---+---+---+---+ + | CRC | 1 octet + +---+---+---+---+---+---+---+---+ + | | + | Static chain | variable length + | | + +---+---+---+---+---+---+---+---+ + | | + | Dynamic chain | present if D = 1, variable length + | | + - - - - - - - - - - - - - - - - + | | + | Payload | variable length + | | + - - - - - - - - - - - - - - - - + + */ + /* Allocate memory and init static context p_rohc_context with a capture lifetime scope if missing*/ + if(!se_verify_pointer(p_rohc_context)) { + p_rohc_context = se_new(rohc_context); + for (i=0;i<=MAX_CID;i++){ + p_rohc_context->profile[i] = 0xffff; + p_rohc_context->rohc_ip_version[i] = g_version; + } + } oct = tvb_get_guint8(tvb,offset); @@ -773,25 +830,40 @@ dissect_rohc_ir_packet(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int proto_tree_add_item(ir_tree, hf_rohc_d_bit, tvb, x_bit_offset, 1, ENC_BIG_ENDIAN); } item = proto_tree_add_item(ir_tree, hf_rohc_profile, tvb, offset, 1, ENC_BIG_ENDIAN); - if(p_rohc_info->profile != profile){ + /* copy selected parts to resident struct */ + p_rohc_context->rohc_ip_version[cid] = p_rohc_info->rohc_ip_version; + p_rohc_context->large_cid_present[cid] = p_rohc_info->large_cid_present; + /* init valid profile if missing */ + if(p_rohc_context->profile[cid] == 0xffff) p_rohc_context->profile[cid] = profile; + /* Update/Change profile to an initiated CID not implemented issue a warning for this */ + if(p_rohc_context->profile[cid] != profile){ expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN, - "Configured profile %u, differs from actual profile %u, Dissection of other packets may be faulty", - p_rohc_info->profile, profile); - /* Oweride the configured profile */ - p_rohc_info->profile = profile; + "Configured profile %u, differs from actual profile %u, cid %u, Dissection of other packets may be faulty", + p_rohc_context->profile[cid], profile, cid); } offset++; proto_tree_add_item(ir_tree, hf_rohc_rtp_crc, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; switch(profile){ case ROHC_PROFILE_UNCOMPRESSED: - offset = dissect_rohc_ir_rtp_udp_profile_static(tvb, ir_tree, pinfo, offset, d, p_rohc_info); + /* + offset = dissect_rohc_ir_rtp_udp_profile_static(tvb, ir_tree, pinfo, offset, d, p_rohc_info, cid, p_rohc_context); + */ + next_tvb = tvb_new_subset_remaining(tvb, offset); + if ( (oct&0xf0) == 0x60 ) { + call_dissector(ipv6_handle, next_tvb, pinfo, tree); + } + else { + call_dissector(ip_handle, next_tvb, pinfo, tree); + } + col_prepend_fstr(pinfo->cinfo, COL_PROTOCOL, "ROHC <"); + col_append_str(pinfo->cinfo, COL_PROTOCOL, ">"); break; case ROHC_PROFILE_RTP: - offset = dissect_rohc_ir_rtp_udp_profile_static(tvb, ir_tree, pinfo, offset, d, p_rohc_info); + offset = dissect_rohc_ir_rtp_udp_profile_static(tvb, ir_tree, pinfo, offset, d, p_rohc_info, cid, p_rohc_context); break; case ROHC_PROFILE_UDP: - offset = dissect_rohc_ir_rtp_udp_profile_static(tvb, ir_tree, pinfo, offset, d, p_rohc_info); + offset = dissect_rohc_ir_rtp_udp_profile_static(tvb, ir_tree, pinfo, offset, d, p_rohc_info, cid, p_rohc_context); break; default: proto_tree_add_text(ir_tree, tvb, offset, feedback_data_len, "profile-specific information[Not dissected yet]"); @@ -824,19 +896,18 @@ dissect_rohc_ir_dyn_packet(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, profile = tvb_get_guint8(tvb,offset); item = proto_tree_add_item(ir_tree, hf_rohc_profile, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; - if(p_rohc_info->profile != profile){ + if(p_rohc_context->profile[cid] == 0xffff) p_rohc_context->profile[cid] = profile; + if(p_rohc_context->profile[cid] != profile){ expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN, - "Configured profile %u, differs from actual profile %u, Dissection of other packets may be faulty", - p_rohc_info->profile, profile); - /* Oweride the configured profile */ - p_rohc_info->profile = profile; + "Configured profile %u, differs from actual profile %u, cid %u, Dissection of other packets may be faulty", + p_rohc_context->profile[cid], profile, cid); } proto_tree_add_item(ir_tree, hf_rohc_rtp_crc, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; switch(profile){ case ROHC_PROFILE_RTP: /* TODO: Currently IPv4 Hardwired, use conversation info or preference ? */ - dissect_rohc_ir_rtp_profile_dynamic(tvb, ir_tree, offset, p_rohc_info); + dissect_rohc_ir_rtp_profile_dynamic(tvb, ir_tree, offset, p_rohc_info, cid, p_rohc_context); break; default: proto_tree_add_text(ir_tree, tvb, offset, feedback_data_len, "profile-specific information[Not dissected yet]"); @@ -857,7 +928,6 @@ dissect_rohc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) rohc_info *p_rohc_info = NULL; rohc_info g_rohc_info; - if(pinfo->private_data != NULL){ p_rohc_info = pinfo->private_data; memset(&g_rohc_info, 0, sizeof(rohc_info)); @@ -978,7 +1048,7 @@ start_over: feedback_data_len = feedback_data_len - val_len; } /* Dissect feedback */ - dissect_rohc_feedback_data(tvb, sub_tree, pinfo, offset, feedback_data_len, p_rohc_info); + dissect_rohc_feedback_data(tvb, sub_tree, pinfo, offset, feedback_data_len, p_rohc_info, cid); offset = offset + size; if(offset