diff options
author | Jörg Mayer <jmayer@loplof.de> | 2005-09-20 15:18:28 +0000 |
---|---|---|
committer | Jörg Mayer <jmayer@loplof.de> | 2005-09-20 15:18:28 +0000 |
commit | e6194537b3aca41e6abd876f88a9c7d36afabb70 (patch) | |
tree | 8983f53a7beb019083a48a883c24f7621338e7d0 /epan/dissectors/packet-dcp.c | |
parent | 44a3e93524647d7ad504b32ab10432a9969357a1 (diff) |
Francesco Fondelli; Add dcp support
svn path=/trunk/; revision=15897
Diffstat (limited to 'epan/dissectors/packet-dcp.c')
-rw-r--r-- | epan/dissectors/packet-dcp.c | 1109 |
1 files changed, 1109 insertions, 0 deletions
diff --git a/epan/dissectors/packet-dcp.c b/epan/dissectors/packet-dcp.c new file mode 100644 index 0000000000..06ee3677fa --- /dev/null +++ b/epan/dissectors/packet-dcp.c @@ -0,0 +1,1109 @@ +/* packet-dcp.c + * Routines for Datagram Congestion Control Protocol, "DCCP" dissection: + * it should be conformance to draft-ietf-dccp-spec-11.txt + * + * Copyright 2005 _FF_ + * + * Francesco Fondelli <francesco dot fondelli, gmail dot com> + * + * $Id: README.developer 11973 2004-09-11 23:10:14Z guy $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * Copied from packet-udp.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licepnse + * as published by the Free Software Foundation; either version 2 + * of the Licepnse, 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 Licepnse for more details. + * + * You should have received a copy of the GNU General Public Licepnse + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/* Note: PROTOABBREV name collision problem, 'dccp' is used by Distributed Checksum + Clearinghouse Protocol. + This dissector should be named packet-dccp.c IMHO. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <epan/packet.h> +#include <epan/addr_resolv.h> +#include <epan/ipproto.h> +#include <epan/in_cksum.h> +#include <epan/prefs.h> + +#include "packet-dcp.h" + +#include "packet-ip.h" +#include <epan/conversation.h> +#include <epan/tap.h> + +/* Some definitions and the dissect_options() logic have been taken from Arnaldo Carvalho de Melo's DCCP implementation, thanks! */ + +#define DCCP_HDR_LEN 16 /* base DCCP header length, with 48 bits seqnos */ +#define DCCP_HDR_LEN_MIN 12 /* , with 24 bits seqnum */ +#define DCCP_HDR_PKT_TYPES_LEN_MAX 12 /* max per packet type extra header length */ +#define DCCP_OPT_LEN_MAX 1008 +#define DCCP_HDR_LEN_MAX (DCCP_HDR_LEN + DCCP_HDR_PKT_TYPES_LEN_MAX + DCCP_OPT_LEN_MAX) + + +static const value_string dcp_packet_type_vals[] = { + {0x0, "Request"}, + {0x1, "Response"}, + {0x2, "Data"}, + {0x3, "Ack"}, + {0x4, "DataAck"}, + {0x5, "CloseReq"}, + {0x6, "Close"}, + {0x7, "Reset"}, + {0x8, "Sync"}, + {0x9, "SyncAck"}, + {0xA, "Reserved"}, + {0xB, "Reserved"}, + {0xC, "Reserved"}, + {0xD, "Reserved"}, + {0xE, "Reserved"}, + {0xF, "Reserved"}, + {0, NULL} +}; + +static const value_string dcp_reset_code_vals[] = { + {0x00, "Unspecified"}, + {0x01, "Closed"}, + {0x02, "Aborted"}, + {0x03, "No Connection"}, + {0x04, "Packet Error"}, + {0x05, "Option Error"}, + {0x06, "Mandatory Error"}, + {0x07, "Connection Refused"}, + {0x08, "Bad Service Code"}, + {0x09, "Too Busy"}, + {0x0A, "Bad Init Cookie"}, + {0x0B, "Aggression Penalty"}, + {0x0C, "Reserved"}, + {0, NULL} +}; + +static const value_string dcp_feature_numbers_vals[] = { + {0x01, "CCID"}, + {0x02, "Allow Short Seqnos"}, + {0x03, "Sequence Window"}, + {0x04, "ECN Incapable"}, + {0x05, "Ack Ratio"}, + {0x06, "Send Ack Vector"}, + {0x07, "Send NDP Count"}, + {0x08, "Minimum Checksum Coverage"}, + {0x09, "Check Data Checksum"}, + {0, NULL} +}; + + +#if 0 +#define DBG(str, args...) do {\ + fprintf(stdout, \ + "[%s][%s][%d]: ",\ + __FILE__, \ + __FUNCTION__, \ + __LINE__); \ + fflush(stdout); \ + fprintf(stdout, str, ## args); \ + } while (0) +#else +#define DBG0(format) +#define DBG1(format, arg1) +#define DBG2(format, arg1, arg2) +#endif /* 0/1 */ + + +static int proto_dcp = -1; +static int dccp_tap = -1; + +static int hf_dcp_srcport = -1; +static int hf_dcp_dstport = -1; +static int hf_dcp_port = -1; +static int hf_dcp_data_offset = -1; +static int hf_dcp_ccval = -1; +static int hf_dcp_cscov = -1; +static int hf_dcp_checksum = -1; +static int hf_dcp_checksum_bad = -1; +static int hf_dcp_res1 = -1; +static int hf_dcp_type = -1; +static int hf_dcp_x = -1; +static int hf_dcp_res2 = -1; +static int hf_dcp_seq = -1; + +static int hf_dcp_ack_res = -1; +static int hf_dcp_ack = -1; + +static int hf_dcp_service_code = -1; +static int hf_dcp_reset_code = -1; +static int hf_dcp_data1 = -1; +static int hf_dcp_data2 = -1; +static int hf_dcp_data3 = -1; + +static int hf_dcp_option_type = -1; +static int hf_dcp_feature_number = -1; +static int hf_dcp_ndp_count = -1; +static int hf_dcp_timestamp = -1; +static int hf_dcp_timestamp_echo = -1; +static int hf_dcp_elapsed_time = -1; +static int hf_dcp_data_checksum = -1; + +static int hf_dcp_malformed = -1; + +static gint ett_dcp = -1; +static gint ett_dcp_options = -1; + +static dissector_table_t dcp_subdissector_table; +static heur_dissector_list_t heur_subdissector_list; +static dissector_handle_t data_handle; + +/* preferences */ +static gboolean dcp_summary_in_tree = TRUE; +static gboolean try_heuristic_first = FALSE; +static gboolean dccp_check_checksum = TRUE; + + +void decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int sport, int dport) +{ + tvbuff_t *next_tvb; + int low_port, high_port; + + next_tvb = tvb_new_subset(tvb, offset, -1, -1); + + /* determine if this packet is part of a conversation and call dissector */ + /* for the conversation if available */ + + if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_DCCP, sport, dport, next_tvb, pinfo, tree)) { + return; + } + + if (try_heuristic_first) { + /* do lookup with the heuristic subdissector table */ + if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) { + return; + } + } + + /* Do lookups with the subdissector table. + We try the port number with the lower value first, followed by the + port number with the higher value. This means that, for packets + where a dissector is registered for *both* port numbers: + + 1) we pick the same dissector for traffic going in both directions; + + 2) we prefer the port number that's more likely to be the right + one (as that prefers well-known ports to reserved ports); + + although there is, of course, no guarantee that any such strategy + will always pick the right port number. + XXX - we ignore port numbers of 0, as some dissectors use a port + number of 0 to disable the port. */ + + if (sport > dport) { + low_port = dport; + high_port = sport; + } else { + low_port = sport; + high_port = dport; + } + if (low_port != 0 && + dissector_try_port(dcp_subdissector_table, low_port, next_tvb, pinfo, tree)) { + return; + } + if (high_port != 0 && + dissector_try_port(dcp_subdissector_table, high_port, next_tvb, pinfo, tree)) { + return; + } + + if (!try_heuristic_first) { + /* do lookup with the heuristic subdissector table */ + if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) { + return; + } + } + + /* Oh, well, we don't know this; dissect it as data. */ + call_dissector(data_handle, next_tvb, pinfo, tree); +} + + +/* + * This function dissects DCCP options + */ +static void dissect_options(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *dcp_options_tree, proto_tree *tree _U_, e_dcphdr *dcph _U_, + int offset_start, + int offset_end) +{ + /* if here I'm sure there is at least offset_end - offset_start bytes in tvb and it should be options */ + int offset=offset_start; + guint8 option_type = 0; + guint8 option_len = 0; + char buff[1024]; + guint8 feature_number = 0; + int i; + + while( offset < offset_end ) { + + /* DBG("offset==%d\n", offset); */ + + /* first byte is the option type */ + option_type = tvb_get_guint8(tvb, offset); + proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_option_type, tvb, offset, 1, option_type); + + if (option_type >= 32) { /* variable length options */ + + if(!tvb_bytes_exist(tvb, offset, 1)) { + /* DBG("malformed\n"); */ + proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, -1, TRUE); + return; + } + + option_len = tvb_get_guint8(tvb, offset + 1); + + if (option_len < 2) { + /* DBG("malformed\n"); */ + proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, -1, TRUE); + return; + } + + if(!tvb_bytes_exist(tvb, offset, option_len)) { + /* DBG("malformed\n"); */ + proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, -1, TRUE); + return; + } + + } else { /* 1byte options */ + option_len = 1; + } + + switch (option_type) { + + case 0: + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Padding"); + break; + + case 1: + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Mandatory"); + break; + + case 2: + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Slow Receiver"); + break; + + case 32: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Change L("); + feature_number = tvb_get_guint8(tvb, offset + 2); + proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number); + + if( (feature_number < 10) && (feature_number!=0) ){ + sprintf(buff, "%s%s ", buff, val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type")); + for (i = 0; i < option_len - 3; i++) + sprintf(buff, "%s %d", buff, tvb_get_guint8(tvb, offset + 3 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + } else { + if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0)) + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Change L (Reserved feature number)"); + else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Change L (CCID-specific features)"); + } + break; + + case 33: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Confirm L("); + feature_number = tvb_get_guint8(tvb, offset + 2); + proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number); + + if( (feature_number < 10) && (feature_number!=0) ){ + sprintf(buff, "%s%s ", buff, val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type")); + for (i = 0; i < option_len - 3; i++) + sprintf(buff, "%s %d", buff, tvb_get_guint8(tvb, offset + 3 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + } else { + if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0)) + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Confirm L (Reserved feature number)"); + else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Confirm L (CCID-specific features)"); + } + break; + + case 34: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Change R("); + feature_number = tvb_get_guint8(tvb, offset + 2); + proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number); + + if( (feature_number < 10) && (feature_number!=0) ){ + sprintf(buff, "%s%s ", buff, val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type")); + for (i = 0; i < option_len - 3; i++) + sprintf(buff, "%s %d", buff, tvb_get_guint8(tvb, offset + 3 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + } else { + if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0)) + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Change R (Reserved feature number)"); + else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Change R (CCID-specific features)"); + } + break; + + case 35: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Confirm R("); + feature_number = tvb_get_guint8(tvb, offset + 2); + proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number); + + if( (feature_number < 10) && (feature_number!=0) ){ + sprintf(buff, "%s%s ", buff, val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type")); + for (i = 0; i < option_len - 3; i++) + sprintf(buff, "%s %d", buff, tvb_get_guint8(tvb, offset + 3 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + } else { + if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0)) + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Confirm R (Reserved feature number)"); + else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Confirm R (CCID-specific features)"); + } + break; + + case 36: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Init Cookie("); + for (i = 0; i < option_len - 2; i++) + sprintf(buff, "%s%02x ", buff, tvb_get_guint8(tvb, offset + 2 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + break; + + case 37: + if(option_len==3) + proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 1, + tvb_get_guint8(tvb, offset + 2)); + else if (option_len==4) + proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 2, + tvb_get_ntohs(tvb, offset + 2)); + else if (option_len==5) + proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 3, + tvb_get_ntoh24(tvb, offset + 2)); + else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count too long (max 3 bytes)"); + + break; + + case 38: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Ack Vector0("); + for (i = 0; i < option_len - 2; i++) + sprintf(buff, "%s%02x ", buff, tvb_get_guint8(tvb, offset + 2 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + break; + + case 39: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Ack Vector1("); + for (i = 0; i < option_len - 2; i++) + sprintf(buff, "%s%02x ", buff, tvb_get_guint8(tvb, offset + 2 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + break; + + case 40: + memset(buff, 0, sizeof(buff)); + sprintf(buff, "Data Dropped("); + for (i = 0; i < option_len - 2; i++) + sprintf(buff, "%s%02x ", buff, tvb_get_guint8(tvb, offset + 2 + i)); + sprintf(buff, "%s)", buff); + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, buff); + break; + + case 41: + if(option_len==6) + proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp, tvb, offset + 2, 4, + tvb_get_ntohl(tvb, offset + 2)); + else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, + "Timestamp too long [%u != 6]", option_len); + break; + + case 42: + if(option_len==6) + proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4, + tvb_get_ntohl(tvb, offset + 2)); + else if (option_len==8) { + proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4, + tvb_get_ntohl(tvb, offset + 2)); + + proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 4, 2, + tvb_get_ntohs(tvb, offset + 4)); + } else if (option_len==10) { + proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4, + tvb_get_ntohl(tvb, offset + 2)); + + proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 4, 4, + tvb_get_ntohl(tvb, offset + 4)); + } else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Timestamp Echo length"); + break; + + case 43: + if(option_len==4) + proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 2, 2, + tvb_get_ntohs(tvb, offset + 2)); + else if (option_len==6) + proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 2, 4, + tvb_get_ntohl(tvb, offset + 2)); + else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Elapsed Time length"); + break; + + case 44: + if(option_len==6) { + proto_tree_add_uint(dcp_options_tree, hf_dcp_data_checksum, tvb, offset + 2, 4, + tvb_get_ntohl(tvb, offset + 2)); + } else + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Data checksum length"); + break; + + default : + if(((option_type >= 45) && (option_type <= 127)) || + ((option_type >= 3) && (option_type <= 31))) { + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Reserved"); + break; + } + + if (option_type >= 128) { + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID option %d", option_type); + break; + } + + /* if here we don't know this option */ + proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Unknown"); + break; + + } /* end switch() */ + + offset+=option_len; /* Skip over the dissected option */ + + } /* end while() */ +} + +static void dissect_dcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_tree *dcp_tree = NULL; + proto_tree *dcp_options_tree = NULL; + proto_item *dcp_item = NULL; + + vec_t cksum_vec[4]; + guint32 phdr[2]; + guint16 computed_cksum; + guint offset = 0; + guint len = 0; + guint reported_len = 0; + guint advertised_dccp_header_len = 0; + guint options_len = 0; + static e_dcphdr dcphstruct[4], *dcph; + static int dcph_count=0; + + /* get at least a full message header */ + if(!tvb_bytes_exist(tvb, 0, DCCP_HDR_LEN_MIN)) { + /* DBG("malformed\n"); */ + if (tree) + proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, -1, TRUE); + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "Packet too short"); + return; + } + + dcph_count++; + if(dcph_count>=4) { + dcph_count=0; + } + dcph=&dcphstruct[dcph_count]; + memset(dcph, 0, sizeof(struct _e_dcphdr)); + + SET_ADDRESS(&dcph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data); + SET_ADDRESS(&dcph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data); + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCCP"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + /* Extract generic header */ + dcph->sport=tvb_get_ntohs(tvb, offset); + /* DBG("dcph->sport: %d\n", dcph->sport); */ + dcph->dport=tvb_get_ntohs(tvb, offset+2); + /* DBG("dcph->dport: %d\n", dcph->dport); */ + + /* update pinfo structure. I guess I have to do it, because this is a transport protocol dissector. Right? */ + pinfo->ptype=PT_DCCP; + pinfo->srcport=dcph->sport; + pinfo->destport=dcph->dport; + + dcph->data_offset=tvb_get_guint8(tvb, offset+4); + /* DBG("dcph->data_offset: %d\n", dcph->data_offset); */ + dcph->cscov=tvb_get_guint8(tvb, offset+5)&0x0F; + /* DBG("dcph->cscov: %d\n", dcph->cscov); */ + dcph->ccval=tvb_get_guint8(tvb, offset+5)&0xF0; + /* DBG("dcph->ccval: %d\n", dcph->ccval); */ + dcph->checksum=tvb_get_ntohs(tvb, offset+6); + /* DBG("dcph->checksum: %d\n", dcph->checksum); */ + dcph->reserved1=tvb_get_guint8(tvb, offset+8)&0xE0; + dcph->reserved1>>=5; + /* DBG("dcph->reserved1: %d\n", dcph->reserved1); */ + dcph->type=tvb_get_guint8(tvb, offset+8)&0x1E; + dcph->type>>=1; + /* DBG("dcph->type: %d\n", dcph->type); */ + dcph->x=tvb_get_guint8(tvb, offset+8)&0x01; + /* DBG("dcph->x: %d\n", dcph->x); */ + if(dcph->x) { + if(!tvb_bytes_exist(tvb, 0, DCCP_HDR_LEN)) { /* at least 16 bytes */ + /* DBG("malformed\n"); */ + proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, -1, TRUE); + return; + } + dcph->reserved2=tvb_get_guint8(tvb, offset+9); + /* DBG("dcph->reserved2: %u\n", dcph->reserved2); */ + dcph->seq=tvb_get_ntohs(tvb, offset+10); + dcph->seq<<=32; + dcph->seq+=tvb_get_ntohl(tvb, offset+12); + /* DBG("dcph->seq[48bits]: %llu\n", dcph->seq); */ + } else { + dcph->seq=tvb_get_guint8(tvb, offset+9); + dcph->seq<<=16; + dcph->seq+=tvb_get_ntohs(tvb, offset+10); + /* DBG("dcph->seq[24bits]: %llu\n", dcph->seq); */ + } + + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "%s > %s [%s] Seq=%" PRIu64, + get_dccp_port(dcph->sport), + get_dccp_port(dcph->dport), + val_to_str(dcph->type, dcp_packet_type_vals, "Unknown Type"), + dcph->seq); + + + if (tree) { + if(dcp_summary_in_tree) { + dcp_item = + proto_tree_add_protocol_format(tree, proto_dcp, tvb, offset, dcph->data_offset*4, + "Datagram Congestion Control Protocol, Src Port: %s (%u), Dst Port: %s (%u)" + " [%s] Seq=%" PRIu64, + get_dccp_port(dcph->sport), dcph->sport, + get_dccp_port(dcph->dport), dcph->dport, + val_to_str(dcph->type, dcp_packet_type_vals, "Unknown Type"), + dcph->seq); + } else { + dcp_item = proto_tree_add_item(tree, proto_dcp, tvb, offset, 8, FALSE); + } + + dcp_tree = proto_item_add_subtree(dcp_item, ett_dcp); + + proto_tree_add_uint_format(dcp_tree, hf_dcp_srcport, tvb, offset, 2, dcph->sport, + "Source port: %s (%u)", get_dccp_port(dcph->sport), dcph->sport); + proto_tree_add_uint_format(dcp_tree, hf_dcp_dstport, tvb, offset + 2, 2, dcph->dport, + "Destination port: %s (%u)", get_dccp_port(dcph->dport), dcph->dport); + + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset, 2, dcph->sport); + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset + 2, 2, dcph->dport); + + proto_tree_add_uint(dcp_tree, hf_dcp_data_offset, tvb, offset + 4, 1, dcph->data_offset); + proto_tree_add_uint(dcp_tree, hf_dcp_ccval, tvb, offset + 5, 1, dcph->ccval); + proto_tree_add_uint(dcp_tree, hf_dcp_cscov, tvb, offset + 5, 1, dcph->cscov); + + /* checksum analisys taken from packet-udp */ + + reported_len = tvb_reported_length(tvb); + len = tvb_length(tvb); + if (dcph->checksum == 0) { + /* No checksum supplied in the packet */ + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, + offset + 6, 2, dcph->checksum, "Checksum: 0x%04x (none)", dcph->checksum); + } else if (!pinfo->fragmented && len >= reported_len) { + + /* The packet isn't part of a fragmented datagram and isn't + truncated, so we can checksum it. + XXX - make a bigger scatter-gather list once we do fragment + reassembly? */ + + if (dccp_check_checksum) { + + /* Set up the fields of the pseudo-header. */ + cksum_vec[0].ptr = pinfo->src.data; + cksum_vec[0].len = pinfo->src.len; + cksum_vec[1].ptr = pinfo->dst.data; + cksum_vec[1].len = pinfo->dst.len; + cksum_vec[2].ptr = (const guint8 *)&phdr; + switch (pinfo->src.type) { + + case AT_IPv4: + phdr[0] = g_htonl((IP_PROTO_DCCP<<16) + reported_len); + cksum_vec[2].len = 4; + break; + case AT_IPv6: + phdr[0] = g_htonl(reported_len); + phdr[1] = g_htonl(IP_PROTO_DCCP); + cksum_vec[2].len = 8; + break; + + default: + /* DCCP runs only atop IPv4 and IPv6.... */ + //DISSECTOR_ASSERT_NOT_REACHED(); + break; + } + cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len); + cksum_vec[3].len = reported_len; + computed_cksum = in_cksum(&cksum_vec[0], 4); + if (computed_cksum == 0) { + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, + offset + 6, 2, dcph->checksum, + "Checksum: 0x%04x [correct]", dcph->checksum); + } else { + proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_checksum_bad, tvb, offset + 6, 2, TRUE); + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, offset + 6, 2, dcph->checksum, + "Checksum: 0x%04x [incorrect, should be 0x%04x]", dcph->checksum, + in_cksum_shouldbe(dcph->checksum, computed_cksum)); + } + } else { + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, + offset + 6, 2, dcph->checksum, "Checksum: 0x%04x", dcph->checksum); + } + } else { + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, + offset + 6, 2, dcph->checksum, "Checksum: 0x%04x", dcph->checksum); + } + + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_res1, tvb, offset + 8, 1, dcph->reserved1); + proto_tree_add_uint(dcp_tree, hf_dcp_type, tvb, offset + 8, 1, dcph->type); + proto_tree_add_boolean(dcp_tree, hf_dcp_x, tvb, offset + 8, 1, dcph->x); + if(dcph->x) { + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_res2, tvb, offset + 9, 1, dcph->reserved2); + proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 10, 6, dcph->seq); + } else { + proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 9, 3, dcph->seq); + + } + } + + if(dcph->x) + offset+=16; /* Skip over extended Generic header */ + else + offset+=12; /* Skip over not extended Generic header */ + + /* dissecting type depending additional fields */ + switch(dcph->type) { + + case 0x0: /* DCCP-Request */ + if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */ + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet"); + return; + } + dcph->service_code=tvb_get_ntohl(tvb, offset); + if(tree) + proto_tree_add_uint(dcp_tree, hf_dcp_service_code, tvb, offset, 4, dcph->service_code); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dcph->service_code); + + offset+=4; /* Skip over service code */ + break; + + case 0x1: /* DCCP-Response */ + if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */ + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet"); + return; + } + dcph->ack_reserved=tvb_get_ntohs(tvb, offset); + if(tree) + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved); + dcph->ack=tvb_get_ntohs(tvb, offset+2); + dcph->ack<<=32; + dcph->ack+=tvb_get_ntohl(tvb, offset+4); + + if(tree) + proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" PRIu64 ")", dcph->ack); + + offset+=8; /* Skip over Acknowledgement Number Subheader */ + + if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */ + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet"); + return; + } + dcph->service_code=tvb_get_ntohl(tvb, offset); + if(tree) + proto_tree_add_uint(dcp_tree, hf_dcp_service_code, tvb, offset, 4, dcph->service_code); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dcph->service_code); + + offset+=4; /* Skip over service code */ + break; + + case 0x2: /* DCCP-Data */ + /* nothing to dissect */ + break; + + case 0x3: /* DCCP-Ack */ + case 0x4: /* DCCP-DataAck */ + if(dcph->x) { + if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */ + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet"); + return; + } + dcph->ack_reserved=tvb_get_ntohs(tvb, offset); + if(tree) + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved); + dcph->ack=tvb_get_ntohs(tvb, offset+2); + dcph->ack<<=32; + dcph->ack+=tvb_get_ntohl(tvb, offset+4); + if(tree) + proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" PRIu64 ")", dcph->ack); + + offset+=8; /* Skip over Acknowledgement Number Subheader */ + } else { + if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */ + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet"); + return; + } + dcph->ack_reserved=tvb_get_guint8(tvb, offset); + if(tree) + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 1, dcph->ack_reserved); + dcph->ack=tvb_get_guint8(tvb, offset+1); + dcph->ack<<=16; + dcph->ack+=tvb_get_ntohs(tvb, offset+2); + if(tree) + proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 1, 3, dcph->ack); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" PRIu64 ")", dcph->ack); + + offset+=4; /* Skip over Acknowledgement Number Subheader */ + } + break; + + case 0x7: /* DCCP-Reset */ + if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */ + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet"); + return; + } + dcph->ack_reserved=tvb_get_ntohs(tvb, offset); + if(tree) + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved); + dcph->ack=tvb_get_ntohs(tvb, offset+2); + dcph->ack<<=32; + dcph->ack+=tvb_get_ntohl(tvb, offset+4); + if(tree) + proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" PRIu64 ")", dcph->ack); + + offset+=8; /* Skip over Acknowledgement Number Subheader */ + + dcph->reset_code=tvb_get_guint8(tvb, offset); + dcph->data1=tvb_get_guint8(tvb, offset+1); + dcph->data2=tvb_get_guint8(tvb, offset+2); + dcph->data3=tvb_get_guint8(tvb, offset+3); + if(tree) { + proto_tree_add_uint(dcp_tree, hf_dcp_reset_code, tvb, offset, 1, dcph->reset_code); + proto_tree_add_uint(dcp_tree, hf_dcp_data1, tvb, offset + 1, 1, dcph->data1); + proto_tree_add_uint(dcp_tree, hf_dcp_data2, tvb, offset + 2, 1, dcph->data2); + proto_tree_add_uint(dcp_tree, hf_dcp_data3, tvb, offset + 3, 1, dcph->data3); + } + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (code=%s)", val_to_str(dcph->reset_code, dcp_reset_code_vals, "Unknown")); + + offset+=4; /* Skip over Reset Code and data123 */ + break; + + case 0x5: /* DCCP-CloseReq */ + case 0x6: /* DCCP-Close */ + case 0x8: /* DCCP-Sync */ + case 0x9: /* DCCP-SyncAck */ + if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */ + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet"); + return; + } + dcph->ack_reserved=tvb_get_ntohs(tvb, offset); + if(tree) + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved); + dcph->ack=tvb_get_ntohs(tvb, offset+2); + dcph->ack<<=32; + dcph->ack+=tvb_get_ntohl(tvb, offset+4); + if(tree) + proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" PRIu64 ")", dcph->ack); + + offset+=8; /* Skip over Acknowledgement Number Subheader */ + break; + + default: + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "Reserved packet type: unable to dissect further"); + return; + break; + } + + + /* note: data_offset is the offset from the start of the packet's DCCP header to the + * start of its application data area, in 32-bit words. + */ + + /* it's time to do some checks */ + advertised_dccp_header_len = dcph->data_offset*4; + options_len = advertised_dccp_header_len - offset; + + if ( advertised_dccp_header_len > DCCP_HDR_LEN_MAX ) { + if(tree) + proto_tree_add_text(dcp_tree, tvb, 4, 2, + "bogus data offset, advertised header length (%d) is larger than max (%d)", + advertised_dccp_header_len, DCCP_HDR_LEN_MAX); + return; + } + + if(!tvb_bytes_exist(tvb, 0, advertised_dccp_header_len)) { + if(tree) + proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet: missing %d bytes of DCCP header", + advertised_dccp_header_len - tvb_reported_length_remaining(tvb, offset)); + return; + } + + if(options_len > DCCP_OPT_LEN_MAX) { + /* DBG("malformed\n"); */ + if(tree) + proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, -1, TRUE); + return; + } + + + /* Dissecting Options (if here we have at least (advertised_dccp_header_len - offset) bytes of options) */ + if(advertised_dccp_header_len == offset) { + ; /* ok no options, no need to skip over */ + } else if (advertised_dccp_header_len < offset) { + if(tree) { + proto_tree_add_text(dcp_tree, tvb, 4, 2, + "bogus data offset, advertised header length (%d) is shorter than expected", + advertised_dccp_header_len); + proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, -1, TRUE); + } + return; + } else { + if(tree) { + dcp_item = proto_tree_add_text(dcp_tree, tvb, offset, options_len, "Options: (%u bytes)", options_len); + dcp_options_tree = proto_item_add_subtree(dcp_item, ett_dcp_options); + dissect_options(tvb, pinfo, dcp_options_tree, tree, dcph, offset, offset + options_len); + } + } + + offset+=options_len; /* Skip over Options */ + + /* Queuing tap data */ + tap_queue_packet(dccp_tap, pinfo, dcph); + + /* Call sub-dissectors */ + + if (!pinfo->in_error_pkt || tvb_length_remaining(tvb, offset) > 0) + decode_dccp_ports(tvb, offset, pinfo, tree, dcph->sport, dcph->dport); +} + + +void proto_register_dcp(void) +{ + module_t *dcp_module; + + static hf_register_info hf[] = { + { &hf_dcp_srcport, + { "Source Port", "dcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_dstport, + { "Destination Port", "dcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_port, + { "Source or Destination Port", "dcp.port", FT_UINT16, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_data_offset, + { "Data Offset", "dcp.data_offset", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_ccval, + { "CCVal", "dcp.ccval", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_cscov, + { "Checksum Coverage", "dcp.cscov", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_checksum_bad, + { "Bad Checksum", "dcp.checksum_bad", FT_BOOLEAN, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_checksum, + { "Checksum", "dcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_res1, + { "Reserved", "dcp.res1", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_res2, + { "Reserved", "dcp.res2", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_type, + { "Type", "dcp.type", FT_UINT8, BASE_DEC, VALS(dcp_packet_type_vals), 0x0, + "", HFILL }}, + + { &hf_dcp_x, + { "Extended Sequence Numbers", "dcp.x", FT_BOOLEAN, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_seq, + { "Sequence Number", "dcp.seq", FT_UINT64, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_ack_res, + { "Reserved", "dcp.ack_res", FT_UINT16, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_ack, + { "Acknowledgement Number", "dcp.ack", FT_UINT64, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_service_code, + { "Service Code", "dcp.service_code", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_reset_code, + { "Reset Code", "dcp.reset_code", FT_UINT8, BASE_DEC, VALS(dcp_reset_code_vals), 0x0, + "", HFILL }}, + + { &hf_dcp_data1, + { "Data 1", "dcp.data1", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_data2, + { "Data 2", "dcp.data2", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_data3, + { "Data 3", "dcp.data3", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_option_type, + { "Option Type", "dcp.option_type", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_feature_number, + { "Feature Number", "dcp.feature_number", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_ndp_count, + { "NDP Count", "dcp.ndp_count", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_timestamp, + { "Timestamp", "dcp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_timestamp_echo, + { "Timestamp Echo", "dcp.timestamp_echo", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_elapsed_time, + { "Elapsed Time", "dcp.elapsed_time", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_data_checksum, + { "Data Checksum", "dcp.checksum_data", FT_UINT32, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_malformed, + { "", "dcp.malformed", FT_BOOLEAN, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + }; + + static gint *ett[] = { + &ett_dcp, + &ett_dcp_options, + }; + + proto_dcp = proto_register_protocol("Datagram Congestion Control Protocol", "DCP", "dcp"); + proto_register_field_array(proto_dcp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* subdissectors */ + dcp_subdissector_table = register_dissector_table("dcp.port", "DCP port", FT_UINT16, BASE_DEC); + register_heur_dissector_list("dcp", &heur_subdissector_list); + + /* reg preferences */ + dcp_module = prefs_register_protocol(proto_dcp, NULL); + prefs_register_bool_preference(dcp_module, "summary_in_tree", + "Show DCCP summary in protocol tree", + "Whether the DCCP summary line should be shown in the protocol tree", + &dcp_summary_in_tree); + + prefs_register_bool_preference(dcp_module, "try_heuristic_first", + "Try heuristic sub-dissectors first", + "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector " + "registered to a specific port", + &try_heuristic_first); + + prefs_register_bool_preference(dcp_module, "check_checksum", + "Check the validity of the DCCP checksum when possible", + "Whether to check the validity of the DCCP checksum", + &dccp_check_checksum); +} + +void proto_reg_handoff_dcp(void) +{ + dissector_handle_t dcp_handle; + + dcp_handle = create_dissector_handle(dissect_dcp, proto_dcp); + dissector_add("ip.proto", IP_PROTO_DCCP, dcp_handle); + data_handle = find_dissector("data"); + dccp_tap = register_tap("dccp"); +} |