wireshark/epan/dissectors/packet-rohc.c
Michael Mann ad6fc87d64 Add proto_tree_add_checksum.
This is an attempt to standardize display/handling of checksum fields for all dissectors.
The main target is for dissectors that do validation, but dissectors that just report the
checksum were also included just to make them easier to find in the future.

Bug: 10620
Bug: 12058
Ping-Bug: 8859
Change-Id: Ia8abd86e42eaf8ed50de6b173409e914b17993bf
Reviewed-on: https://code.wireshark.org/review/16380
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Jeff Morriss <jeff.morriss.ws@gmail.com>
Reviewed-by: Michael Mann <mmann78@netscape.net>
2016-07-21 12:35:22 +00:00

3015 lines
125 KiB
C

/* packet-rohc.c
* Routines for RObust Header Compression (ROHC) dissection.
*
* Copyright 2011, Anders Broman <anders.broman[at]ericsson.com>
* Per Liedberg <per.liedberg [at]ericsson.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Ref:
* http://www.ietf.org/rfc/rfc3095.txt RObust Header Compression (ROHC): Framework and four profiles: RTP, UDP, ESP, and uncompressed
* http://datatracker.ietf.org/doc/rfc4815/ RObust Header Compression (ROHC): Corrections and Clarifications to RFC 3095
* http://datatracker.ietf.org/doc/rfc5225/ RObust Header Compression Version 2 (ROHCv2): Profiles for RTP, UDP, IP, ESP and UDP-Lite
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/etypes.h>
#include <epan/ipproto.h>
#include <epan/addr_resolv.h>
#include <epan/rtp_pt.h>
#include <epan/expert.h>
#include <epan/proto_data.h>
#include "packet-rohc.h"
void proto_register_rohc(void);
void proto_reg_handoff_rohc(void);
static GHashTable *rohc_cid_hash = NULL;
/* Initialize the protocol and registered fields */
static int proto_rohc = -1;
static int hf_rohc_padding = -1;
static int hf_rohc_add_cid = -1;
static int hf_rohc_feedback = -1;
static int hf_rohc_code = -1;
static int hf_rohc_size = -1;
static int hf_rohc_ir_packet = -1;
static int hf_rohc_ir_dyn_packet = -1;
static int hf_rohc_small_cid = -1;
static int hf_rohc_large_cid = -1;
static int hf_rohc_acktype = -1;
static int hf_rohc_mode = -1;
static int hf_rohc_sn = -1;
static int hf_rohc_profile_spec_octet = -1;
static int hf_rohc_fb1_sn = -1;
static int hf_rohc_opt_type = -1;
static int hf_rohc_opt_len = -1;
static int hf_rohc_crc = -1;
static int hf_rohc_opt_sn = -1;
static int hf_rohc_ext_sn = -1;
static int hf_rohc_opt_clock = -1;
static int hf_rohc_opt_jitter = -1;
static int hf_rohc_opt_loss = -1;
static int hf_rohc_profile = -1;
static int hf_rohc_d_bit = -1;
static int hf_rohc_ip_version = -1;
static int hf_rohc_ip_protocol = -1;
static int hf_rohc_static_ipv4 = -1;
static int hf_rohc_ipv4_src = -1;
static int hf_rohc_ipv4_dst = -1;
static int hf_rohc_ipv6_flow = -1;
static int hf_rohc_ipv6_nxt_hdr = -1;
static int hf_rohc_ipv6_src = -1;
static int hf_rohc_ipv6_dst = -1;
static int hf_rohc_static_udp = -1;
static int hf_rohc_udp_src_port = -1;
static int hf_rohc_udp_dst_port = -1;
static int hf_rohc_static_rtp = -1;
static int hf_rohc_rtp_ssrc = -1;
static int hf_rohc_dynamic_ipv4 = -1;
static int hf_rohc_dynamic_udp = -1;
static int hf_rohc_rtp_tos = -1;
static int hf_rohc_rtp_ttl = -1;
static int hf_rohc_rtp_id = -1;
static int hf_rohc_rtp_df = -1;
static int hf_rohc_rtp_rnd = -1;
static int hf_rohc_rtp_nbo = -1;
static int hf_rohc_dynamic_udp_checksum = -1;
static int hf_rohc_dynamic_rtp =-1;
static int hf_rohc_rtp_v = -1;
static int hf_rohc_rtp_p = -1;
static int hf_rohc_rtp_rx = -1;
static int hf_rohc_rtp_cc = -1;
static int hf_rohc_rtp_m = -1;
static int hf_rohc_rtp_pt = -1;
static int hf_rohc_rtp_sn = -1;
static int hf_rohc_rtp_timestamp = -1;
static int hf_rohc_rtp_x = -1;
static int hf_rohc_rtp_mode = -1;
static int hf_rohc_rtp_tis = -1;
static int hf_rohc_rtp_tss = -1;
static int hf_rohc_rtp_ts_stride = -1;
static int hf_rohc_rtp_time_stride = -1;
static int hf_rohc_var_len = -1;
static int hf_rohc_ipv6_tc = -1;
static int hf_rohc_ipv6_hop_limit = -1;
static int hf_rohc_ir_pkt_frame = -1;
static int hf_rohc_ir_previous_frame = -1;
static int hf_rohc_ir_profile = -1;
static int hf_rohc_ir_ip_version = -1;
static int hf_rohc_ir_mode = -1;
static int hf_rohc_comp_sn = -1;
static int hf_rohc_r_0_crc = -1;
static int hf_rohc_x = -1;
static int hf_rohc_ts = -1;
static int hf_rohc_comp_ip_id = -1;
static int hf_rohc_t = -1;
static int hf_rohc_compressed_list = -1;
static int hf_rohc_compressed_list_et = -1;
static int hf_rohc_compressed_list_gp = -1;
static int hf_rohc_compressed_list_ps = -1;
static int hf_rohc_compressed_list_res = -1;
static int hf_rohc_compressed_list_count = -1;
static int hf_rohc_compressed_list_cc = -1;
static int hf_rohc_compressed_list_xi_1 = -1;
static int hf_rohc_compressed_list_gen_id = -1;
static int hf_rohc_compressed_list_ref_id = -1;
static int hf_rohc_compressed_list_mask_size = -1;
static int hf_rohc_compressed_list_ins_bit_mask = -1;
static int hf_rohc_compressed_list_rem_bit_mask = -1;
static int hf_rohc_spare_bits = -1;
static int hf_rohc_ip_id = -1;
static int hf_rohc_udp_checksum = -1;
/* Generated from convert_proto_tree_add_text.pl */
static int hf_rohc_no_configuration_info = -1;
static int hf_rohc_unknown_option_data = -1;
static int hf_rohc_error_packet = -1;
static int hf_rohc_configured_by_ir_packet = -1;
static int ett_rohc = -1;
static int ett_rohc_conf = -1;
static int ett_rohc_fb = -1;
static int ett_rohc_feedback = -1;
static int ett_rohc_ir = -1;
static int ett_rohc_ir_dyn = -1;
static int ett_rohc_static_ipv4 = -1;
static int ett_rohc_static_udp = -1;
static int ett_rohc_static_rtp = -1;
static int ett_rohc_rtp_static = -1;
static int ett_rohc_rtp_dynamic = -1;
static int ett_rohc_dynamic_ipv4 = -1;
static int ett_rohc_dynamic_udp = -1;
static int ett_rohc_dynamic_rtp = -1;
static int ett_rohc_compressed_list = -1;
static int ett_rohc_packet = -1;
static expert_field ei_rohc_profile_spec_octet = EI_INIT;
static expert_field ei_rohc_rohc_opt_clock = EI_INIT;
static expert_field ei_rohc_opt_jitter = EI_INIT;
static expert_field ei_rohc_feedback_type_2_is_not_applicable_for_uncompressed_profile = EI_INIT;
static expert_field ei_rohc_not_dissected_yet = EI_INIT;
static expert_field ei_rohc_profile_specific = EI_INIT;
static expert_field ei_rohc_profile_not_supported = EI_INIT;
static expert_field ei_rohc_ip_version = EI_INIT;
static expert_field ei_rohc_desegmentation_not_implemented = EI_INIT;
static dissector_handle_t rohc_handle;
static dissector_handle_t ip_handle;
static dissector_handle_t ipv6_handle;
typedef struct _rohc_cid_context_t
{
guint16 rohc_ip_version;
gboolean large_cid_present;
enum rohc_mode mode;
enum rohc_d_mode d_mode;
gboolean rnd;
gboolean udp_checksum_present;
guint16 profile;
gint prev_ir_frame_number; /* The frame number of the previous IR packet seen */
gint ir_frame_number; /* The frame number of the latest IR packet seen */
} rohc_cid_context_t;
/* ROHC Profiles */
#define ROHC_PROFILE_UNCOMPRESSED 0
#define ROHC_PROFILE_RTP 1
#define ROHC_PROFILE_UDP 2
#define ROHC_PROFILE_IP 4
#define ROHC_PROFILE_UNKNOWN 0xFFFF
static const value_string rohc_profile_vals[] =
{
{ 0x0000, "Uncompressed" }, /*RFC 5795*/
{ 0x0001, "RTP" }, /*RFC 3095*/
{ 0x0002, "UDP" }, /*RFC 3095*/
{ 0x0003, "ESP" }, /*RFC 3095*/
{ 0x0004, "IP" }, /*RFC 3843*/
{ 0x0005, "LLA" }, /*RFC 3242*/
{ 0x0105, "LLA with R-mode" }, /*RFC 3408*/
{ 0x0006, "TCP" }, /*RFC 4996*/
{ 0x0007, "RTP/UDP-Lite" }, /*RFC 4019*/
{ 0x0008, "UDP-Lite" }, /*RFC 4019*/
{ 0x0101, "v2 RTP" }, /*RFC 5225*/
{ 0x0102, "v2 UDP" }, /*RFC 5225*/
{ 0x0103, "v2 ESP" }, /*RFC 5225*/
{ 0x0104, "v2 IP" }, /*RFC 5225*/
{ 0x0107, "v2 RTP/UDP-Lite" }, /*RFC 5225*/
{ 0x0108, "v2 UDP-Lite" }, /*RFC 5225*/
{ 0, NULL },
};
/* IPv4 hard wired for now */
static guint16 g_profile = ROHC_PROFILE_UNKNOWN;
static guint8 g_version = 4;
static const value_string rohc_acktype_vals[] =
{
{ 0, "ACK" },
{ 1, "NACK" },
{ 2, "STATIC-NACK" },
{ 3, "reserved (MUST NOT be used. Otherwise unparsable)" },
{ 0, NULL },
};
static const value_string rohc_mode_vals[] =
{
{ 0, "Reserved" },
{ 1, "Unidirectional" },
{ 2, "Bidirectional Optimistic" },
{ 3, "Bidirectional Reliable" },
{ 0, NULL },
};
static const value_string rohc_opt_type_vals[] =
{
{ 1, "CRC" },
{ 2, "REJECT" },
{ 3, "SN-NOT-VALID" },
{ 4, "SN" },
{ 5, "CLOCK" },
{ 6, "JITTER" },
{ 7, "LOSS" },
{ 0, NULL },
};
static const value_string rohc_ip_version_vals[] =
{
{ 4, "IPv4" },
{ 6, "IPv6" },
{ 0, NULL },
};
static const value_string rohc_var_len_vals[] =
{
{ 0, "One octet" },
{ 2, "Two octets" },
{ 6, "Three octets" },
{ 7, "Four octets" },
{ 0, NULL },
};
static const value_string compressed_list_encoding_type_vals[] =
{
{ 0, "Generic scheme" },
{ 1, "Insertion only scheme" },
{ 2, "Removal only scheme" },
{ 3, "Remove then insert scheme" },
{ 0, NULL },
};
static const value_string compressed_list_ps_vals[] =
{
{ 0, "4-bit XI fields" },
{ 1, "8-bit XI fields" },
{ 0, NULL },
};
/* 4.5.6. Self-describing variable-length values */
static guint32
get_self_describing_var_len_val(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_index, guint8 *val_len){
guint8 oct;
guint32 val = 0;
int num_bits = 0, bit_offset = offset <<3;
oct = tvb_get_guint8(tvb, offset);
if((oct&0x80)==0){
/* One octet */
*val_len = 1;
val = (oct&0x7f);
proto_tree_add_bits_item(tree, hf_rohc_var_len, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
num_bits = 7;
bit_offset++;
}else if((oct&0xc0)==0x80){
/* Two octets */
*val_len = 2;
proto_tree_add_bits_item(tree, hf_rohc_var_len, tvb, bit_offset, 2, ENC_BIG_ENDIAN);
bit_offset+=2;
num_bits = 14;
val = tvb_get_ntohs(tvb, offset)&0x3fff;
}else if((oct&0xe0)==0xc0){
/* Three octets */
*val_len = 3;
proto_tree_add_bits_item(tree, hf_rohc_var_len, tvb, bit_offset, 3, ENC_BIG_ENDIAN);
bit_offset+=3;
num_bits = 21;
val = tvb_get_ntoh24(tvb, offset)&0x1fffff;
}else if ((oct&0xe0)==0xe0){
/* Four octets */
*val_len = 4;
proto_tree_add_bits_item(tree, hf_rohc_var_len, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
bit_offset+=3;
num_bits = 29;
val = tvb_get_ntohl(tvb, offset)&0x1fffffff;
}
proto_tree_add_bits_item(tree, hf_index, tvb, bit_offset, num_bits, ENC_BIG_ENDIAN);
return val;
}
/* 5.7.1. Packet type 0: UO-0, R-0, R-0-CRC */
static int
dissect_rohc_pkt_type_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint8 pkt_type, rohc_cid_context_t *rohc_cid_context)
{
guint8 val_len = 0;
guint64 sn;
proto_tree *pkt_tree;
switch(rohc_cid_context->mode){
case RELIABLE_BIDIRECTIONAL: /* R-mode */
if((pkt_type&0xc0)==0x00){
/* R-0
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 0 0 | SN |
* +===+===+===+===+===+===+===+===+
*/
if (rohc_cid_context->large_cid_present == TRUE) {
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, tree, offset+1, hf_rohc_large_cid, &val_len);
}
col_set_str(pinfo->cinfo, COL_INFO, "R-0");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, 1+val_len, ett_rohc_packet, NULL, "R-0 packet");
sn = tvb_get_bits8(tvb,(offset<<3)+2, 6);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
offset += 1 + val_len;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", (guint)sn);
}else if((pkt_type&0xc0)==0x40){
/* R-0-CRC
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 0 1 | SN |
* +===+===+===+===+===+===+===+===+
* |SN | CRC |
* +---+---+---+---+---+---+---+---+
*/
crumb_spec_t rohc_sn_crumbs[] = {
{ 2, 6},
{ 8, 1},
{ 0, 0}
};
if (rohc_cid_context->large_cid_present == TRUE) {
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, tree, offset+1, hf_rohc_large_cid, &val_len);
rohc_sn_crumbs[1].crumb_bit_offset += val_len*8;
}
col_set_str(pinfo->cinfo, COL_INFO, "R-0-CRC");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, 2+val_len, ett_rohc_packet, NULL, "R-0-CRC packet");
proto_tree_add_split_bits_item_ret_val(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3),
rohc_sn_crumbs, &sn);
offset += 1 + val_len;
proto_tree_add_bits_item(pkt_tree, hf_rohc_r_0_crc, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
offset++;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", (guint)sn);
}
break;
case UNIDIRECTIONAL: /* U-mode */
/* Fall trough */
case OPTIMISTIC_BIDIRECTIONAL: /* O-mode */
/* UO-0
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 0 | SN | CRC |
* +===+===+===+===+===+===+===+===+
*/
if (rohc_cid_context->large_cid_present == TRUE) {
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, tree, offset+1, hf_rohc_large_cid, &val_len);
}
col_set_str(pinfo->cinfo, COL_INFO, "UO-0");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, 1+val_len, ett_rohc_packet, NULL, "UO-0 packet");
sn = tvb_get_bits8(tvb,(offset<<3)+1, 4);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+1, 4, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_r_0_crc, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
offset += 1 + val_len;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", (guint)sn);
break;
default:
col_set_str(pinfo->cinfo, COL_INFO, "Packet type 0");
break;
}
return offset;
}
/* 5.7.5. Extension formats */
static int
dissect_rohc_ext_format(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint8 t, rohc_cid_context_t *rohc_cid_context)
{
guint8 ext_type = tvb_get_guint8(tvb, offset) & 0xc0;
proto_tree_add_bits_item(tree, hf_rohc_comp_sn, tvb, (offset<<3)+2, 3, ENC_BIG_ENDIAN);
if (ext_type == 0x00) {
/* Extension 0:
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 0 0 | SN | +T |
* +---+---+---+---+---+---+---+---+
*/
if ((t == 0) || (rohc_cid_context->profile == ROHC_PROFILE_UDP)) {
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
} else {
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
}
offset++;
} else if (ext_type == 0x40) {
/* Extension 1:
*
* +---+---+---+---+---+---+---+---+
* | 0 1 | SN | +T |
* +---+---+---+---+---+---+---+---+
* | -T |
* +---+---+---+---+---+---+---+---+
*/
if (rohc_cid_context->profile == ROHC_PROFILE_UDP) {
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+5, 11, ENC_BIG_ENDIAN);
offset++;
}else if (t == 0) {
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3), 8, ENC_BIG_ENDIAN);
} else if (t == 1) {
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3), 8, ENC_BIG_ENDIAN);
} else {
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3), 8, ENC_BIG_ENDIAN);
}
offset++;
} else if (ext_type == 0x80) {
/* Extension 2:
*
* +---+---+---+---+---+---+---+---+
* | 1 0 | SN | +T |
* +---+---+---+---+---+---+---+---+
* | +T |
* +---+---+---+---+---+---+---+---+
* | -T |
* +---+---+---+---+---+---+---+---+
*/
if (rohc_cid_context->profile == ROHC_PROFILE_UDP) {
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+5, 11, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3), 8, ENC_BIG_ENDIAN);
}else if (t == 0) {
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+5, 11, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3), 8, ENC_BIG_ENDIAN);
} else if (t == 1) {
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3)+5, 11, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_bits_item(tree, hf_rohc_comp_ip_id, tvb, (offset<<3), 8, ENC_BIG_ENDIAN);
} else {
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3)+5, 11, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_bits_item(tree, hf_rohc_ts, tvb, (offset<<3), 8, ENC_BIG_ENDIAN);
}
offset++;
} else {
proto_tree_add_expert_format(tree, pinfo, &ei_rohc_not_dissected_yet, tvb, offset, -1, "extension 3 [Not dissected yet]");
if (tvb_captured_length_remaining(tvb, offset) > 0)
offset += tvb_captured_length_remaining(tvb, offset);
}
return offset;
}
/* 5.7.2. Packet type 1 (R-mode): R-1, R-1-TS, R-1-ID */
static int
dissect_rohc_pkt_type_1_r_mode(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, rohc_cid_context_t *rohc_cid_context)
{
proto_item *ti;
proto_tree *pkt_tree;
guint8 val_len = 0, x, sn, t = 0xff;
int start_offset = offset;
if (rohc_cid_context->large_cid_present == TRUE) {
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, tree, offset+1, hf_rohc_large_cid, &val_len);
}
if ((rohc_cid_context->rohc_ip_version != 4) ||
(rohc_cid_context->rnd == 1) ||
(rohc_cid_context->profile == ROHC_PROFILE_UDP)) {
/* R-1 (RTP profile)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 | SN |
* +===+===+===+===+===+===+===+===+
* | M | X | TS |
* +---+---+---+---+---+---+---+---+
*/
/* R-1 (UDP profile)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 | SN |
* +===+===+===+===+===+===+===+===+
* | X | IP-ID |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "R-1");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "R-1 packet");
sn = tvb_get_bits8(tvb, (offset<<3)+2, 6);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
offset += 1 + val_len;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
if (rohc_cid_context->profile == ROHC_PROFILE_UDP) {
x= tvb_get_bits8(tvb, (offset<<3), 1);
proto_tree_add_bits_item(pkt_tree, hf_rohc_x, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
} else {
proto_tree_add_bits_item(pkt_tree, hf_rohc_rtp_m, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
x = tvb_get_bits8(tvb, (offset<<3)+1, 1);
proto_tree_add_bits_item(pkt_tree, hf_rohc_x, tvb, (offset<<3)+1, 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_ts, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
}
offset++;
} else {
t = tvb_get_bits8(tvb, ((offset+1+val_len)<<3)+2, 1);
if (t == 0) {
/* R-1-ID
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 | SN |
* +===+===+===+===+===+===+===+===+
* | M | X |T=0| IP-ID |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "R-1-ID");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "R-1-ID packet");
} else {
/* R-1-TS
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 | SN |
* +===+===+===+===+===+===+===+===+
* | M | X |T=1| TS |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "R-1-TS");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "R-1-TS packet");
}
sn = tvb_get_bits8(tvb, (offset<<3)+2, 6);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
offset += 1 + val_len;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
proto_tree_add_bits_item(pkt_tree, hf_rohc_rtp_m, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
x = tvb_get_bits8(tvb, (offset<<3)+1, 1);
proto_tree_add_bits_item(pkt_tree, hf_rohc_x, tvb, (offset<<3)+1, 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_t, tvb, (offset<<3)+2, 1, ENC_BIG_ENDIAN);
if (t == 0) {
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
} else {
proto_tree_add_bits_item(pkt_tree, hf_rohc_ts, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
}
offset++;
}
if (x) {
offset = dissect_rohc_ext_format(tvb, pinfo, pkt_tree, offset, t, rohc_cid_context);
}
proto_item_set_len(ti, offset-start_offset);
return offset;
}
/* 5.7.3. Packet type 1 (U/O-mode): UO-1, UO-1-ID, UO-1-TS */
static int
dissect_rohc_pkt_type_1_u_o_mode(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, rohc_cid_context_t *rohc_cid_context)
{
proto_item *ti;
proto_tree *pkt_tree;
guint8 val_len = 0, x = 0, sn, t = 0xff;
int start_offset = offset;
if (rohc_cid_context->large_cid_present == TRUE) {
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, tree, offset+1, hf_rohc_large_cid, &val_len);
}
if ((rohc_cid_context->rohc_ip_version != 4) ||
(rohc_cid_context->rnd == 1) ||
(rohc_cid_context->profile == ROHC_PROFILE_UDP)) {
/* UO-1 (RTP profile)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 | TS |
* +===+===+===+===+===+===+===+===+
* | M | SN | CRC |
* +---+---+---+---+---+---+---+---+
*/
/* UO-1 (UDP profile)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 | IP-ID |
* +===+===+===+===+===+===+===+===+
* | SN | CRC |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "UO-1");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "UO-1 packet");
if (rohc_cid_context->profile == ROHC_PROFILE_UDP) {
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
offset += 1 + val_len;
sn = tvb_get_bits8(tvb, (offset<<3), 5);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3), 5, ENC_BIG_ENDIAN);
} else {
proto_tree_add_bits_item(pkt_tree, hf_rohc_ts, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
offset += 1 + val_len;
proto_tree_add_bits_item(pkt_tree, hf_rohc_rtp_m, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
sn = tvb_get_bits8(tvb, (offset<<3)+1, 4);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+1, 4, ENC_BIG_ENDIAN);
}
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
proto_tree_add_bits_item(pkt_tree, hf_rohc_crc, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
offset++;
} else {
t = tvb_get_bits8(tvb, ((offset)<<3)+2, 1);
if (t == 0) {
/* UO-1-ID
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 |T=0| IP-ID |
* +===+===+===+===+===+===+===+===+
* | X | SN | CRC |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "UO-1-ID");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "UO-1-ID packet");
proto_tree_add_bits_item(pkt_tree, hf_rohc_t, tvb, (offset<<3)+2, 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
offset += 1 + val_len;
x = tvb_get_bits8(tvb, (offset<<3), 1);
proto_tree_add_bits_item(pkt_tree, hf_rohc_x, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
} else {
/* UO-1-TS
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 0 |T=1| TS |
* +===+===+===+===+===+===+===+===+
* | M | SN | CRC |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "UO-1-TS");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "UO-1-TS packet");
proto_tree_add_bits_item(pkt_tree, hf_rohc_t, tvb, (offset<<3)+2, 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_ts, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
offset += 1 + val_len;
proto_tree_add_bits_item(pkt_tree, hf_rohc_rtp_m, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
}
sn = tvb_get_bits8(tvb, (offset<<3)+1, 4);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+1, 4, ENC_BIG_ENDIAN);
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
proto_tree_add_bits_item(pkt_tree, hf_rohc_crc, tvb, (offset<<3)+5, 3, ENC_BIG_ENDIAN);
offset++;
}
if (x) {
offset = dissect_rohc_ext_format(tvb, pinfo, pkt_tree, offset, t, rohc_cid_context);
}
proto_item_set_len(ti, offset-start_offset);
return offset;
}
/* 5.7.4. Packet type 2: UOR-2 */
static int
dissect_rohc_pkt_type_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, rohc_cid_context_t *rohc_cid_context)
{
proto_item *ti;
proto_tree *pkt_tree;
guint8 val_len = 0, x, sn, t = 0xff;
int start_offset = offset;
if (rohc_cid_context->large_cid_present == TRUE) {
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, tree, offset+1, hf_rohc_large_cid, &val_len);
}
if ((rohc_cid_context->rohc_ip_version != 4) ||
(rohc_cid_context->rnd == 1) ||
(rohc_cid_context->profile == ROHC_PROFILE_UDP)) {
/* UOR-2 (RTP profile)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 1 0 | TS |
* +===+===+===+===+===+===+===+===+
* |TS | M | SN |
* +---+---+---+---+---+---+---+---+
* | X | CRC |
* +---+---+---+---+---+---+---+---+
*/
/* UOR-2 (UDP profile)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 1 0 | SN |
* +===+===+===+===+===+===+===+===+
* | X | CRC |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "UOR-2");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "UOR-2 packet");
if (rohc_cid_context->profile == ROHC_PROFILE_UDP) {
sn = tvb_get_bits8(tvb, (offset<<3)+3, 5);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
offset += 1 + val_len;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
} else {
crumb_spec_t rohc_ts_crumbs[] = {
{ 2, 6},
{ 8, 1},
{ 0, 0}
};
rohc_ts_crumbs[1].crumb_bit_offset += val_len*8;
proto_tree_add_split_bits_item_ret_val(pkt_tree, hf_rohc_ts, tvb, (offset<<3),
rohc_ts_crumbs, NULL);
offset += 1 + val_len;
proto_tree_add_bits_item(pkt_tree, hf_rohc_rtp_m, tvb, (offset<<3)+1, 1, ENC_BIG_ENDIAN);
sn = tvb_get_bits8(tvb, (offset<<3)+2, 6);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
offset++;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
}
x = tvb_get_bits8(tvb, (offset<<3), 1);
proto_tree_add_bits_item(pkt_tree, hf_rohc_x, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_crc, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
offset++;
} else {
t = tvb_get_bits8(tvb, ((offset+1+val_len)<<3), 1);
if (t == 0) {
/* UOR-2-ID
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 1 0 | IP-ID |
* +===+===+===+===+===+===+===+===+
* |T=0| M | SN |
* +---+---+---+---+---+---+---+---+
* | X | CRC |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "UOR-2-ID");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "UOR-2-ID packet");
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_ip_id, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
} else {
/* UOR-2-TS
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 1 1 0 | TS |
* +===+===+===+===+===+===+===+===+
* |T=1| M | SN |
* +---+---+---+---+---+---+---+---+
* | X | CRC |
* +---+---+---+---+---+---+---+---+
*/
col_set_str(pinfo->cinfo, COL_INFO, "UOR-2-TS");
pkt_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rohc_packet, &ti, "UOR-2-TS packet");
proto_tree_add_bits_item(pkt_tree, hf_rohc_ts, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
}
offset += 1 + val_len;
proto_tree_add_bits_item(pkt_tree, hf_rohc_t, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_rtp_m, tvb, (offset<<3)+1, 1, ENC_BIG_ENDIAN);
sn = tvb_get_bits8(tvb, (offset<<3)+2, 6);
proto_tree_add_bits_item(pkt_tree, hf_rohc_comp_sn, tvb, (offset<<3)+2, 6, ENC_BIG_ENDIAN);
offset++;
/* Show SN in info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
x = tvb_get_bits8(tvb, (offset<<3), 1);
proto_tree_add_bits_item(pkt_tree, hf_rohc_x, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(pkt_tree, hf_rohc_crc, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
offset++;
}
if (x) {
offset = dissect_rohc_ext_format(tvb, pinfo, pkt_tree, offset, t, rohc_cid_context);
}
proto_item_set_len(ti, offset-start_offset);
return offset;
}
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, guint16 cid, gboolean cid_context){
proto_item *ti;
proto_tree *rohc_feedback_tree;
guint8 opt, opt_len, oct;
rohc_cid_context_t *rohc_cid_context = NULL;
gint key = cid;
guint32 sn;
if (!pinfo->fd->flags.visited){
rohc_cid_context = (rohc_cid_context_t*)g_hash_table_lookup(rohc_cid_hash, GUINT_TO_POINTER(key));
if(rohc_cid_context){
p_add_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0, rohc_cid_context);
}
}else{
rohc_cid_context = (rohc_cid_context_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0);
}
if(!rohc_cid_context){
if (cid_context) {
/* Reuse info coming from private data */
rohc_cid_context = wmem_new(wmem_packet_scope(), rohc_cid_context_t);
/*rohc_cid_context->d_mode;*/
rohc_cid_context->rnd = p_rohc_info->rnd;
rohc_cid_context->udp_checksum_present = p_rohc_info->udp_checksum_present;
rohc_cid_context->profile = p_rohc_info->profile;
rohc_cid_context->mode = p_rohc_info->mode;
rohc_cid_context->rohc_ip_version = p_rohc_info->rohc_ip_version;
rohc_cid_context->large_cid_present = p_rohc_info->large_cid_present;
rohc_cid_context->prev_ir_frame_number = -1;
rohc_cid_context->ir_frame_number = -1;
} else {
/* No context info, not much we can do */
proto_item_append_text(p_rohc_info->last_created_item, " (type %d)", (feedback_data_len==1) ? 1 : 2);
proto_tree_add_expert_format(tree, pinfo, &ei_rohc_profile_not_supported, tvb, offset, feedback_data_len, "profile-specific information [Profile not known]");
return;
}
}
if(feedback_data_len==1){
/* FEEDBACK-1 */
proto_item_append_text(p_rohc_info->last_created_item, " (type 1)");
oct = tvb_get_guint8(tvb, offset);
switch(rohc_cid_context->profile){
case ROHC_PROFILE_UNCOMPRESSED: /* 0 */
ti = proto_tree_add_item(tree, hf_rohc_profile_spec_octet, tvb, offset, 1, ENC_BIG_ENDIAN);
if (oct) {
expert_add_info_format(pinfo, ti, &ei_rohc_profile_spec_octet, "Invalid profile-specific octet value (0x%02X)", oct);
}
break;
case ROHC_PROFILE_RTP: /* 1 */
case ROHC_PROFILE_UDP: /* 2 */
/*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | SN |
* +---+---+---+---+---+---+---+---+
*
*/
proto_tree_add_item(tree, hf_rohc_fb1_sn, tvb, offset, 1, ENC_BIG_ENDIAN);
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", oct);
break;
default:
proto_tree_add_expert(tree, pinfo, &ei_rohc_profile_specific, tvb, offset, feedback_data_len);
break;
}
return;
}
/* FEEDBACK-2 */
proto_item_append_text(p_rohc_info->last_created_item, " (type 2)");
switch(rohc_cid_context->profile){
case ROHC_PROFILE_UNCOMPRESSED: /* 0 */
expert_add_info(pinfo, p_rohc_info->last_created_item, &ei_rohc_feedback_type_2_is_not_applicable_for_uncompressed_profile);
break;
case ROHC_PROFILE_RTP: /* 1 */
case ROHC_PROFILE_UDP: /* 2 */
rohc_feedback_tree = proto_tree_add_subtree_format(tree, tvb, offset, feedback_data_len, ett_rohc_feedback, NULL,
"%s profile-specific information",
(rohc_cid_context->profile == ROHC_PROFILE_RTP) ? "RTP" : "UDP");
/* Set mode at first pass? Do we need a new context for the following frames?
*
*/
rohc_cid_context->mode = (enum rohc_mode)((tvb_get_guint8(tvb,offset) & 0x30)>>4);
proto_tree_add_item(rohc_feedback_tree, hf_rohc_acktype, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(rohc_feedback_tree, hf_rohc_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
sn = tvb_get_ntohs(tvb, offset) & 0x0fff;
proto_tree_add_item(rohc_feedback_tree, hf_rohc_sn, tvb, offset, 2, ENC_BIG_ENDIAN);
offset+=2;
feedback_data_len-=2;
while(feedback_data_len>0){
opt = opt_len = tvb_get_guint8(tvb,offset);
opt = opt >> 4;
opt_len = opt_len &0x0f;
ti = proto_tree_add_item(rohc_feedback_tree, hf_rohc_opt_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(rohc_feedback_tree, hf_rohc_opt_len, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
feedback_data_len--;
switch(opt){
case 1:
/* CRC */
proto_tree_add_item(rohc_feedback_tree, hf_rohc_crc, tvb, offset, 1, ENC_BIG_ENDIAN);
oct = tvb_get_guint8(tvb, offset);
col_append_fstr(pinfo->cinfo, COL_INFO, "CRC=%u ", oct);
break;
case 2:
/* REJECT */
col_append_str(pinfo->cinfo, COL_INFO, "Reject ");
break;
case 3:
/* SN-Not-Valid */
col_append_str(pinfo->cinfo, COL_INFO, "SN-Not-Valid ");
break;
case 4:
/* SN */
proto_tree_add_item(rohc_feedback_tree, hf_rohc_opt_sn, tvb, offset, 1, ENC_BIG_ENDIAN);
sn = (sn << 8) | tvb_get_guint8(tvb, offset);
ti = proto_tree_add_uint(rohc_feedback_tree, hf_rohc_ext_sn, tvb, 0, 0, sn);
PROTO_ITEM_SET_GENERATED(ti);
break;
case 5:
/* Clock */
if (rohc_cid_context->profile == ROHC_PROFILE_RTP) {
proto_tree_add_item(rohc_feedback_tree, hf_rohc_opt_clock, tvb, offset, 1, ENC_BIG_ENDIAN);
oct = tvb_get_guint8(tvb, offset);
col_append_fstr(pinfo->cinfo, COL_INFO, "Clock=%u ", oct);
} else {
expert_add_info(pinfo, ti, &ei_rohc_rohc_opt_clock);
}
break;
case 6:
/* Jitter */
if (rohc_cid_context->profile == ROHC_PROFILE_RTP) {
proto_tree_add_item(rohc_feedback_tree, hf_rohc_opt_jitter, tvb, offset, 1, ENC_BIG_ENDIAN);
oct = tvb_get_guint8(tvb, offset);
col_append_fstr(pinfo->cinfo, COL_INFO, "Jitter=%u ", oct);
}else {
expert_add_info(pinfo, ti, &ei_rohc_opt_jitter);
}
break;
case 7:
/* Loss */
proto_tree_add_item(rohc_feedback_tree, hf_rohc_opt_loss, tvb, offset, 1, ENC_BIG_ENDIAN);
oct = tvb_get_guint8(tvb, offset);
col_append_fstr(pinfo->cinfo, COL_INFO, "Loss=%u ", oct);
break;
default:
proto_tree_add_item(rohc_feedback_tree, hf_rohc_unknown_option_data, tvb, offset, opt_len, ENC_NA);
break;
}
feedback_data_len = feedback_data_len - opt_len;
offset = offset + opt_len;
}
col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
break;
default:
rohc_feedback_tree = proto_tree_add_subtree(tree, tvb, offset, feedback_data_len,
ett_rohc_feedback, NULL, "profile-specific information[Not dissected yet]");
proto_tree_add_item(rohc_feedback_tree, hf_rohc_acktype, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
}
}
const true_false_string rohc_cmp_lst_mask_size_vals = { "15-bit mask", "7-bit mask" };
/* 5.8.6. Compressed list formats */
static int
dissect_compressed_list(int expected_encoding_type _U_, packet_info *pinfo _U_,
proto_tree *tree, tvbuff_t *tvb, int offset)
{
proto_item *list_ti /* , *et_ti */;
proto_item *list_tree;
guint8 first_byte = tvb_get_guint8(tvb, offset);
guint8 ET, GP , PS, CC , bit_mask_size;
int start_offset = offset;
/* Compressed list root */
list_ti = proto_tree_add_item(tree, hf_rohc_compressed_list, tvb, offset, -1, ENC_NA);
list_tree = proto_item_add_subtree(list_ti, ett_rohc_compressed_list);
/* Fixed fields from first byte */
ET = (first_byte & 0xc0) >> 6;
/* et_ti = proto_tree_add_item(list_tree, hf_rohc_compressed_list_et, tvb, offset, 1, ENC_BIG_ENDIAN); */
proto_tree_add_item(list_tree, hf_rohc_compressed_list_et, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_item_append_text(list_ti, " (type=%d - %s)",
ET, val_to_str_const(ET, compressed_list_encoding_type_vals, "Unknown"));
#if 0
if (ET != expected_encoding_type) {
expert_add_info_format(pinfo, et_ti, PI_MALFORMED, PI_ERROR,
"Wrong compressed list encoding type (expected %d, got %d)",
expected_encoding_type, ET);
return offset+1;
}
#endif
GP = (first_byte & 0x20) >> 5;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_gp, tvb, offset, 1, ENC_BIG_ENDIAN);
switch (ET) {
case 0:
/* 5.8.6.1 Encoding Type 0 (generic scheme)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | ET=0 |GP |PS | CC = m |
* +---+---+---+---+---+---+---+---+
* : gen_id : 1 octet, if GP = 1
* +---+---+---+---+---+---+---+---+
* | XI 1, ..., XI m | m octets, or m * 4 bits
* / --- --- --- ---/
* | : Padding : if PS = 0 and m is odd
* +---+---+---+---+---+---+---+---+
* | |
* / item 1, ..., item n / variable
* | |
* +---+---+---+---+---+---+---+---+
*
*/
/* PS = (first_byte & 0x10) >> 4;
* PS: Indicates size of XI fields:
* PS = 0 indicates 4-bit XI fields;
* PS = 1 indicates 8-bit XI fields.
*/
PS = (first_byte & 0x10) >> 4;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_ps, tvb, offset, 1, ENC_BIG_ENDIAN);
/* CC: CSRC counter from original RTP header. */
CC = first_byte & 0x0f;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_cc, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* GP: Indicates presence of gen_id field. */
if (GP) {
proto_tree_add_item(list_tree, hf_rohc_compressed_list_gen_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
}
if(CC!=0){
/* TODO: calculate how many bytes to skip for items */
/*
* XI 1, ..., XI m: m XI items. The format of an XI item is as
* follows:
*
* +---+---+---+---+
* PS = 0: | X | Index |
* +---+---+---+---+
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* PS = 1: | X | Index |
* +---+---+---+---+---+---+---+---+
*
* X = 1 indicates that the item corresponding to the Index
* is sent in the item 0, ..., item n list.
* X = 0 indicates that the item corresponding to the Index is
* not sent.
*/
if(PS){
/* PS = 1 indicates 8-bit XI fields. */
}else{
/* PS = 0 indicates 4-bit XI fields; */
}
}
break;
case 1:
/*
* 5.8.6.2. Encoding Type 1 (insertion only scheme)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | ET=1 |GP |PS | XI 1 |
* +---+---+---+---+---+---+---+---+
* : gen_id : 1 octet, if GP = 1
* +---+---+---+---+---+---+---+---+
* | ref_id |
* +---+---+---+---+---+---+---+---+
* / insertion bit mask / 1-2 octets
* +---+---+---+---+---+---+---+---+
* | XI list | k octets, or (k - 1) * 4 bits
* / --- --- --- ---/
* | : Padding : if PS = 0 and k is even
* +---+---+---+---+---+---+---+---+
* | |
* / item 1, ..., item n / variable
* | |
* +---+---+---+---+---+---+---+---+
*
*/
PS = (first_byte & 0x10) >> 4;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_ps, tvb, offset, 1, ENC_BIG_ENDIAN);
/* XI 1: When PS = 0, the first 4-bit XI item is placed here.
* When PS = 1, the field is set to zero when sending, and
* ignored when receiving.
*/
if(PS==0){
proto_tree_add_item(list_tree, hf_rohc_compressed_list_xi_1, tvb, offset, 1, ENC_BIG_ENDIAN);
}
offset++;
/* GP: Indicates presence of gen_id field. */
if (GP) {
proto_tree_add_item(list_tree, hf_rohc_compressed_list_gen_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
}
proto_tree_add_item(list_tree, hf_rohc_compressed_list_ref_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/*
* insertion bit mask: Bit mask indicating the positions where new
* items are to be inserted. See Insertion Only scheme in
* section 5.8.3. The bit mask can have either of the
* following two formats:
*
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 0 | 7-bit mask | bit 1 is the first bit
* +---+---+---+---+---+---+---+---+
*
* +---+---+---+---+---+---+---+---+
* | 1 | | bit 1 is the first bit
* +---+ 15-bit mask +
* | | bit 7 is the last bit
* +---+---+---+---+---+---+---+---+
*/
bit_mask_size = (tvb_get_guint8(tvb,offset)&0x80)>>7;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_mask_size, tvb, offset, 1, ENC_BIG_ENDIAN);
if(bit_mask_size){
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_ins_bit_mask, tvb, (offset<<3)+1, 15, ENC_BIG_ENDIAN);
offset+=2;
}else{
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_ins_bit_mask, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
offset++;
}
/*
* XI list: XI fields for items to be inserted. When the insertion
* bit mask has k ones, the total number of XI fields is k. When
* PS = 1, all XI fields are in the XI list. When PS = 0, the
* first XI field is in the XI 1 field, and the remaining k - 1
* XI fields are in the XI list.
*
* Padding: Present when PS = 0 and k is even.
*/
/* TODO: */
break;
case 2:
/*
* 5.8.6.3. Encoding Type 2 (removal only scheme)
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | ET=2 |GP |res| Count |
* +---+---+---+---+---+---+---+---+
* : gen_id : 1 octet, if GP = 1
* +---+---+---+---+---+---+---+---+
* | ref_id |
* +---+---+---+---+---+---+---+---+
* / removal bit mask / 1-2 octets
* +---+---+---+---+---+---+---+---+
*
*/
proto_tree_add_item(list_tree, hf_rohc_compressed_list_res, tvb, offset, 1, ENC_BIG_ENDIAN);
/* Count: Number of elements in ref_list. */
proto_tree_add_item(list_tree, hf_rohc_compressed_list_count, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* GP: Indicates presence of gen_id field. */
if (GP) {
proto_tree_add_item(list_tree, hf_rohc_compressed_list_gen_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
}
proto_tree_add_item(list_tree, hf_rohc_compressed_list_ref_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/*
* removal bit mask: Indicates the elements in ref_list to be
* removed in order to obtain the current list. See section
* 5.8.3. The removal bit mask has the same format as the
* insertion bit mask of section 5.8.6.3.
*/
bit_mask_size = (tvb_get_guint8(tvb,offset)&0x80)>>7;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_mask_size, tvb, offset, 1, ENC_BIG_ENDIAN);
if(bit_mask_size){
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_rem_bit_mask, tvb, (offset<<3)+1, 15, ENC_BIG_ENDIAN);
offset+=2;
}else{
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_rem_bit_mask, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
offset++;
}
break;
case 3:
/*
* 5.8.6.4. Encoding Type 3 (remove then insert scheme)
*
* See section 5.8.3 for a description of the Remove then insert
* scheme.
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | ET=3 |GP |PS | XI 1 |
* +---+---+---+---+---+---+---+---+
* : gen_id : 1 octet, if GP = 1
* +---+---+---+---+---+---+---+---+
* | ref_id |
* +---+---+---+---+---+---+---+---+
* / removal bit mask / 1-2 octets
* +---+---+---+---+---+---+---+---+
* / insertion bit mask / 1-2 octets
* +---+---+---+---+---+---+---+---+
* | XI list | k octets, or (k - 1) * 4 bits
* / --- --- --- ---/
* | : Padding : if PS = 0 and k is even
* +---+---+---+---+---+---+---+---+
* | |
* / item 1, ..., item n / variable
* | |
* +---+---+---+---+---+---+---+---+
*
*/
PS = (first_byte & 0x10) >> 4;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_ps, tvb, offset, 1, ENC_BIG_ENDIAN);
/* XI 1: When PS = 0, the first 4-bit XI item is placed here.
* When PS = 1, the field is set to zero when sending, and
* ignored when receiving.
*/
if(PS==0){
proto_tree_add_item(list_tree, hf_rohc_compressed_list_xi_1, tvb, offset, 1, ENC_BIG_ENDIAN);
}
offset++;
/* GP: Indicates presence of gen_id field. */
if (GP) {
proto_tree_add_item(list_tree, hf_rohc_compressed_list_gen_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
}
proto_tree_add_item(list_tree, hf_rohc_compressed_list_ref_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/*
* removal bit mask: Indicates the elements in ref_list to be
* removed in order to obtain the current list. See section
* 5.8.3. The removal bit mask has the same format as the
* insertion bit mask of section 5.8.6.3.
*/
bit_mask_size = (tvb_get_guint8(tvb,offset)&0x80)>>7;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_mask_size, tvb, offset, 1, ENC_BIG_ENDIAN);
if(bit_mask_size){
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_rem_bit_mask, tvb, (offset<<3)+1, 15, ENC_BIG_ENDIAN);
offset+=2;
}else{
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_rem_bit_mask, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
offset++;
}
/*
* insertion bit mask: Bit mask indicating the positions where new
* items are to be inserted. See Insertion Only scheme in
* section 5.8.3. The bit mask can have either of the
* following two formats:
*
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | 0 | 7-bit mask | bit 1 is the first bit
* +---+---+---+---+---+---+---+---+
*
* +---+---+---+---+---+---+---+---+
* | 1 | | bit 1 is the first bit
* +---+ 15-bit mask +
* | | bit 7 is the last bit
* +---+---+---+---+---+---+---+---+
*/
bit_mask_size = (tvb_get_guint8(tvb,offset)&0x80)>>7;
proto_tree_add_item(list_tree, hf_rohc_compressed_list_mask_size, tvb, offset, 1, ENC_BIG_ENDIAN);
if(bit_mask_size){
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_ins_bit_mask, tvb, (offset<<3)+1, 15, ENC_BIG_ENDIAN);
offset+=2;
}else{
proto_tree_add_bits_item(list_tree, hf_rohc_compressed_list_ins_bit_mask, tvb, (offset<<3)+1, 7, ENC_BIG_ENDIAN);
offset++;
}
/* TODO: */
offset++;
break;
}
proto_item_set_len(list_ti, offset-start_offset);
return offset;
}
static int
dissect_rohc_ir_rtp_profile_dynamic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
int offset, guint8 profile, rohc_cid_context_t *rohc_cid_context){
proto_item *item, *root_ti;
proto_tree *sub_tree = NULL, *dynamic_ipv4_tree, *dynamic_udp_tree, *dynamic_rtp_tree;
guint8 oct, rx, /* cc, */ val_len = 0;
int start_offset, tree_start_offset;
guint8 tos, ttl, nbo;
guint16 id;
/*guint8 contributing_csrcs;*/
guint16 sequence_number;
guint32 timestamp;
#if 0
guint8 tis = 0, tss=0;
guint64 ts_stride = 0;
#endif
start_offset = offset;
switch(profile){
case ROHC_PROFILE_UNCOMPRESSED:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_dynamic, &item, "Profile 0x0000 Uncompressed");
break;
case ROHC_PROFILE_RTP:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_dynamic, &item, "Profile 0x0001 RTP Dynamic Chain");
break;
case ROHC_PROFILE_UDP:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_dynamic, &item, "Profile 0x0002 UDP Dynamic Chain");
break;
case ROHC_PROFILE_IP:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_dynamic, &item, "Profile 0x0004 IP Dynamic Chain");
break;
default:
proto_tree_add_expert(tree, pinfo, &ei_rohc_profile_not_supported, tvb, offset, 0);
return -1;
}
/* IP dynamic*/
/* for all profiles except uncompressed */
if ( (profile != ROHC_PROFILE_UNCOMPRESSED) ) {
switch(rohc_cid_context->rohc_ip_version){
case 4:
/* 5.7.7.4. Initialization of IPv4 Header [IPv4, section 3.1].
* Dynamic part:
*/
/* Create dynamic IPv4 subtree */
tree_start_offset = offset;
root_ti = proto_tree_add_item(sub_tree, hf_rohc_dynamic_ipv4, tvb, offset, -1, ENC_NA);
dynamic_ipv4_tree = proto_item_add_subtree(root_ti, ett_rohc_dynamic_ipv4);
/* Type of Service */
tos = tvb_get_guint8(tvb, offset);
proto_tree_add_item(dynamic_ipv4_tree, hf_rohc_rtp_tos, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* Time to Live */
ttl = tvb_get_guint8(tvb, offset);
proto_tree_add_item(dynamic_ipv4_tree, hf_rohc_rtp_ttl, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* Identification */
id = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(dynamic_ipv4_tree, hf_rohc_rtp_id, tvb, offset, 2, ENC_BIG_ENDIAN);
offset+=2;
/* +---+---+---+---+---+---+---+---+
* | DF|RND|NBO| 0 |
* +---+---+---+---+---+---+---+---+
*/
rohc_cid_context->rnd = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
nbo = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
proto_tree_add_item(dynamic_ipv4_tree, hf_rohc_rtp_df, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_ipv4_tree, hf_rohc_rtp_rnd, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_ipv4_tree, hf_rohc_rtp_nbo, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_bits_item(dynamic_ipv4_tree, hf_rohc_spare_bits, tvb, (offset<<3)+3, 5, ENC_BIG_ENDIAN);
offset++;
/* Set proper length for subtree */
proto_item_set_len(root_ti, offset-tree_start_offset);
/* +---+---+---+---+---+---+---+---+
* / Generic extension header list / variable length
* +---+---+---+---+---+---+---+---+
* Generic extension header list: Encoded according to section
* 5.8.6.1, with all header items present in uncompressed form.
*/
offset = dissect_compressed_list(0, pinfo, dynamic_ipv4_tree, tvb, offset);
/* Add summary to ipv4 root item */
proto_item_append_text(root_ti, " (ToS=%u, TTL=%u, ID=%u, RND=%u, NBO=%u)",
tos, ttl, id, rohc_cid_context->rnd, nbo);
break;
case 6:
/* Dynamic part:
* +---+---+---+---+---+---+---+---+
* | Traffic Class | 1 octet
* +---+---+---+---+---+---+---+---+
* | Hop Limit | 1 octet
* +---+---+---+---+---+---+---+---+
* / Generic extension header list / variable length
* +---+---+---+---+---+---+---+---+
*/
proto_tree_add_item(sub_tree, hf_rohc_ipv6_tc, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(sub_tree, hf_rohc_ipv6_hop_limit, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* XXX TODO: use the IPv6 dissector to dissect Generic extension header list ?*/
proto_tree_add_expert(sub_tree, pinfo, &ei_rohc_not_dissected_yet, tvb, offset, -1);
return -1;
default:
break;
}
}
/* UDP dynamic*/
if ( (profile == ROHC_PROFILE_UDP) ||
(profile == ROHC_PROFILE_RTP) ) {
/* 5.7.7.5. Initialization of UDP Header
* Dynamic part:
*
* +---+---+---+---+---+---+---+---+
* / Checksum / 2 octets
* +---+---+---+---+---+---+---+---+
*/
/* Create dynamic UDP subtree */
root_ti = proto_tree_add_item(sub_tree, hf_rohc_dynamic_udp, tvb, offset, 2, ENC_NA);
dynamic_udp_tree = proto_item_add_subtree(root_ti, ett_rohc_dynamic_udp);
id = tvb_get_ntohs(tvb, offset);
rohc_cid_context->udp_checksum_present = id ? TRUE : FALSE;
proto_tree_add_checksum(dynamic_udp_tree, tvb, offset, hf_rohc_dynamic_udp_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
offset +=2;
proto_item_set_len(item, offset - start_offset);
}
/* RTP dynamic*/
if (profile == ROHC_PROFILE_RTP) {
/* 5.7.7.6. Initialization of RTP Header
* Dynamic part:
* Checksum
* P, X, CC, PT, M, sequence number, timestamp, timestamp stride,
* CSRC identifiers.
*
* 0 1 2 3 4 5 6 7
* +---+---+---+---+---+---+---+---+
* | V=2 | P | RX| CC | (RX is NOT the RTP X bit)
* +---+---+---+---+---+---+---+---+
* | M | PT |
* +---+---+---+---+---+---+---+---+
* / RTP Sequence Number / 2 octets
* +---+---+---+---+---+---+---+---+
* / RTP Timestamp (absolute) / 4 octets
* +---+---+---+---+---+---+---+---+
* / Generic CSRC list / variable length
* +---+---+---+---+---+---+---+---+
* : Reserved | X | Mode |TIS|TSS: if RX = 1
* +---+---+---+---+---+---+---+---+
* : TS_Stride : 1-4 octets, if TSS = 1
* +---+---+---+---+---+---+---+---+
* : Time_Stride : 1-4 octets, if TIS = 1
* +---+---+---+---+---+---+---+---+
*/
/* Create dynamic RTP subtree */
root_ti = proto_tree_add_item(sub_tree, hf_rohc_dynamic_rtp, tvb, offset, -1, ENC_NA);
dynamic_rtp_tree = proto_item_add_subtree(root_ti, ett_rohc_dynamic_rtp);
tree_start_offset = offset;
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_v, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_p, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_rx, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_cc, tvb, offset, 1, ENC_BIG_ENDIAN);
oct = tvb_get_guint8(tvb,offset);
/* cc = oct & 0x0f; */
rx = (oct >> 4)& 0x01;
offset++;
proto_tree_add_bits_item(dynamic_rtp_tree, hf_rohc_rtp_m, tvb, (offset<<3), 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_pt, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
sequence_number = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_sn, tvb, offset, 2, ENC_BIG_ENDIAN);
offset+=2;
timestamp = tvb_get_ntohl(tvb, offset);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_timestamp, tvb, offset, 4, ENC_BIG_ENDIAN);
offset+=4;
/* RFC 4815
* This field is always at least one octet in size, even if the
* list is empty (as opposed to the CSRC list in the uncompressed RTP
* header, which is not present when the RTP CC field is set to 0).
* :
* Generic CSRC list: CSRC list encoded according to section
* 5.8.6.1, with all CSRC items present.
* FORMAL ADDITION TO RFC 3095:
*
* "The first octet in the dynamic part of the RTP header contains a
* CC field, as defined in Section 5.7.7.6. A second occurrence
* appears in the 'Generic CSRC list', which is also in the dynamic
* part of the RTP header, where Encoding Type 0 is used according
* to the format defined in RFC 3095-5.8.6.1.
*
* The compressor MUST set both occurrences of the CC field to the
* same value.
*
* The decompressor MUST use the value of the CC field from the
* Encoding Type 0 within the Generic CRSC list, and it MUST thus
* ignore the first occurrence of the CC field."
*/
offset = dissect_compressed_list(0, pinfo, dynamic_rtp_tree, tvb, offset);
/* : Reserved | X | Mode |TIS|TSS: if RX = 1 */
if(rx==0){
return offset;
}
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_x, tvb, offset, 1, ENC_BIG_ENDIAN);
rohc_cid_context->mode = (enum rohc_mode)((tvb_get_guint8(tvb,offset) & 0x0c)>>2);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_tis, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(dynamic_rtp_tree, hf_rohc_rtp_tss, tvb, offset, 1, ENC_BIG_ENDIAN);
oct = tvb_get_guint8(tvb,offset);
offset++;
/* TS_Stride : 1-4 octets, if TSS = 1 */
if((oct&0x01)== 1){
/* TS_Stride encoded as
* 4.5.6. Self-describing variable-length values
*/
get_self_describing_var_len_val(tvb, dynamic_rtp_tree, offset, hf_rohc_rtp_ts_stride, &val_len);
offset = offset + val_len;
}
/* Time_Stride : 1-4 octets, if TIS = 1 */
if((oct&0x02)== 2){
/* Time_Stride encoded as
* 4.5.6. Self-describing variable-length values
*/
get_self_describing_var_len_val(tvb, dynamic_rtp_tree, offset, hf_rohc_rtp_time_stride, &val_len);
offset = offset + val_len;
}
/* Set proper length for subtree */
proto_item_set_len(root_ti, offset-tree_start_offset);
/* Add summary to root item */
proto_item_append_text(root_ti, " (seqnum = %u, timestamp = %u)",
sequence_number, timestamp);
proto_item_set_len(item, offset - start_offset);
}
return offset;
}
static int
dissect_rohc_ir_rtp_udp_ip_profile_static(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo _U_, int offset, gboolean d, guint8 profile, rohc_cid_context_t *rohc_cid_context){
proto_item *item, *ipv4_item, *udp_item, *rtp_item, *ver_item;
proto_tree *sub_tree = NULL, *static_ipv4_tree, *static_udp_tree, *static_rtp_tree;
guint8 version, protocol;
int start_offset, tree_start_offset;
start_offset = offset;
switch(profile){
case ROHC_PROFILE_UNCOMPRESSED:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_static, &item, "Profile 0x0000 Uncompressed");
break;
case ROHC_PROFILE_RTP:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_static, &item, "Profile 0x0001 RTP Static Chain");
break;
case ROHC_PROFILE_UDP:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_static, &item, "Profile 0x0002 UDP Static Chain");
break;
case ROHC_PROFILE_IP:
sub_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_rohc_rtp_static, &item, "Profile 0x0004 IP Static Chain");
break;
default:
proto_tree_add_expert(tree, pinfo, &ei_rohc_profile_not_supported, tvb, offset, 0);
return -1;
}
/* IP static*/
/* for all profiles except uncompressed */
if (profile != ROHC_PROFILE_UNCOMPRESSED) {
version = tvb_get_guint8(tvb,offset)>>4;
ver_item = proto_tree_add_item(sub_tree, hf_rohc_ip_version, tvb, offset, 1, ENC_BIG_ENDIAN);
rohc_cid_context->rohc_ip_version = version;
switch(version) {
case 4:
{
/* 5.7.7.4. Initialization of IPv4 Header [IPv4, section 3.1].
* Static part:
*/
guint32 source, dest;
offset++;
tree_start_offset = offset;
/* Create static IPv4 subtree */
ipv4_item = proto_tree_add_item(sub_tree, hf_rohc_static_ipv4, tvb, offset, -1, ENC_NA);
static_ipv4_tree = proto_item_add_subtree(ipv4_item, ett_rohc_static_ipv4);
/* Protocol */
protocol = tvb_get_guint8(tvb, offset);
proto_tree_add_item(static_ipv4_tree, hf_rohc_ip_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* Source Address */
source = tvb_get_ipv4(tvb, offset);
proto_tree_add_item(static_ipv4_tree, hf_rohc_ipv4_src, tvb, offset, 4, ENC_BIG_ENDIAN);
offset+=4;
/* Destination Address */
dest = tvb_get_ipv4(tvb, offset);
proto_tree_add_item(static_ipv4_tree, hf_rohc_ipv4_dst, tvb, offset, 4, ENC_BIG_ENDIAN);
offset+=4;
/* Set proper length for subtree */
proto_item_set_len(ipv4_item, offset-tree_start_offset);
/* Add summary to root item */
proto_item_append_text(ipv4_item, " (prot=%s: %s -> %s)",
val_to_str_ext_const(protocol, &ipproto_val_ext, "Unknown"),
get_hostname(source),
get_hostname(dest));
}
break;
case 6:
{
/* 5.7.7.3. Initialization of IPv6 Header [IPv6]*/
/* Static part:
*
* +---+---+---+---+---+---+---+---+
* | Version = 6 |Flow Label(msb)| 1 octet
* +---+---+---+---+---+---+---+---+
* / Flow Label (lsb) / 2 octets
* +---+---+---+---+---+---+---+---+
* | Next Header | 1 octet
* +---+---+---+---+---+---+---+---+
* / Source Address / 16 octets
* +---+---+---+---+---+---+---+---+
* / Destination Address / 16 octets
* +---+---+---+---+---+---+---+---+
*/
/* Flow Label */
proto_tree_add_item(sub_tree, hf_rohc_ipv6_flow, tvb, offset, 3, ENC_BIG_ENDIAN);
offset+=3;
/* Next Header */
protocol = tvb_get_guint8(tvb, offset);
proto_tree_add_item(sub_tree, hf_rohc_ipv6_nxt_hdr, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* Source Address */
proto_tree_add_item(sub_tree, hf_rohc_ipv6_src, tvb, offset, 16, ENC_NA);
offset+=16;
/* Destination Address */
proto_tree_add_item(sub_tree, hf_rohc_ipv6_dst, tvb, offset, 16, ENC_NA);
offset+=16;
break;
}
default:
expert_add_info(pinfo, ver_item, &ei_rohc_ip_version);
return -1;
}
} else {
protocol = 0; /* Something other than UDP (which is checked for below) */
}
if (protocol == IP_PROTO_UDP) {
/* UDP static */
if ((profile == ROHC_PROFILE_RTP) ||
(profile == ROHC_PROFILE_UDP)) {
/* 5.7.7.5. Initialization of UDP Header [RFC-768].
* Static part
*/
guint16 source_port, dest_port, ssrc;
/* Create static UDP subtree */
tree_start_offset = offset;
udp_item = proto_tree_add_item(sub_tree, hf_rohc_static_udp, tvb, offset, -1, ENC_NA);
static_udp_tree = proto_item_add_subtree(udp_item, ett_rohc_static_udp);
/* Source Port */
source_port = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(static_udp_tree, hf_rohc_udp_src_port, tvb, offset, 2, ENC_BIG_ENDIAN);
offset+=2;
/* Destination Port */
dest_port = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(static_udp_tree, hf_rohc_udp_dst_port, tvb, offset, 2, ENC_BIG_ENDIAN);
offset+=2;
/* Set proper length for subtree */
proto_item_set_len(udp_item, offset-tree_start_offset);
/* Add summary to root item */
proto_item_append_text(udp_item, " (%u -> %u)", source_port, dest_port);
if (profile == ROHC_PROFILE_UDP) {
proto_item_set_len(item, offset - start_offset);
if (d==TRUE) {
offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, pinfo, tree, offset, profile, rohc_cid_context);
}
return offset;
}
/* RTP static */
/* 5.7.7.6. Initialization of RTP Header [RTP]. */
/* Create static RTP subtree */
rtp_item = proto_tree_add_item(sub_tree, hf_rohc_static_rtp, tvb, offset, 4, ENC_NA);
static_rtp_tree = proto_item_add_subtree(rtp_item, ett_rohc_static_rtp);
/* SSRC */
ssrc = tvb_get_ntohl(tvb, offset);
proto_tree_add_item(static_rtp_tree, hf_rohc_rtp_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
/* Add summary to root item */
proto_item_append_text(rtp_item, " (SSRC=%u)", ssrc);
proto_item_set_len(item, offset - start_offset);
/* D: D = 1 indicates that the dynamic chain is present. */
if (d==TRUE) {
offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, pinfo, tree, offset, profile, rohc_cid_context);
}
}
} else if (profile == ROHC_PROFILE_IP) {
proto_item_set_len(item, offset - start_offset);
if (d==TRUE) {
offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, pinfo, tree, offset, profile, rohc_cid_context);
}
return offset;
} else {
proto_tree_add_expert(sub_tree, pinfo, &ei_rohc_not_dissected_yet, tvb, offset, -1);
}
return offset;
}
static int
dissect_rohc_ir_packet(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo,
int offset, guint16 cid, gboolean is_add_cid, rohc_info *p_rohc_info)
{
proto_item *ir_item, *item;
proto_tree *ir_tree;
int ir_item_start;
int x_bit_offset;
gboolean d = FALSE;
guint8 oct, profile, val_len = 0;
gint16 feedback_data_len = 0;
tvbuff_t *next_tvb;
rohc_cid_context_t *rohc_cid_context = NULL;
/* 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
| |
- - - - - - - - - - - - - - - -
*/
oct = tvb_get_guint8(tvb,offset);
if((p_rohc_info->large_cid_present == FALSE) && (is_add_cid == FALSE)){
item = proto_tree_add_uint(tree, hf_rohc_small_cid, tvb, 0, 0, cid);
PROTO_ITEM_SET_GENERATED(item);
}
ir_item = proto_tree_add_item(tree, hf_rohc_ir_packet, tvb, offset, 1, ENC_BIG_ENDIAN);
ir_tree = proto_item_add_subtree(ir_item, ett_rohc_ir);
ir_item_start = offset;
d = oct & 0x01;
x_bit_offset = offset;
offset++;
if(p_rohc_info->large_cid_present == TRUE){
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, ir_tree, offset, hf_rohc_large_cid, &val_len);
offset = offset + val_len;
}
/* Read profile */
profile = tvb_get_guint8(tvb,offset);
if(profile==ROHC_PROFILE_RTP){
proto_tree_add_item(ir_tree, hf_rohc_d_bit, tvb, x_bit_offset, 1, ENC_BIG_ENDIAN);
}
proto_tree_add_item(ir_tree, hf_rohc_profile, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(ir_tree, hf_rohc_crc, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* See if we have an entry for this CID
* Update it if we do otherwise create it
* and fill in the info.
*/
if (!pinfo->fd->flags.visited){
gint key = cid;
rohc_cid_context = (rohc_cid_context_t*)g_hash_table_lookup(rohc_cid_hash, GUINT_TO_POINTER(key));
if (rohc_cid_context != NULL){
/* This is not the first IR packet seen*/
gint tmp_prev_ir_frame_number = rohc_cid_context->ir_frame_number;
gint tmp_prev_rohc_ip_version = rohc_cid_context->rohc_ip_version;
gint tmp_prev_mode = rohc_cid_context->mode;
gboolean tmp_prev_rnd = rohc_cid_context->rnd;
gboolean tmp_prev_udp_checksum_present = rohc_cid_context->udp_checksum_present;
/*g_warning("IR pkt found CID %u",cid);*/
rohc_cid_context = wmem_new(wmem_file_scope(), rohc_cid_context_t);
rohc_cid_context->profile = profile;
rohc_cid_context->prev_ir_frame_number = tmp_prev_ir_frame_number;
rohc_cid_context->ir_frame_number = pinfo->num;
rohc_cid_context->rohc_ip_version = tmp_prev_rohc_ip_version;
rohc_cid_context->mode = (enum rohc_mode)tmp_prev_mode;
rohc_cid_context->rnd = tmp_prev_rnd;
rohc_cid_context->udp_checksum_present = tmp_prev_udp_checksum_present;
rohc_cid_context->large_cid_present = p_rohc_info->large_cid_present;
g_hash_table_replace(rohc_cid_hash, GUINT_TO_POINTER(key), rohc_cid_context);
p_add_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0, rohc_cid_context);
}else{
rohc_cid_context = wmem_new(wmem_file_scope(), rohc_cid_context_t);
rohc_cid_context->large_cid_present = p_rohc_info->large_cid_present;
/*rohc_cid_context->mode mode;*/
/*rohc_cid_context->d_mode;*/
rohc_cid_context->rnd = FALSE;
rohc_cid_context->udp_checksum_present = FALSE;
rohc_cid_context->profile = profile;
rohc_cid_context->prev_ir_frame_number = -1;
rohc_cid_context->ir_frame_number = pinfo->num;
rohc_cid_context->rohc_ip_version = p_rohc_info->rohc_ip_version;
rohc_cid_context->mode = p_rohc_info->mode;
/*g_warning("IR pkt New CID %u",cid);*/
g_hash_table_insert(rohc_cid_hash, GUINT_TO_POINTER(key), rohc_cid_context);
p_add_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0, rohc_cid_context);
}
}else{
/* get the stored data */
rohc_cid_context = (rohc_cid_context_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0);
}
switch(profile){
case ROHC_PROFILE_UNCOMPRESSED:
if (tvb_reported_length_remaining(tvb, offset) > 0) {
oct = tvb_get_guint8(tvb, offset);
if ( (oct&0xf0) == 0x60 ) {
next_tvb = tvb_new_subset_remaining(tvb, offset);
call_dissector(ipv6_handle, next_tvb, pinfo, tree);
offset += tvb_captured_length_remaining(tvb, offset);
}
else if ( (oct&0xf0) == 0x40 ) {
next_tvb = tvb_new_subset_remaining(tvb, offset);
call_dissector(ip_handle, next_tvb, pinfo, tree);
offset += tvb_captured_length_remaining(tvb, offset);
}
col_prepend_fstr(pinfo->cinfo, COL_PROTOCOL, "ROHC <");
col_append_str(pinfo->cinfo, COL_PROTOCOL, ">");
}
break;
case ROHC_PROFILE_RTP:
case ROHC_PROFILE_UDP:
case ROHC_PROFILE_IP:
offset = dissect_rohc_ir_rtp_udp_ip_profile_static(tvb, ir_tree, pinfo, offset, d, profile, rohc_cid_context);
break;
default:
proto_tree_add_expert(ir_tree, pinfo, &ei_rohc_profile_specific, tvb, offset, feedback_data_len);
offset = -1;
break;
}
if (offset != -1) {
/* Set length of IR header */
proto_item_set_len(ir_item, offset-ir_item_start);
}
return offset;
}
static int
dissect_rohc_ir_dyn_packet(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo,
int offset, guint16 cid, gboolean is_add_cid, rohc_info *p_rohc_info)
{
proto_item *ir_item, *item;
proto_tree *ir_tree;
gint ir_item_start;
guint8 profile, val_len = 0;
gint16 feedback_data_len = 0;
rohc_cid_context_t *rohc_cid_context;
if((p_rohc_info->large_cid_present == FALSE) && (is_add_cid == FALSE)){
item = proto_tree_add_uint(tree, hf_rohc_small_cid, tvb, 0, 0, cid);
PROTO_ITEM_SET_GENERATED(item);
}
ir_item = proto_tree_add_item(tree, hf_rohc_ir_dyn_packet, tvb, offset, 1, ENC_BIG_ENDIAN);
ir_tree = proto_item_add_subtree(ir_item, ett_rohc_ir_dyn);
ir_item_start = offset;
offset++;
if(p_rohc_info->large_cid_present == TRUE){
/* Handle Large CID:s here */
get_self_describing_var_len_val(tvb, ir_tree, offset, hf_rohc_large_cid, &val_len);
offset = offset + val_len;
}
profile = tvb_get_guint8(tvb,offset);
proto_tree_add_item(ir_tree, hf_rohc_profile, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* See if we have an entry for this CID
* Update it if we do otherwise create it
* and fill in the info.
*/
if (!pinfo->fd->flags.visited){
gint key = cid;
rohc_cid_context = (rohc_cid_context_t*)g_hash_table_lookup(rohc_cid_hash, GUINT_TO_POINTER(key));
if (rohc_cid_context){
/* This is not the first IR packet seen*/
gint tmp_prev_ir_frame_number = rohc_cid_context->ir_frame_number;
gint tmp_prev_rohc_ip_version = rohc_cid_context->rohc_ip_version;
gint tmp_prev_mode = rohc_cid_context->mode;
gboolean tmp_prev_rnd = rohc_cid_context->rnd;
gboolean tmp_prev_udp_checksum_present = rohc_cid_context->udp_checksum_present;
/*g_warning("IR pkt found CID %u",cid);*/
rohc_cid_context = wmem_new(wmem_file_scope(), rohc_cid_context_t);
rohc_cid_context->profile = profile;
rohc_cid_context->prev_ir_frame_number = tmp_prev_ir_frame_number;
rohc_cid_context->ir_frame_number = pinfo->num;
rohc_cid_context->rohc_ip_version = tmp_prev_rohc_ip_version;
rohc_cid_context->mode = (enum rohc_mode)tmp_prev_mode;
rohc_cid_context->rnd = tmp_prev_rnd;
rohc_cid_context->udp_checksum_present = tmp_prev_udp_checksum_present;
rohc_cid_context->large_cid_present = p_rohc_info->large_cid_present;
g_hash_table_replace(rohc_cid_hash, GUINT_TO_POINTER(key), rohc_cid_context);
p_add_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0, rohc_cid_context);
}else{
rohc_cid_context = wmem_new(wmem_file_scope(), rohc_cid_context_t);
/*rohc_cid_context->rohc_ip_version;*/
rohc_cid_context->large_cid_present = p_rohc_info->large_cid_present;
/*rohc_cid_context->mode mode;*/
/*rohc_cid_context->d_mode;*/
rohc_cid_context->rnd = FALSE;
rohc_cid_context->udp_checksum_present = FALSE;
rohc_cid_context->profile = profile;
rohc_cid_context->prev_ir_frame_number = -1;
rohc_cid_context->ir_frame_number = pinfo->num;
rohc_cid_context->mode = p_rohc_info->mode;
/*g_warning("IR pkt New CID %u",cid);*/
g_hash_table_insert(rohc_cid_hash, GUINT_TO_POINTER(key), rohc_cid_context);
p_add_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0, rohc_cid_context);
}
}else{
/* get the stored data */
rohc_cid_context = (rohc_cid_context_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0);
}
proto_tree_add_item(ir_tree, hf_rohc_crc, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
switch(profile){
case ROHC_PROFILE_RTP:
offset = dissect_rohc_ir_rtp_profile_dynamic(tvb, pinfo, ir_tree, offset, profile, rohc_cid_context);
break;
default:
proto_tree_add_expert(ir_tree, pinfo, &ei_rohc_profile_specific, tvb, offset, feedback_data_len);
break;
}
/* Set length of IR-DYN header */
if (offset != -1) {
proto_item_set_len(ir_item, offset-ir_item_start);
}
return offset;
}
static int
dissect_rohc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
proto_item *ti, *item, *conf_item;
proto_tree *rohc_tree, *sub_tree = NULL, *conf_tree;
int offset = 0, length;
guint8 oct, code, size, val_len = 0;
gint16 feedback_data_len = 0, cid = 0;
gboolean is_add_cid = FALSE;
rohc_info *p_rohc_info = NULL;
rohc_info g_rohc_info;
tvbuff_t *next_tvb=NULL, *payload_tvb;
rohc_cid_context_t *rohc_cid_context = NULL;
if(data == NULL){
g_rohc_info.rohc_compression = FALSE;
g_rohc_info.rohc_ip_version = g_version;
g_rohc_info.cid_inclusion_info = FALSE;
g_rohc_info.large_cid_present = FALSE;
g_rohc_info.mode = RELIABLE_BIDIRECTIONAL;
g_rohc_info.rnd = FALSE;
g_rohc_info.udp_checksum_present = FALSE;
g_rohc_info.profile = g_profile;
g_rohc_info.last_created_item = NULL;
p_rohc_info = &g_rohc_info;
}else{
p_rohc_info = (rohc_info *)data;
memset(&g_rohc_info, 0, sizeof(rohc_info));
}
length = tvb_reported_length(tvb);
/* If this is ROHC ethertype clear col */
if ( pinfo->src.type == AT_ETHER ){
col_set_str(pinfo->cinfo, COL_INFO, "ROHC");
col_clear(pinfo->cinfo, COL_INFO);
}else{
col_append_str(pinfo->cinfo, COL_PROTOCOL, "|ROHC");
/* Append a space if we add stuff to existing col info */
col_append_str(pinfo->cinfo, COL_INFO, " ");
}
ti = proto_tree_add_item(tree, proto_rohc, tvb, 0, -1, ENC_NA);
rohc_tree = proto_item_add_subtree(ti, ett_rohc);
/* 1) If the first octet is a Padding Octet (11100000),
* strip away all initial Padding Octets and goto next step.
*/
/* Put configuration data into the tree */
conf_tree = proto_tree_add_subtree_format(rohc_tree, tvb, offset, 0, ett_rohc_conf, &item,
"Global Configuration: (%s)", p_rohc_info->large_cid_present ? "Large CID" : "Small CID");
PROTO_ITEM_SET_GENERATED(item);
rohc_cid_context = (rohc_cid_context_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0);
if(rohc_cid_context){
/* Do we have info from an IR frame? */
if(rohc_cid_context->ir_frame_number>0){
conf_item = proto_tree_add_item(conf_tree, hf_rohc_configured_by_ir_packet, tvb, offset, 0, ENC_NA);
PROTO_ITEM_SET_GENERATED(conf_item);
conf_item = proto_tree_add_uint(conf_tree, hf_rohc_ir_pkt_frame, tvb, 0, 0, rohc_cid_context->ir_frame_number);
PROTO_ITEM_SET_GENERATED(conf_item);
if(rohc_cid_context->prev_ir_frame_number>0){
conf_item = proto_tree_add_uint(conf_tree, hf_rohc_ir_previous_frame, tvb, 0, 0, rohc_cid_context->prev_ir_frame_number);
PROTO_ITEM_SET_GENERATED(conf_item);
}
conf_item = proto_tree_add_uint(conf_tree, hf_rohc_ir_profile, tvb, offset, 0, rohc_cid_context->profile);
PROTO_ITEM_SET_GENERATED(conf_item);
conf_item = proto_tree_add_uint(conf_tree, hf_rohc_ir_ip_version, tvb, offset, 0, rohc_cid_context->rohc_ip_version);
PROTO_ITEM_SET_GENERATED(conf_item);
if(rohc_cid_context->mode == 0){
conf_item = proto_tree_add_uint_format_value(conf_tree, hf_rohc_ir_mode, tvb, offset, 0, 0, "not known");
PROTO_ITEM_SET_GENERATED(conf_item);
}else{
conf_item = proto_tree_add_uint(conf_tree, hf_rohc_ir_mode, tvb, offset, 0, rohc_cid_context->mode);
PROTO_ITEM_SET_GENERATED(conf_item);
}
}else{
conf_item = proto_tree_add_item(conf_tree, hf_rohc_no_configuration_info, tvb, offset, 0, ENC_NA);
PROTO_ITEM_SET_GENERATED(conf_item);
}
}
start_over:
cid = 0;
oct = tvb_get_guint8(tvb,offset);
if(oct== 0xe0){
while(oct == 0xe0){
offset++;
oct = tvb_get_guint8(tvb,offset);
}
proto_tree_add_item(rohc_tree, hf_rohc_padding, tvb, 0, offset, ENC_NA);
}
/* 2) If the first remaining octet starts with 1110, it is an Add-CID octet:
* remember the Add-CID octet; remove the octet.
*/
if((oct&0xf0) == 0xe0){
is_add_cid = TRUE;
cid = oct & 0x0f;
proto_tree_add_item(rohc_tree, hf_rohc_add_cid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_uint(rohc_tree, hf_rohc_small_cid, tvb, offset, 1, cid);
offset++;
oct = tvb_get_guint8(tvb,offset);
}
/* feedback ?
* Feedback (begins with 11110)
*/
if((oct&0xf8) == 0xf0){
/* 3) If the first remaining octet starts with 11110, and an Add-CID
* octet was found in step 2), an error has occurred;
* the header MUST be discarded without further action.
*/
int feedback_start = offset;
if(is_add_cid){
p_rohc_info->last_created_item = proto_tree_add_item(rohc_tree, hf_rohc_feedback, tvb, offset, 1, ENC_BIG_ENDIAN);
col_append_str(pinfo->cinfo, COL_INFO, "Error packet");
proto_tree_add_item(rohc_tree, hf_rohc_error_packet, tvb, offset, -1, ENC_NA);
return tvb_captured_length(tvb);
}else{
col_append_str(pinfo->cinfo, COL_INFO, "Feedback ");
/* 4) If the first remaining octet starts with 11110, and an Add-CID
* octet was not found in step 2), this is feedback:
* find the size of the feedback data, call it s;
* remove the feedback type octet;
* remove the Size octet if Code is 0;
* send feedback data of length s to the same-side associated
* compressor;
* if packet exhausted, stop; otherwise goto 2).
*/
p_rohc_info->last_created_item = proto_tree_add_item(rohc_tree, hf_rohc_feedback, tvb, offset, 1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(p_rohc_info->last_created_item, ett_rohc_fb);
proto_tree_add_item(sub_tree, hf_rohc_code, tvb, offset, 1, ENC_BIG_ENDIAN);
code = oct&0x7;
offset++;
if(code==0){
size = tvb_get_guint8(tvb,offset);
proto_tree_add_item(sub_tree, hf_rohc_size, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
}else{
size = code;
}
feedback_data_len = size;
if(p_rohc_info->large_cid_present == FALSE){
/* Check for Add-CID octet */
oct = tvb_get_guint8(tvb,offset);
if((oct&0xf0) == 0xe0){
cid = oct & 0x0f;
proto_tree_add_item(sub_tree, hf_rohc_add_cid, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_uint(sub_tree, hf_rohc_small_cid, tvb, offset, 1, cid);
offset++;
feedback_data_len--;
}else{
item = proto_tree_add_uint(sub_tree, hf_rohc_small_cid, tvb, 0, 0, cid);
PROTO_ITEM_SET_GENERATED(item);
}
}else{
/* Read Large CID here */
get_self_describing_var_len_val(tvb, sub_tree, offset, hf_rohc_large_cid, &val_len);
/* feedback_data_len - "length of large CID" */
feedback_data_len = feedback_data_len - val_len;
offset += val_len;
}
/* Dissect feedback */
dissect_rohc_feedback_data(tvb, sub_tree, pinfo, offset, feedback_data_len, p_rohc_info, cid, p_rohc_info != &g_rohc_info);
offset = offset + size;
if(offset<length)
goto start_over;
proto_item_set_len(p_rohc_info->last_created_item, offset-feedback_start);
return tvb_captured_length(tvb);
}
}/*feedback */
/* 5) If the first remaining octet starts with 1111111, this is a segment:
*
*/
if((oct&0xfe) == 0xfe){
col_append_str(pinfo->cinfo, COL_INFO, "Segment");
if((p_rohc_info->large_cid_present == FALSE) && (is_add_cid == FALSE)){
item = proto_tree_add_uint(rohc_tree, hf_rohc_small_cid, tvb, 0, 0, cid);
PROTO_ITEM_SET_GENERATED(item);
}
proto_tree_add_expert(rohc_tree, pinfo, &ei_rohc_desegmentation_not_implemented, tvb, offset, -1);
return tvb_captured_length(tvb);
}
/* 6) Here, it is known that the rest is forward information (unless the
* header is damaged).
*/
if((oct&0xfe) == 0xfc){
col_append_str(pinfo->cinfo, COL_INFO, "IR packet");
offset = dissect_rohc_ir_packet(tvb, rohc_tree, pinfo, offset, cid, is_add_cid, p_rohc_info);
if(offset == -1){
/* Could not parse header */
return tvb_captured_length(tvb);
}
payload_tvb = tvb_new_subset_remaining(tvb, offset);
call_data_dissector(payload_tvb, pinfo, rohc_tree);
return tvb_captured_length(tvb);
}
if((oct&0xff) == 0xf8){
col_append_str(pinfo->cinfo, COL_INFO, "IR-DYN packet");
offset = dissect_rohc_ir_dyn_packet(tvb, rohc_tree, pinfo, offset, cid, is_add_cid, p_rohc_info);
if(offset == -1){
/* Could not parse header */
return tvb_captured_length(tvb);
}
payload_tvb = tvb_new_subset_remaining(tvb, offset);
call_data_dissector(payload_tvb, pinfo, rohc_tree);
return tvb_captured_length(tvb);
}
if (!pinfo->fd->flags.visited){
gint key = cid;
/*g_warning("Lookup CID %u",cid);*/
rohc_cid_context = (rohc_cid_context_t*)g_hash_table_lookup(rohc_cid_hash, GUINT_TO_POINTER(key));
if(rohc_cid_context){
/*g_warning("Found CID %u",cid);*/
}else{
rohc_cid_context = wmem_new(wmem_file_scope(), rohc_cid_context_t);
/*rohc_cid_context->d_mode;*/
rohc_cid_context->rnd = p_rohc_info->rnd;
rohc_cid_context->udp_checksum_present = p_rohc_info->udp_checksum_present;
rohc_cid_context->profile = p_rohc_info->profile;
rohc_cid_context->mode = p_rohc_info->mode;
rohc_cid_context->rohc_ip_version = p_rohc_info->rohc_ip_version;
rohc_cid_context->large_cid_present = p_rohc_info->large_cid_present;
rohc_cid_context->prev_ir_frame_number = -1;
rohc_cid_context->ir_frame_number = -1;
/*g_warning("Store dummy data %u",cid);*/
}
p_add_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0, rohc_cid_context);
} else {
rohc_cid_context = (rohc_cid_context_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_rohc, 0);
}
/* Call IP for uncompressed*/
DISSECTOR_ASSERT(rohc_cid_context);
if (rohc_cid_context->profile==ROHC_PROFILE_UNCOMPRESSED) {
if (rohc_cid_context->large_cid_present) {
guint8 *payload_data;
gint len;
get_self_describing_var_len_val(tvb, rohc_tree, offset+1, hf_rohc_large_cid, &val_len);
len = tvb_captured_length_remaining(tvb, offset);
if (len >= val_len) {
len -= val_len;
payload_data = (guint8 *)wmem_alloc(pinfo->pool, len);
tvb_memcpy(tvb, payload_data, offset, 1);
tvb_memcpy(tvb, &payload_data[1], offset+1+val_len, len-1);
next_tvb = tvb_new_child_real_data(tvb, payload_data, len, len);
add_new_data_source(pinfo, next_tvb, "Payload");
}
}
else {
next_tvb = tvb_new_subset_remaining(tvb, offset);
}
if ((oct&0xf0)==0x40) {
call_dissector(ip_handle, next_tvb, pinfo, tree);
}
else if ((oct&0xf0)==0x60) {
call_dissector(ipv6_handle, next_tvb, pinfo, tree);
}
else {
call_data_dissector(next_tvb, pinfo, tree);
}
col_prepend_fstr(pinfo->cinfo, COL_PROTOCOL, "ROHC <");
col_append_str(pinfo->cinfo, COL_PROTOCOL, ">");
return tvb_captured_length(tvb);
}
else if (((oct&0x80)==0x00) && (rohc_cid_context->profile==ROHC_PROFILE_RTP)) {
/* 5.7.1. Packet type 0: UO-0, R-0, R-0-CRC */
offset = dissect_rohc_pkt_type_0(tvb, pinfo, rohc_tree, offset, oct, rohc_cid_context);
} else if ((oct&0xc0)==0x80) {
if (rohc_cid_context->mode == RELIABLE_BIDIRECTIONAL) {
/* 5.7.2. Packet type 1 (R-mode): R-1, R-1-TS, R-1-ID */
offset = dissect_rohc_pkt_type_1_r_mode(tvb, pinfo, rohc_tree, offset, rohc_cid_context);
}
else {
/* 5.7.3. Packet type 1 (U/O-mode): UO-1, UO-1-ID, UO-1-TS */
offset = dissect_rohc_pkt_type_1_u_o_mode(tvb, pinfo, rohc_tree, offset, rohc_cid_context);
}
} else if ((oct&0xe0)==0xc0) {
/* 5.7.4. Packet type 2: UOR-2 */
offset = dissect_rohc_pkt_type_2(tvb, pinfo, rohc_tree, offset, rohc_cid_context);
}
/* IP-ID */
if (rohc_cid_context->rnd) {
proto_tree_add_item(rohc_tree, hf_rohc_ip_id, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
}
/* UDP Checksum */
if (rohc_cid_context->udp_checksum_present) {
proto_tree_add_checksum(rohc_tree, tvb, offset, hf_rohc_udp_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
offset += 2;
}
payload_tvb = tvb_new_subset_remaining(tvb, offset);
call_data_dissector(payload_tvb, pinfo, tree);
return tvb_captured_length(tvb);
}
/* Set up rohc_cid_hash which holds data for a CID
* needed to dissect subsequent packages.
* XXXX ToDo:
* A better Key than just the CID may have to be devised.
*
*/
static gint cid_hash_equal(gconstpointer v, gconstpointer v2)
{
return (v == v2);
}
static guint cid_hash_func(gconstpointer v)
{
return GPOINTER_TO_UINT(v);
}
static void
rohc_init_protocol(void)
{
rohc_cid_hash = g_hash_table_new(cid_hash_func, cid_hash_equal);
}
static void
rohc_cleanup_protocol(void)
{
g_hash_table_destroy(rohc_cid_hash);
}
void
proto_register_rohc(void)
{
static hf_register_info hf[] =
{
{ &hf_rohc_padding,
{ "Padding","rohc.padding",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_add_cid,
{ "Add-CID","rohc.add_cid",
FT_UINT8, BASE_HEX, NULL, 0xf0,
NULL , HFILL
}
},
{ &hf_rohc_feedback,
{ "Feedback","rohc.feedback",
FT_UINT8, BASE_HEX, NULL, 0xf8,
NULL , HFILL
}
},
{ &hf_rohc_code,
{ "Code","rohc.code",
FT_UINT8, BASE_DEC, NULL, 0x07,
NULL , HFILL
}
},
{ &hf_rohc_size,
{ "Size","rohc.size",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL , HFILL
}
},
{ &hf_rohc_ir_packet,
{ "IR packet","rohc.ir_packet",
FT_UINT8, BASE_HEX, NULL, 0xfe,
NULL , HFILL
}
},
{ &hf_rohc_ir_dyn_packet,
{ "IR-DYN packet","rohc.ir_dyn_packet",
FT_UINT8, BASE_HEX, NULL, 0xff,
NULL , HFILL
}
},
{ &hf_rohc_small_cid,
{ "Small CID","rohc.small_cid",
FT_UINT8, BASE_DEC, NULL, 0x0f,
NULL , HFILL
}
},
{ &hf_rohc_large_cid,
{ "Large CID","rohc.large_cid",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_acktype,
{ "Acktype","rohc.acktype",
FT_UINT8, BASE_DEC, VALS(rohc_acktype_vals), 0xc0,
NULL , HFILL
}
},
{ &hf_rohc_mode,
{ "Mode","rohc.mode",
FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x30,
NULL , HFILL
}
},
{ &hf_rohc_sn,
{ "SN LSB","rohc.sn",
FT_UINT16, BASE_HEX_DEC, NULL, 0x0fff,
NULL , HFILL
}
},
{ &hf_rohc_profile_spec_octet,
{ "Profile-specific octet","rohc.profile_spec_octet",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_fb1_sn,
{ "SN LSB","rohc.sn",
FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_opt_type,
{ "Option type","rohc.opt_type",
FT_UINT8, BASE_DEC, VALS(rohc_opt_type_vals), 0xf0,
NULL , HFILL
}
},
{ &hf_rohc_opt_len,
{ "Option length","rohc.opt_length",
FT_UINT8, BASE_DEC, NULL, 0x0f,
NULL , HFILL
}
},
{ &hf_rohc_crc,
{ "CRC","rohc.crc",
FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_opt_sn,
{ "SN additional bits","rohc.opt.sn_add_bits",
FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
"Feedback Option SN", HFILL
}
},
{ &hf_rohc_ext_sn,
{ "SN LSB","rohc.sn",
FT_UINT24, BASE_HEX_DEC, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_opt_clock,
{ "Clock", "rohc.opt.clock",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Feedback Option Clock", HFILL
}
},
{ &hf_rohc_opt_jitter,
{ "Max Jitter", "rohc.opt.jitter",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Feedback Option Jitter", HFILL
}
},
{ &hf_rohc_opt_loss,
{ "Longest loss event (packets)", "rohc.opt.loss",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Feedback Option Loss", HFILL
}
},
{ &hf_rohc_profile,
{ "Profile","rohc.profile",
FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
NULL , HFILL
}
},
{ &hf_rohc_d_bit,
{ "D - Dynamic chain","rohc.d",
FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x01,
NULL , HFILL
}
},
{ &hf_rohc_ip_version,
{ "Version","rohc.ip.version",
FT_UINT8, BASE_DEC, VALS(rohc_ip_version_vals), 0xf0,
NULL , HFILL
}
},
{ &hf_rohc_static_ipv4,
{ "Static IPv4 chain",
"rohc.static.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_ip_protocol,
{ "Protocol","rohc.ip.protocol",
FT_UINT8, BASE_DEC|BASE_EXT_STRING, &ipproto_val_ext, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ipv4_src,
{ "Source address","rohc.ipv4_src",
FT_IPv4, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_ipv4_dst,
{ "Destination address","rohc.ipv4_dst",
FT_IPv4, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_ipv6_flow,
{ "Flow Label","rohc.ipv6.flow",
FT_UINT24, BASE_DEC, NULL, 0x0fffff,
NULL , HFILL
}
},
{ &hf_rohc_ipv6_nxt_hdr,
{ "Next Header","rohc.ipv6.nxt_hdr",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ipv6_src,
{ "Source Address","rohc.ipv6.src",
FT_IPv6, BASE_NONE, NULL, 0,
NULL , HFILL
}
},
{ &hf_rohc_ipv6_dst,
{ "Destination Address","rohc.ipv6.src",
FT_IPv6, BASE_NONE, NULL, 0,
NULL , HFILL
}
},
{ &hf_rohc_static_udp,
{ "Static UDP chain", "rohc.static.udp",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_udp_src_port,
{ "Source Port","rohc.udp_src_port",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_udp_dst_port,
{ "Destination Port","rohc.udp_dst_port",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_static_rtp,
{ "Static RTP chain",
"rohc.static.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_rtp_ssrc,
{ "SSRC","rohc.rtp.ssrc",
FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_dynamic_ipv4,
{ "Dynamic IPv4 chain",
"rohc.dynamic.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_dynamic_udp,
{ "Dynamic UDP chain",
"rohc.dynamic.udp", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_rtp_tos,
{ "Type of Service","rohc.rtp.tos",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_rtp_ttl,
{ "Time to Live","rohc.rtp.ttl",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_rtp_id,
{ "Identification","rohc.rtp.id",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_rtp_df,
{ "Don't Fragment(DF)","rohc.rtp.df",
FT_BOOLEAN, 8, NULL, 0x80,
NULL , HFILL
}
},
{ &hf_rohc_rtp_rnd,
{ "RND(IP-ID behaves randomly)","rohc.rtp.rnd",
FT_BOOLEAN, 8, NULL, 0x40,
NULL , HFILL
}
},
{ &hf_rohc_rtp_nbo,
{ "Network Byte Order (NBO)","rohc.rtp.nbo",
FT_BOOLEAN, 8, NULL, 0x20,
"Whether the IP-ID is in Network Byte Order" , HFILL
}
},
{ &hf_rohc_dynamic_udp_checksum,
{ "UDP Checksum", "rohc.dynamic.udp.checksum",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_dynamic_rtp,
{ "Dynamic RTP chain",
"rohc.dynamic.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_rtp_v,
{ "Version","rohc.rtp.v",
FT_UINT8, BASE_DEC, NULL, 0xc0,
NULL , HFILL
}
},
{ &hf_rohc_rtp_p,
{ "Padding(P)","rohc.rtp.p",
FT_BOOLEAN, 8, NULL, 0x20,
NULL , HFILL
}
},
{ &hf_rohc_rtp_rx,
{ "RX","rohc.rtp.rx",
FT_BOOLEAN, 8, NULL, 0x10,
NULL , HFILL
}
},
{ &hf_rohc_rtp_cc,
{ "CC","rohc.rtp.cc",
FT_UINT8, BASE_DEC, NULL, 0x0f,
"CSRC counter from original RTP header" , HFILL
}
},
{ &hf_rohc_rtp_m,
{ "Marker Bit (M)","rohc.rtp.m",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_set_notset), 0x00,
NULL , HFILL
}
},
{ &hf_rohc_rtp_pt,
{ "Payload Type(PT)","rohc.rtp.pt",
FT_UINT8, BASE_DEC|BASE_EXT_STRING, &rtp_payload_type_vals_ext, 0x7f,
NULL , HFILL
}
},
{ &hf_rohc_rtp_sn,
{ "Sequence Number(SN)","rohc.rtp.sn",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_rtp_timestamp,
{ "RTP Timestamp","rohc.rtp.timestamp",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_rtp_x,
{ "X","rohc.rtp.x",
FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x10,
NULL , HFILL
}
},
{ &hf_rohc_rtp_mode,
{ "Mode","rohc.rtp.mode",
FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0c,
NULL , HFILL
}
},
{ &hf_rohc_rtp_tis,
{ "TIS","rohc.rtp.tis",
FT_BOOLEAN, 8, NULL, 0x02,
NULL , HFILL
}
},
{ &hf_rohc_rtp_tss,
{ "TSS","rohc.rtp.tss",
FT_BOOLEAN, 8, NULL, 0x01,
NULL , HFILL
}
},
{ &hf_rohc_rtp_ts_stride,
{ "TS_Stride","rohc.rtp.ts_stride",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_rtp_time_stride,
{ "Time_Stride","rohc.rtp.time_stride",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_var_len,
{ "Variable length","rohc.var_len",
FT_UINT8, BASE_DEC, VALS(rohc_var_len_vals), 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ipv6_tc,
{ "Traffic class","rohc.tc",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ipv6_hop_limit,
{ "Hop limit","rohc.hop_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ir_previous_frame,
{ "Previous IR frame","rohc.ir.prev.frame_num",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
NULL , HFILL,
}
},
{ &hf_rohc_ir_profile,
{ "Mode","rohc.ir_profile",
FT_UINT16, BASE_DEC, VALS(rohc_profile_vals), 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ir_ip_version,
{ "Mode","rohc.ir_ip_version",
FT_UINT16, BASE_DEC, VALS(rohc_ip_version_vals), 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ir_mode,
{ "Mode","rohc.ir_mode",
FT_UINT32, BASE_DEC, VALS(rohc_mode_vals), 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ir_pkt_frame,
{ "Setup by IR frame","rohc.ir.frame_num",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_comp_sn,
{ "Compressed Sequence Number","rohc.comp.sn",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_r_0_crc,
{ "CRC","rohc.r_0_crc",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_x,
{ "Extension","rohc.x",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_present_not_present), 0x0,
NULL , HFILL
}
},
{ &hf_rohc_ts,
{ "Compressed RTP timestamp","rohc.tp",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_comp_ip_id,
{ "Compressed IP-ID","rohc.comp_ip_id",
FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_t,
{ "T bit","rohc.t",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_compressed_list,
{ "Compressed List", "rohc.compressed-list",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL , HFILL
}
},
{ &hf_rohc_compressed_list_et,
{ "Encoding Type", "rohc.compressed-list.et",
FT_UINT8, BASE_DEC, VALS(compressed_list_encoding_type_vals), 0xc0,
NULL , HFILL
}
},
{ &hf_rohc_compressed_list_gp,
{ "Gen-id Present", "rohc.compressed-list.gp",
FT_UINT8, BASE_DEC, NULL, 0x20,
NULL , HFILL
}
},
{ &hf_rohc_compressed_list_ps,
{ "PS", "rohc.compressed-list.ps",
FT_UINT8, BASE_DEC, VALS(compressed_list_ps_vals), 0x10,
"Size of xi fields", HFILL
}
},
{ &hf_rohc_compressed_list_res,
{ "Reserved", "rohc.compressed-list.res",
FT_UINT8, BASE_DEC, NULL, 0x10,
NULL, HFILL
}
},
{ &hf_rohc_compressed_list_count,
{ "Count", "rohc.compressed-list.count",
FT_UINT8, BASE_DEC, NULL, 0x0f,
NULL, HFILL
}
},
{ &hf_rohc_compressed_list_cc,
{ "CSRC Counter", "rohc.compressed-list.cc",
FT_UINT8, BASE_DEC, NULL, 0x0f,
"CSRC Counter from original RTP header", HFILL
}
},
{ &hf_rohc_compressed_list_xi_1,
{ "XI 1", "rohc.compressed-list.xi_1",
FT_UINT8, BASE_DEC, NULL, 0x0f,
NULL, HFILL
}
},
{ &hf_rohc_compressed_list_gen_id,
{ "gen_id", "rohc.compressed-list.gen-id",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_compressed_list_ref_id,
{ "ref_id", "rohc.compressed-list.ref-id",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_compressed_list_mask_size,
{ "Mask size","rohc.compressed-list.mask_size",
FT_BOOLEAN, 8, TFS(&rohc_cmp_lst_mask_size_vals), 0x80,
NULL , HFILL
}
},
{ &hf_rohc_compressed_list_ins_bit_mask,
{ "Insertion bit mask","rohc.compressed-list.ins_bit_mask",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_compressed_list_rem_bit_mask,
{ "Removal bit mask","rohc.compressed-list.rem_bit_mask",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_spare_bits,
{ "Spare bits(0)", "rohc.spare_bits",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_ip_id,
{ "IP-ID", "rohc.ip-id",
FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_rohc_udp_checksum,
{ "UDP checksum", "rohc.udp_checksum",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL
}
},
/* Generated from convert_proto_tree_add_text.pl */
{ &hf_rohc_unknown_option_data, { "Unknown Option data", "rohc.unknown_option_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_rohc_configured_by_ir_packet, { "Configured by IR packet", "rohc.configured_by_ir_packet", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_rohc_no_configuration_info, { "No configuration info", "rohc.no_configuration_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_rohc_error_packet, { "Error packet", "rohc.error_packet", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
};
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_rohc,
&ett_rohc_conf,
&ett_rohc_fb,
&ett_rohc_feedback,
&ett_rohc_ir,
&ett_rohc_ir_dyn,
&ett_rohc_static_ipv4,
&ett_rohc_static_udp,
&ett_rohc_static_rtp,
&ett_rohc_rtp_static,
&ett_rohc_rtp_dynamic,
&ett_rohc_dynamic_ipv4,
&ett_rohc_dynamic_udp,
&ett_rohc_dynamic_rtp,
&ett_rohc_compressed_list,
&ett_rohc_packet
};
static ei_register_info ei[] = {
{ &ei_rohc_profile_spec_octet, { "rohc.profile_spec_octet.bad", PI_PROTOCOL, PI_WARN, "Invalid profile-specific octet value", EXPFILL }},
{ &ei_rohc_feedback_type_2_is_not_applicable_for_uncompressed_profile, { "rohc.feedback.type_2_is_not_applicable_for_uncompressed_profile", PI_PROTOCOL, PI_WARN, "Feedback type 2 is not applicable for uncompressed profile", EXPFILL }},
{ &ei_rohc_rohc_opt_clock, { "rohc.opt.clock.udp", PI_MALFORMED, PI_ERROR, "CLOCK option should not be used for UDP", EXPFILL }},
{ &ei_rohc_opt_jitter, { "rohc.opt.jitter.udp", PI_MALFORMED, PI_ERROR, "JITTER option should not be used for UDP", EXPFILL }},
{ &ei_rohc_not_dissected_yet, { "rohc.not_dissected_yet", PI_UNDECODED, PI_WARN, "Not dissected yet", EXPFILL }},
{ &ei_rohc_profile_specific, { "rohc.profile_specific", PI_UNDECODED, PI_WARN, "profile-specific information [Not dissected yet]", EXPFILL }},
{ &ei_rohc_profile_not_supported, { "rohc.profile_not_supported", PI_PROTOCOL, PI_WARN, "Profile not supported", EXPFILL }},
{ &ei_rohc_ip_version, { "rohc.ip.version.unknown", PI_PROTOCOL, PI_WARN, "Error unknown version, only 4 or 6 allowed", EXPFILL }},
{ &ei_rohc_desegmentation_not_implemented, { "rohc.desegmentation_not_implemented", PI_UNDECODED, PI_WARN, "Segment [Desegmentation not implemented yet]", EXPFILL }},
};
expert_module_t* expert_rohc;
/* Register the protocol name and description */
proto_rohc = proto_register_protocol("RObust Header Compression (ROHC)", "ROHC", "rohc");
rohc_handle = register_dissector("rohc", dissect_rohc, proto_rohc);
register_init_routine(&rohc_init_protocol);
register_cleanup_routine(&rohc_cleanup_protocol);
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_rohc, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_rohc = expert_register_protocol(proto_rohc);
expert_register_field_array(expert_rohc, ei, array_length(ei));
}
void
proto_reg_handoff_rohc(void)
{
dissector_add_uint("ethertype", ETHERTYPE_ROHC, rohc_handle);
ip_handle = find_dissector_add_dependency("ip", proto_rohc);
ipv6_handle = find_dissector_add_dependency("ipv6", proto_rohc);
}
/*
* Editor modelines - http://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:
*/