/* packet-rohc.c * Routines for RObust Header Compression (ROHC) dissection. * * Copyright 2011, Anders Broman * Per Liedberg * * Wireshark - Network traffic analyzer * By Gerald Combs * 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 #include #include #include #include #include #include #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(offsetlast_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: */