*** packet-dcp.c.orig Sun Apr 20 05:50:21 2003 --- packet-dcp.c Mon Apr 21 03:47:16 2003 *************** *** 0 **** --- 1,526 ---- + /* packet-dcp.c + * Routines for Datagram Congestion Control Protocol (DCCP) + * packet dissection. In etherreal the name dccp was already in + * use by Distributed Checksum Clearinghouse Protocol. + * + * Copyright 2003, Joacim Häggmark + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + #ifdef HAVE_CONFIG_H + # include "config.h" + #endif + + #include + #include + #include + + #include + #include + #include + #include "ipproto.h" + #include "in_cksum.h" + #include "prefs.h" + + #include "packet-ip.h" + #include + + static int proto_dcp = -1; + static int hf_dcp_srcport = -1; + static int hf_dcp_dstport = -1; + static int hf_dcp_port = -1; + static int hf_dcp_type = -1; + static int hf_dcp_res = -1; + static int hf_dcp_res2 = -1; + static int hf_dcp_seq = -1; + static int hf_dcp_ack = -1; + static int hf_dcp_sname = -1; + static int hf_dcp_dataoff = -1; + static int hf_dcp_ndp = -1; + static int hf_dcp_cslen = -1; + static int hf_dcp_checksum = -1; + static int hf_dcp_checksum_bad = -1; + static int hf_dcp_r_reason = -1; + static int hf_dcp_r_data1 = -1; + static int hf_dcp_r_data2 = -1; + static int hf_dcp_r_data3 = -1; + + static gint ett_dcp = -1; + static gint ett_dcp_options = -1; + + /* DCCP structs and definitions */ + + typedef struct _e_dcphdr { + guint16 dh_sport; + guint16 dh_dport; + guint32 dh_type_res:8, dh_seq:24; + guint8 dh_dataoff; + guint8 dh_ndpcslen; + guint16 dh_sum; + + } e_dcphdr; + + static dissector_handle_t data_handle; + + /* DCCP packet types */ + + #define DCCP_TYPE_REQUEST 0 + #define DCCP_TYPE_RESPONSE 1 + #define DCCP_TYPE_DATA 2 + #define DCCP_TYPE_ACK 3 + #define DCCP_TYPE_DATAACK 4 + #define DCCP_TYPE_CLOSEREQ 5 + #define DCCP_TYPE_CLOSE 6 + #define DCCP_TYPE_RESET 7 + #define DCCP_TYPE_MOVE 8 + + guchar *get_dcp_type(guint); + guchar *get_dcp_reason(guint); + guchar *get_dcp_option(guint); + guchar *get_dcp_feature(guint); + void dissect_dcp_options(tvbuff_t *, guint, guint, proto_tree *); + + static void + dissect_dcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) + { + e_dcphdr dh; + guint32 dh_seq, dh_ack, dh_sname; + guint16 dh_sport, dh_dport, dh_sum; + guint8 dh_dataoff, dh_ndp, dh_cslen, dh_type, dh_res, dh_res2; + guint8 dh_r_reason, dh_r_data1, dh_r_data2, dh_r_data3; + proto_tree *dcp_tree; + proto_tree *field_tree = NULL; + proto_item *ti, *tf; + guint len, extrah_len = 0, optlen = 0; + guint reported_len; + vec_t cksum_vec[4]; + guint32 phdr[2]; + guint16 computed_cksum; + tvbuff_t *next_tvb; + int offset = 0; + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCP"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + tvb_memcpy(tvb, (guint8 *)&dh, offset, sizeof(e_dcphdr)); + dh_sport = g_ntohs(dh.dh_sport); + dh_dport = g_ntohs(dh.dh_dport); + #ifdef WORDS_BIGENDIAN + dh_seq = g_ntohl(dh.dh_seq); + #else + dh_seq = g_ntohl(dh.dh_seq << 8); + #endif + dh_dataoff = dh.dh_dataoff; + dh_ndp = hi_nibble(dh.dh_ndpcslen); + dh_cslen = lo_nibble(dh.dh_ndpcslen); + dh_sum = g_ntohs(dh.dh_sum); + dh_type = hi_nibble(dh.dh_type_res); + dh_res = lo_nibble(dh.dh_type_res); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "Source port: %u Destination port: %u", dh_sport, dh_dport); + + if (tree) { + ti = proto_tree_add_protocol_format(tree, proto_dcp, tvb, offset, 8, + "Datagram Congestion Control Protocol, Src Port: (%u, Dst Port: %u", + dh_sport, dh_dport); + dcp_tree = proto_item_add_subtree(ti, ett_dcp); + + proto_tree_add_uint_format(dcp_tree, hf_dcp_srcport, tvb, offset, 2, dh_sport, + "Source port: %u", dh_sport); + proto_tree_add_uint_format(dcp_tree, hf_dcp_dstport, tvb, offset + 2, 2, dh_dport, + "Destination port: %u", dh_dport); + + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset, 2, dh_sport); + proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset+2, 2, dh_dport); + + proto_tree_add_uint_format(dcp_tree, hf_dcp_type, tvb, offset+4, 1, dh_type, "Type: %s (%u)", get_dcp_type(dh_type), dh_type); + proto_tree_add_uint_format(dcp_tree, hf_dcp_res, tvb, offset+4, 1, dh_res, "Reserved: %u", dh_res); + proto_tree_add_uint_format(dcp_tree, hf_dcp_seq, tvb, offset+5, 3, dh_seq, "Sequence number: %u", dh_seq); + + proto_tree_add_uint_format(dcp_tree, hf_dcp_dataoff, tvb, offset+8, 1, dh_dataoff, "Data offset: %u", dh_dataoff); + proto_tree_add_uint_format(dcp_tree, hf_dcp_ndp, tvb, offset+9, 1, dh_ndp, "NDP: %u", dh_ndp); + proto_tree_add_uint_format(dcp_tree, hf_dcp_cslen, tvb, offset+9, 1, dh_cslen, "Cslen: %u", dh_cslen); + + reported_len = tvb_reported_length(tvb); + len = tvb_length(tvb); + if (dh_sum == 0) { + /* No checksum supplied in the packet. */ + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, + offset + 10, 2, dh_sum, "Checksum: 0x%04x (none)", dh_sum); + } 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? */ + + /* 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_DCP<<16) + reported_len); + cksum_vec[2].len = 4; + break; + + case AT_IPv6: + phdr[0] = g_htonl(reported_len); + phdr[1] = g_htonl(IP_PROTO_DCP); + cksum_vec[2].len = 8; + break; + + default: + /* DCCP runs only atop IPv4 and IPv6.... */ + g_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 + 10, 2, dh_sum, "Checksum: 0x%04x (correct)", dh_sum); + } else { + proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_checksum_bad, tvb, + offset + 10, 2, TRUE); + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, + offset + 10, 2, dh_sum, + "Checksum: 0x%04x (incorrect, should be 0x%04x)", dh_sum, + in_cksum_shouldbe(dh_sum, computed_cksum)); + } + } else { + proto_tree_add_uint_format(dcp_tree, hf_dcp_checksum, tvb, + offset + 10, 2, dh_sum, "Checksum: 0x%04x", dh_sum); + } + + if ( dh_type == DCCP_TYPE_DATA ) { + extrah_len = 0; + } else if ( dh_type == DCCP_TYPE_REQUEST ) { + extrah_len = 4; + dh_sname = tvb_get_ntohl(tvb, offset + 12); + proto_tree_add_uint_format(dcp_tree, hf_dcp_sname, tvb, offset+ 12, 4, dh_sname, "Servicename: %u", dh_sname); + } else if ( dh_type == DCCP_TYPE_RESET ) { + extrah_len = 8; + dh_res2 = tvb_get_guint8(tvb, offset + 12); + dh_ack = tvb_get_ntoh24(tvb, offset + 13); + dh_r_reason = tvb_get_guint8(tvb, offset + 16); + dh_r_data1 = tvb_get_guint8(tvb, offset + 17); + dh_r_data2 = tvb_get_guint8(tvb, offset + 18); + dh_r_data3 = tvb_get_guint8(tvb, offset + 19); + proto_tree_add_uint_format(dcp_tree, hf_dcp_res2, tvb, offset+ 12, 1, dh_res2, "Reserved: %u", dh_res2); + proto_tree_add_uint_format(dcp_tree, hf_dcp_ack, tvb, offset+ 13, 3, dh_ack, "Ack: %u", dh_ack); + proto_tree_add_uint_format(dcp_tree, hf_dcp_r_reason, tvb, offset+ 16, 1, dh_r_reason, "Reset reason: %s (%u)", get_dcp_reason(dh_r_reason), dh_r_reason); + proto_tree_add_uint_format(dcp_tree, hf_dcp_r_data1, tvb, offset+ 17, 1, dh_r_reason, "Reset data1: %u", dh_r_data1); + proto_tree_add_uint_format(dcp_tree, hf_dcp_r_data2, tvb, offset+ 18, 1, dh_r_reason, "Reset data2: %u", dh_r_data2); + proto_tree_add_uint_format(dcp_tree, hf_dcp_r_data3, tvb, offset+ 19, 1, dh_r_reason, "Reset data3: %u", dh_r_data3); + } else if ( dh_type < 8 ) { + extrah_len = 4; + dh_res2 = tvb_get_guint8(tvb, offset + 12); + dh_ack = tvb_get_ntoh24(tvb, offset + 13); + proto_tree_add_uint_format(dcp_tree, hf_dcp_res2, tvb, offset+ 12, 1, dh_res2, "Reserved: %u", dh_res2); + proto_tree_add_uint_format(dcp_tree, hf_dcp_ack, tvb, offset+ 13, 3, dh_ack, "Ack: %u", dh_ack); + } + + optlen = (dh_dataoff * 4) - 12 - extrah_len; + + if ( dh_type < 8 && optlen > 0 ) { + tf = proto_tree_add_text(dcp_tree, tvb, offset + 12 + extrah_len, optlen, "Options: (%u bytes)", optlen); + field_tree = proto_item_add_subtree(tf, ett_dcp_options); + dissect_dcp_options(tvb, offset + 12 + extrah_len, optlen, field_tree); + } + + + + } + + offset += 12 + extrah_len + optlen; + next_tvb = tvb_new_subset(tvb, offset, -1, -1); + call_dissector(data_handle,next_tvb, pinfo, tree); + } + + void + dissect_dcp_options(tvbuff_t *tvb, guint offset, guint length, proto_tree *opt_tree) + { + guchar opt; + guint optlen, feature; + while ( length > 0 ) { + opt = tvb_get_guint8(tvb, offset); + if ( opt < 32 ) { + proto_tree_add_text(opt_tree, tvb, offset, 1, "%s (%u)", get_dcp_option(opt), opt); + length--; + offset++; + } else { + optlen = tvb_get_guint8(tvb, offset +1); + if ( optlen > length ) { + proto_tree_add_text(opt_tree, tvb, offset, length, "%s (%u) with an optlen %u that goes past end of options!", get_dcp_option(opt), opt, optlen); + return; + } + + if ( opt > 32 && opt < 36 ) { + feature = tvb_get_guint8(tvb, offset +2); + proto_tree_add_text(opt_tree, tvb, offset, optlen, "%s (%u), length: %u, feature: %s (%u)", get_dcp_option(opt), opt, optlen, get_dcp_feature(feature), feature); + } else { + proto_tree_add_text(opt_tree, tvb, offset, optlen, "%s (%u), length: %u", get_dcp_option(opt), opt, optlen); + } + length -= optlen; + offset += optlen; + } + + } + } + + 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_type, + { "DCCP type", "dcp.type", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_seq, + { "Sequence number", "dcp.seq", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_ack, + { "Ack number", "dcp.ack", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_sname, + { "Service name", "dcp.sname", FT_UINT32, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_dataoff, + { "Data offset", "dcp.dataoff", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_ndp, + { "NDP", "dcp.ndp", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_cslen, + { "Cslen", "dcp.cslen", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + { &hf_dcp_res, + { "Reserved", "dcp.res", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + { &hf_dcp_res2, + { "Reserved", "dcp.res2", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_r_reason, + { "Reset reason", "dcp.r_reason", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_r_data1, + { "Reset data1", "dcp.r_data1", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_r_data2, + { "Reset data2", "dcp.r_data2", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_r_data3, + { "Reset data3", "dcp.r_data3", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_checksum_bad, + { "Bad Checksum", "dcp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "", HFILL }}, + + { &hf_dcp_checksum, + { "Checksum", "dcp.checksum", FT_UINT16, BASE_HEX, 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)); + + dcp_module = prefs_register_protocol(proto_dcp, NULL); + } + + 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_DCP, dcp_handle); + data_handle = find_dissector("data"); + } + + guchar *get_dcp_type(guint port) + { + switch ( port ) { + case 0: + return "DCCP-Request"; + case 1: + return "DCCP-Response"; + case 2: + return "DCCP-Data"; + case 3: + return "DCCP-Ack"; + case 4: + return "DCCP-DataAck"; + case 5: + return "DCCP-CloseReq"; + case 6: + return "DCCP-Close"; + case 7: + return "DCCP-Reset"; + case 8: + return "DCCP-Move"; + default: + return "Unknown"; + } + } + + guchar *get_dcp_option(guint option) + { + switch ( option ) { + case 0: + return "Padding"; + case 1: + return "Data Discarded"; + case 2: + return "Slow Receiver"; + case 3: + return "Buffer Closed"; + case 32: + return "Ignored"; + case 33: + return "Change"; + case 34: + return "Prefer"; + case 35: + return "Confirm"; + case 36: + return "Init Cookie"; + case 37: + return "Ack Vector [Nonce 0]"; + case 38: + return "Ack Vector [Nonce 1]"; + case 39: + return "Receive Buffer Drops"; + case 40: + return "Timestamp"; + case 41: + return "Timestamp Echo"; + case 42: + return "Identification"; + case 44: + return "Challenge"; + } + + if ( option < 32 ) { + return "Unknown 1-byte option"; + + } else if ( option > 127 ) { + return "CCID-Specific option"; + } else { + return "Unknown option"; + } + } + + guchar *get_dcp_feature(guint feature) + { + switch ( feature ) { + case 1: + return "Congestion Control"; + case 2: + return "ECN Capable"; + case 3: + return "Ack Ratio"; + case 4: + return "Use Ack Vector"; + case 5: + return "Mobility Capable"; + case 6: + return "Loss Window"; + case 7: + return "Connection Nonce"; + case 8: + return "Identification Regime"; + } + if ( feature > 127 ) { + return "CCID-Specific feature"; + } else { + return "Unknown feature"; + } + } + + guchar *get_dcp_reason(guint reason) + { + switch ( reason ) { + case 0: + return "Unspecified"; + case 1: + return "Closed"; + case 2: + return "Invalid Packet"; + case 3: + return "Option Error"; + case 4: + return "Feature Error"; + case 5: + return "Connection Refused"; + case 6: + return "Bad Service Name"; + case 7: + return "Too Busy"; + case 8: + return "Bad Init Cookie"; + case 9: + return "Invalid Move"; + case 10: + return "Unanswered Challenge"; + case 11: + return "Fruitless Negotiation"; + default: + return "Unknown"; + } + } + *** ipproto.h.orig Sun Apr 20 06:11:58 2003 --- ipproto.h Sun Apr 20 06:12:52 2003 *************** *** 43,48 **** --- 43,49 ---- #define IP_PROTO_UDP 17 /* user datagram protocol */ #define IP_PROTO_IDP 22 /* xns idp */ #define IP_PROTO_TP 29 /* tp-4 w/ class negotiation */ + #define IP_PROTO_DCP 33 /* Datagram Congestion Control Protocol */ #define IP_PROTO_IPV6 41 /* IP6 header */ #define IP_PROTO_ROUTING 43 /* IP6 routing header */ #define IP_PROTO_FRAGMENT 44 /* IP6 fragmentation header */ *** Makefile.in.orig Sun Apr 20 05:50:38 2003 --- Makefile.in Sun Apr 20 06:04:45 2003 *************** *** 314,319 **** --- 314,320 ---- packet-dcerpc-ubikvote.c \ packet-dcerpc-update.c \ packet-dcerpc-wkssvc.c \ + packet-dcp.c \ packet-ddtp.c \ packet-dec-bpdu.c \ packet-dhcpv6.c \ *************** *** 1286,1291 **** --- 1287,1293 ---- packet-dcerpc-ubikdisk.$(OBJEXT) \ packet-dcerpc-ubikvote.$(OBJEXT) packet-dcerpc-update.$(OBJEXT) \ packet-dcerpc-wkssvc.$(OBJEXT) packet-ddtp.$(OBJEXT) \ + packet-dcp.$(OBJEXT) \ packet-dec-bpdu.$(OBJEXT) packet-dhcpv6.$(OBJEXT) \ packet-diameter.$(OBJEXT) packet-dlsw.$(OBJEXT) \ packet-dns.$(OBJEXT) packet-dsi.$(OBJEXT) \ *************** *** 1538,1543 **** --- 1540,1546 ---- @AMDEP_TRUE@ ./$(DEPDIR)/packet-dcerpc-update.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/packet-dcerpc-wkssvc.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/packet-dcerpc.Po \ + @AMDEP_TRUE@ ./$(DEPDIR)/packet-dcp.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/packet-ddtp.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/packet-dec-bpdu.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/packet-dhcpv6.Po \ *************** *** 2029,2034 **** --- 2032,2038 ---- @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-dcerpc-update.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-dcerpc-wkssvc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-dcerpc.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-dcp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-ddtp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-dec-bpdu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-dhcpv6.Po@am__quote@ *** Makefile.am.orig Sun Apr 20 05:50:50 2003 --- Makefile.am Sun Apr 20 05:53:12 2003 *************** *** 168,173 **** --- 168,174 ---- packet-dcerpc-ubikvote.c \ packet-dcerpc-update.c \ packet-dcerpc-wkssvc.c \ + packet-dcp.c \ packet-ddtp.c \ packet-dec-bpdu.c \ packet-dhcpv6.c \