diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-skinny.c.in | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-skinny.c.in')
-rw-r--r-- | epan/dissectors/packet-skinny.c.in | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/epan/dissectors/packet-skinny.c.in b/epan/dissectors/packet-skinny.c.in new file mode 100644 index 00000000..4949748e --- /dev/null +++ b/epan/dissectors/packet-skinny.c.in @@ -0,0 +1,675 @@ +/* Do not modify this file. Changes will be overwritten */ +/* Generated Automatically */ +/* packet-skinny.c */ + +/* packet-skinny.c + * Dissector for the Skinny Client Control Protocol + * (The "D-Channel"-Protocol for Cisco Systems' IP-Phones) + * + * Author: Diederik de Groot <ddegroot@user.sf.net>, Copyright 2014 + * Rewritten to support newer skinny protocolversions (V0-V22) + * Based on previous versions/contributions: + * - Joerg Mayer <jmayer@loplof.de>, Copyright 2001 + * - Paul E. Erkkila (pee@erkkila.org) - fleshed out the decode + * skeleton to report values for most message/message fields. + * Much help from Guy Harris on figuring out the wireshark api. + * - packet-aim.c by Ralf Hoelzer <ralf@well.com>, Copyright 2000 + * - Wireshark - Network traffic analyzer, + * By Gerald Combs <gerald@wireshark.org>, Copyright 1998 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* [[[cog +# +# Using Cog.py Inplace Code Generator +# +# Dependencies: +# - python2.x +# - cog.py: (pip install cogapp / http://nedbatchelder.com/code/cog/) +# - python.xml +# - python.xml.sax +# +cog.out('/*\n') +cog.out(' * Generated automatically Using (from wireshark base directory):\n') +cog.out(' * cog.py -D xmlfile=tools/SkinnyProtocolOptimized.xml -d -c -o epan/dissectors/packet-skinny.c epan/dissectors/packet-skinny.c.in\n') +cog.out(' */\n') +/*]]]*/ +/*[[[end]]]*/ + +/* c-basic-offset: 2; tab-width: 8; indent-tabs-mode: nil + * vi: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */ + + +#include "config.h" + +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/conversation.h> +#include <epan/wmem_scopes.h> +#include <epan/to_str.h> +#include <epan/reassemble.h> +#include <epan/tap.h> +#include <epan/ptvcursor.h> + +#include "packet-rtp.h" +#include "packet-tcp.h" +#include "packet-tls.h" +#include "packet-skinny.h" + +/* un-comment the following as well as this line in conversation.c, to enable debug printing */ +/* #define DEBUG_CONVERSATION */ +#include "conversation_debug.h" + +void proto_register_skinny(void); +void proto_reg_handoff_skinny(void); + +#define TCP_PORT_SKINNY 2000 /* Not IANA registered */ +#define SSL_PORT_SKINNY 2443 /* IANA assigned to PowerClient Central Storage Facility */ + +#define BASIC_MSG_TYPE 0x00 +#define V10_MSG_TYPE 0x0A +#define V11_MSG_TYPE 0x0B +#define V15_MSG_TYPE 0x0F +#define V16_MSG_TYPE 0x10 +#define V17_MSG_TYPE 0x11 +#define V18_MSG_TYPE 0x12 +#define V19_MSG_TYPE 0x13 +#define V20_MSG_TYPE 0x14 +#define V21_MSG_TYPE 0x15 +#define V22_MSG_TYPE 0x16 + +static const value_string header_version[] = { + { BASIC_MSG_TYPE, "Basic" }, + { V10_MSG_TYPE, "V10" }, + { V11_MSG_TYPE, "V11" }, + { V15_MSG_TYPE, "V15" }, + { V16_MSG_TYPE, "V16" }, + { V17_MSG_TYPE, "V17" }, + { V18_MSG_TYPE, "V18" }, + { V19_MSG_TYPE, "V19" }, + { V20_MSG_TYPE, "V20" }, + { V21_MSG_TYPE, "V21" }, + { V22_MSG_TYPE, "V22" }, + { 0 , NULL } +}; + +/* Declare MessageId */ +/* [[[cog +import sys +sys.path.append('tools/') + +import parse_xml2skinny_dissector as xml2skinny +global skinny +global message_dissector_functions + +message_dissector_functions = '' +skinny = xml2skinny.xml2obj(xmlfile) + +cog.out('static const value_string message_id[] = {\n') +for message in skinny.message: + message_dissector_functions += '%s' %message.dissect() + cog.out(' { %s, "%s" },\n' %(message.opcode, message.name.replace('Message',''))) +cog.out(' {0 , NULL}\n') +cog.out('};\n') +cog.out('static value_string_ext message_id_ext = VALUE_STRING_EXT_INIT(message_id);\n') +/*]]]*/ +/*[[[end]]]*/ + +/* Declare Enums and Defines */ +/* [[[cog +for enum in skinny.enum: + name = enum.name[0].upper() + enum.name[1:] + if enum.define == "yes": + for entries in enum.entries: + for entry in sorted(entries.entry, key=lambda x: int(x['value'],0)): + if entries.type is not None: + cog.out('#define {0:38} 0x{1:05x} /* {2} */\n' .format(entry.name.upper(), int(entry.value,0), entries.type)) + else: + cog.out('#define {0:38} 0x{1:05x}\n' .format(entry.name.upper(), int(entry.value,0))) + cog.out('\n') + cog.out('static const value_string %s[] = {\n' %(name)) + for entries in enum.entries: + for entry in sorted(entries.entry, key=lambda x: int(x['value'],0)): + if enum.define == "yes": + cog.out(' { %s, "%s" },\n' %(entry.name.upper(), entry.text)) + else: + cog.out(' { 0x%05x, "%s" },\n' %(int(entry.value,0), entry.text)) + cog.out(' { 0x00000, NULL }\n') + cog.out('};\n') + cog.out('static value_string_ext %s_ext = VALUE_STRING_EXT_INIT(%s);\n\n' %(name, name)) +/*]]]*/ +/*[[[end]]]*/ + +/* Staticly Declared Variables */ +static int proto_skinny = -1; +static int hf_skinny_messageId = -1; +static int hf_skinny_data_length = -1; +static int hf_skinny_hdr_version = -1; +static int hf_skinny_xmlData = -1; +static int hf_skinny_ipv4or6 = -1; +static int hf_skinny_response_in = -1; +static int hf_skinny_response_to = -1; +static int hf_skinny_response_time = -1; + +/* [[[cog +for key in sorted(xml2skinny.fieldsArray.keys()): + cog.out('static int hf_skinny_%s = -1;\n' %key) +]]]*/ +/*[[[end]]]*/ + +static dissector_handle_t xml_handle; + +/* Initialize the subtree pointers */ +static int ett_skinny = -1; +static int ett_skinny_tree = -1; + +/* preference globals */ +static gboolean global_skinny_desegment = true; + +/* tap register id */ +static int skinny_tap = -1; + +/* skinny protocol tap info */ +#define MAX_SKINNY_MESSAGES_IN_PACKET 10 +static skinny_info_t pi_arr[MAX_SKINNY_MESSAGES_IN_PACKET]; +static int pi_current = 0; +static skinny_info_t *si; + +dissector_handle_t skinny_handle; + +/* Get the length of a single SKINNY PDU */ +static unsigned +get_skinny_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) +{ + uint32_t hdr_data_length; + + /* Get the length of the SKINNY packet. */ + hdr_data_length = tvb_get_letohl(tvb, offset); + + /* That length doesn't include the length of the header itself. */ + return hdr_data_length + 8; +} + +static void +dissect_skinny_xml(ptvcursor_t *cursor, int hfindex, packet_info *pinfo, uint32_t length, uint32_t maxlength) +{ + proto_item *item = NULL; + proto_tree *subtree = NULL; + proto_tree *tree = ptvcursor_tree(cursor); + uint32_t offset = ptvcursor_current_offset(cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(cursor); + tvbuff_t *next_tvb; + + if (length == 0) { + length = tvb_strnlen(tvb, offset, -1); + } + if (length >= maxlength) { + length = maxlength; + } + + ptvcursor_add_no_advance(cursor, hfindex, length, ENC_ASCII); + + item = proto_tree_add_item(tree, hf_skinny_xmlData, tvb, offset, length, ENC_ASCII); + subtree = proto_item_add_subtree(item, 0); + next_tvb = tvb_new_subset_length_caplen(tvb, offset, length, -1); + if (xml_handle != NULL) { + call_dissector(xml_handle, next_tvb, pinfo, subtree); + } + ptvcursor_advance(cursor, maxlength); +} + +static void +dissect_skinny_ipv4or6(ptvcursor_t *cursor, int hfindex_ipv4, int hfindex_ipv6) +{ + uint32_t ipversion = 0; + uint32_t offset = ptvcursor_current_offset(cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(cursor); + uint32_t hdr_version = tvb_get_letohl(tvb, 4); + + /* ProtocolVersion > 18 include and extra field to declare IPv4 (0) / IPv6 (1) */ + if (hdr_version >= V17_MSG_TYPE) { + ipversion = tvb_get_letohl(tvb, offset); + ptvcursor_add(cursor, hf_skinny_ipv4or6, 4, ENC_LITTLE_ENDIAN); + } + if (ipversion == IPADDRTYPE_IPV4) { + ptvcursor_add(cursor, hfindex_ipv4, 4, ENC_BIG_ENDIAN); + if (hdr_version >= V17_MSG_TYPE) { + /* skip over the extra room for ipv6 addresses */ + ptvcursor_advance(cursor, 12); + } + } else if (ipversion == IPADDRTYPE_IPV6 || ipversion == IPADDRTYPE_IPV4_V6) { + ptvcursor_add(cursor, hfindex_ipv6, 16, ENC_NA); + } else { + /* Invalid : skip over ipv6 space completely */ + ptvcursor_advance(cursor, 16); + } +} + +/* Reads address to provided variable */ +static void +read_skinny_ipv4or6(ptvcursor_t *cursor, address *media_addr) +{ + uint32_t ipversion = IPADDRTYPE_IPV4; + uint32_t offset = ptvcursor_current_offset(cursor); + uint32_t offset2 = 0; + tvbuff_t *tvb = ptvcursor_tvbuff(cursor); + uint32_t hdr_version = tvb_get_letohl(tvb, 4); + + /* ProtocolVersion > 18 include and extra field to declare IPv4 (0) / IPv6 (1) */ + if (hdr_version >= V17_MSG_TYPE) { + ipversion = tvb_get_letohl(tvb, offset); + offset2 = 4; + } + if (ipversion == IPADDRTYPE_IPV4) { + set_address_tvb(media_addr, AT_IPv4, 4, tvb, offset+offset2); + } else if (ipversion == IPADDRTYPE_IPV6 || ipversion == IPADDRTYPE_IPV4_V6) { + set_address_tvb(media_addr, AT_IPv6, 16, tvb, offset+offset2); + } else { + clear_address(media_addr); + } +} + +/** + * Parse a displayLabel string and check if it is using any embedded labels, if so lookup the label and add a user readable translation to the item_tree + */ +static void +dissect_skinny_displayLabel(ptvcursor_t *cursor, packet_info *pinfo, int hfindex, int length) +{ + proto_item *item = NULL; + proto_tree *tree = ptvcursor_tree(cursor); + uint32_t offset = ptvcursor_current_offset(cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(cursor); + wmem_strbuf_t *wmem_new = NULL; + char *disp_string = NULL; + const char *replacestr = NULL; + bool show_replaced_str = false; + int x = 0; + + if (length == 0) { + length = tvb_strnlen(tvb, offset, -1); + if (length == -1) { + /* did not find end of string */ + length = tvb_captured_length_remaining(tvb, offset); + } + } + + item = proto_tree_add_item(tree, hfindex, tvb, offset, length, ENC_ASCII); + + wmem_new = wmem_strbuf_new_sized(pinfo->pool, length + 1); + disp_string = (char*) wmem_alloc(pinfo->pool, length + 1); + disp_string[length] = '\0'; + tvb_memcpy(tvb, (void*)disp_string, offset, length); + + for (x = 0; x < length && disp_string[x] != '\0'; x++) { + replacestr = NULL; + if (x + 1 < length) { + if (disp_string[x] == '\36') { + replacestr = try_val_to_str_ext(disp_string[x + 1], &DisplayLabels_36_ext); + } else if (disp_string[x] == '\200') { + replacestr = try_val_to_str_ext(disp_string[x + 1], &DisplayLabels_200_ext); + } + } + if (replacestr) { + x++; /* swallow replaced characters */ + wmem_strbuf_append(wmem_new, replacestr); + show_replaced_str = true; + } else if (disp_string[x] & 0x80) { + wmem_strbuf_append_unichar_repl(wmem_new); + } else { + wmem_strbuf_append_c(wmem_new, disp_string[x]); + } + } + if (show_replaced_str) { + si->additionalInfo = ws_strdup_printf("\"%s\"", wmem_strbuf_get_str(wmem_new)); + proto_item_append_text(item, " => \"%s\"" , wmem_strbuf_get_str(wmem_new)); + } + ptvcursor_advance(cursor, length); +} + +/*** Request / Response helper functions */ +static void skinny_reqrep_add_request(ptvcursor_t *cursor, packet_info * pinfo, skinny_conv_info_t * skinny_conv, const int request_key) +{ + proto_tree *tree = ptvcursor_tree(cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(cursor); + skinny_req_resp_t *req_resp = NULL; + + if (!PINFO_FD_VISITED(pinfo)) { + req_resp = wmem_new0(wmem_file_scope(), skinny_req_resp_t); + req_resp->request_frame = pinfo->num; + req_resp->response_frame = 0; + req_resp->request_time = pinfo->abs_ts; + wmem_map_insert(skinny_conv->pending_req_resp, GINT_TO_POINTER(request_key), (void *)req_resp); + DPRINT(("SKINNY: setup_request: frame=%d add key=%d to map\n", pinfo->num, request_key)); + } + + req_resp = (skinny_req_resp_t *) wmem_map_lookup(skinny_conv->requests, GUINT_TO_POINTER(pinfo->num)); + if (req_resp && req_resp->response_frame) { + DPRINT(("SKINNY: show request in tree: frame/key=%d\n", pinfo->num)); + proto_item *it; + it = proto_tree_add_uint(tree, hf_skinny_response_in, tvb, 0, 0, req_resp->response_frame); + proto_item_set_generated(it); + } else { + DPRINT(("SKINNY: no request found for frame/key=%d\n", pinfo->num)); + } +} + + +static void skinny_reqrep_add_response(ptvcursor_t *cursor, packet_info * pinfo, skinny_conv_info_t * skinny_conv, const int request_key) +{ + proto_tree *tree = ptvcursor_tree(cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(cursor); + skinny_req_resp_t *req_resp = NULL; + + if (!PINFO_FD_VISITED(pinfo)) { + req_resp = (skinny_req_resp_t *) wmem_map_remove(skinny_conv->pending_req_resp, GINT_TO_POINTER(request_key)); + if (req_resp) { + DPRINT(("SKINNY: match request:%d with response:%d for key=%d\n", req_resp->request_frame, pinfo->num, request_key)); + req_resp->response_frame = pinfo->num; + wmem_map_insert(skinny_conv->requests, GUINT_TO_POINTER(req_resp->request_frame), (void *)req_resp); + wmem_map_insert(skinny_conv->responses, GUINT_TO_POINTER(pinfo->num), (void *)req_resp); + } else { + DPRINT(("SKINNY: no match found for response frame=%d and key=%d\n", pinfo->num, request_key)); + } + } + + req_resp = (skinny_req_resp_t *) wmem_map_lookup(skinny_conv->responses, GUINT_TO_POINTER(pinfo->num)); + if (req_resp && req_resp->request_frame) { + DPRINT(("SKINNY: show response in tree: frame/key=%d\n", pinfo->num)); + proto_item *it; + nstime_t ns; + it = proto_tree_add_uint(tree, hf_skinny_response_to, tvb, 0, 0, req_resp->request_frame); + proto_item_set_generated(it); + + nstime_delta(&ns, &pinfo->abs_ts, &req_resp->request_time); + it = proto_tree_add_time(tree, hf_skinny_response_time, tvb, 0, 0, &ns); + proto_item_set_generated(it); + } else { + DPRINT(("SKINNY: no response found for frame/key=%d\n", pinfo->num)); + } +} + +/*** Messages Handlers ***/ +/* [[[cog +cog.out(message_dissector_functions) +]]]*/ +/*[[[end]]]*/ + +typedef void (*message_handler) (ptvcursor_t * cursor, packet_info *pinfo, skinny_conv_info_t * skinny_conv); + +typedef struct _skinny_opcode_map_t { + uint32_t opcode; + message_handler handler; + skinny_message_type_t type; + const char *name; +} skinny_opcode_map_t; + +/* Messages Handler Array */ +/* [[[cog +cog.out('static const skinny_opcode_map_t skinny_opcode_map[] = {\n') +for message in skinny.message: + msg_type = "SKINNY_MSGTYPE_EVENT" + if message.msgtype == "request": + msg_type = "SKINNY_MSGTYPE_REQUEST" + if message.msgtype == "response" and message.request is not None: + msg_type = "SKINNY_MSGTYPE_RESPONSE" + cog.out(' {%-6s, %-47s, %-24s, "%s"},\n' %(message.opcode, message.gen_handler(), msg_type, message.name)) +cog.out('};\n') +]]]*/ +/*[[[end]]]*/ + +/* Dissect a single SKINNY PDU */ +static int dissect_skinny_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + unsigned offset = 0; + /*bool is_video = false;*/ /* FIX ME: need to indicate video or not */ + ptvcursor_t* cursor; + conversation_t *conversation; + skinny_conv_info_t *skinny_conv; + const skinny_opcode_map_t *opcode_entry = NULL; + + /* Header fields */ + uint32_t hdr_data_length; + uint32_t hdr_version; + uint32_t hdr_opcode; + uint16_t i; + + /* Set up structures we will need to add the protocol subtree and manage it */ + proto_tree *skinny_tree = NULL; + proto_item *ti = NULL; + + /* Initialization */ + hdr_data_length = tvb_get_letohl(tvb, 0); + hdr_version = tvb_get_letohl(tvb, 4); + hdr_opcode = tvb_get_letohl(tvb, 8); + + for (i = 0; i < sizeof(skinny_opcode_map)/sizeof(skinny_opcode_map_t) ; i++) { + if (skinny_opcode_map[i].opcode == hdr_opcode) { + opcode_entry = &skinny_opcode_map[i]; + } + } + + conversation = find_or_create_conversation(pinfo); + skinny_conv = (skinny_conv_info_t *)conversation_get_proto_data(conversation, proto_skinny); + if (!skinny_conv) { + skinny_conv = wmem_new0(wmem_file_scope(), skinny_conv_info_t); + //skinny_conv->pending_req_resp = wmem_map_new(wmem_file_scope(), wmem_str_hash, g_str_equal); + skinny_conv->pending_req_resp = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + skinny_conv->requests = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + skinny_conv->responses = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + skinny_conv->lineId = -1; + skinny_conv->mtype = SKINNY_MSGTYPE_EVENT; + conversation_add_proto_data(conversation, proto_skinny, skinny_conv); + } + + /* Initialise stat info for passing to tap */ + /* WIP: will be (partially) replaced in favor of conversionation, dependents: ui/voip_calls.c */ + pi_current++; + if (pi_current == MAX_SKINNY_MESSAGES_IN_PACKET) + { + /* Overwrite info in first struct if run out of space... */ + pi_current = 0; + } + si = &pi_arr[pi_current]; + si->messId = hdr_opcode; + si->messageName = val_to_str_ext(hdr_opcode, &message_id_ext, "0x%08X (Unknown)"); + si->callId = 0; + si->lineId = 0; + si->passThroughPartyId = 0; + si->callState = 0; + g_free(si->callingParty); + si->callingParty = NULL; + g_free(si->calledParty); + si->calledParty = NULL; + si->mediaReceptionStatus = -1; + si->mediaTransmissionStatus = -1; + si->multimediaReceptionStatus = -1; + si->multimediaTransmissionStatus = -1; + si->multicastReceptionStatus = -1; + g_free(si->additionalInfo); + si->additionalInfo = NULL; + + col_add_fstr(pinfo->cinfo, COL_INFO,"%s ", si->messageName); + col_set_fence(pinfo->cinfo, COL_INFO); + + if (tree) { + ti = proto_tree_add_item(tree, proto_skinny, tvb, offset, hdr_data_length+8, ENC_NA); + skinny_tree = proto_item_add_subtree(ti, ett_skinny); + } + + if (opcode_entry && opcode_entry->type != SKINNY_MSGTYPE_EVENT) { + skinny_conv->mtype = opcode_entry->type; + if (opcode_entry->type == SKINNY_MSGTYPE_REQUEST) { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY/REQ"); + } else { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY/RESP"); + } + } + + if (skinny_tree) { + proto_tree_add_uint(skinny_tree, hf_skinny_data_length, tvb, offset , 4, hdr_data_length); + proto_tree_add_uint(skinny_tree, hf_skinny_hdr_version, tvb, offset+4, 4, hdr_version); + proto_tree_add_uint(skinny_tree, hf_skinny_messageId, tvb, offset+8, 4, hdr_opcode ); + } + offset += 12; + + cursor = ptvcursor_new(pinfo->pool, skinny_tree, tvb, offset); + if (opcode_entry && opcode_entry->handler) { + opcode_entry->handler(cursor, pinfo, skinny_conv); + } + ptvcursor_free(cursor); + + tap_queue_packet(skinny_tap, pinfo, si); + + return tvb_captured_length(tvb); +} + +/* Code to actually dissect the packets */ +static int +dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + /* The general structure of a packet: {IP-Header|TCP-Header|n*SKINNY} + * SKINNY-Packet: {Header(Size, Reserved)|Data(MessageID, Message-Data)} + */ + /* Header fields */ + uint32_t hdr_data_length; + uint32_t hdr_version; + + /* check, if this is really an SKINNY packet, they start with a length + 0 */ + + if (tvb_captured_length(tvb) < 8) + { + return 0; + } + /* get relevant header information */ + hdr_data_length = tvb_get_letohl(tvb, 0); + hdr_version = tvb_get_letohl(tvb, 4); + + /* data_size = MIN(8+hdr_data_length, tvb_length(tvb)) - 0xC; */ + + if ( + (hdr_data_length < 4) || + ((hdr_version != BASIC_MSG_TYPE) && + (hdr_version != V10_MSG_TYPE) && + (hdr_version != V11_MSG_TYPE) && + (hdr_version != V15_MSG_TYPE) && + (hdr_version != V16_MSG_TYPE) && + (hdr_version != V17_MSG_TYPE) && + (hdr_version != V18_MSG_TYPE) && + (hdr_version != V19_MSG_TYPE) && + (hdr_version != V20_MSG_TYPE) && + (hdr_version != V21_MSG_TYPE) && + (hdr_version != V22_MSG_TYPE)) + ) + { + /* Not an SKINNY packet, just happened to use the same port */ + return 0; + } + + /* Make entries in Protocol column and Info column on summary display */ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY"); + + col_set_str(pinfo->cinfo, COL_INFO, "Skinny Client Control Protocol"); + + tcp_dissect_pdus(tvb, pinfo, tree, global_skinny_desegment, 4, get_skinny_pdu_len, dissect_skinny_pdu, data); + + return tvb_captured_length(tvb); +} + +/* Register the protocol with Wireshark */ +void +proto_register_skinny(void) +{ + /* Setup list of header fields */ + static hf_register_info hf[] = { + { &hf_skinny_data_length, + { + "Data length", "skinny.data_length", FT_UINT32, BASE_DEC, NULL, 0x0, + "Number of bytes in the data portion.", HFILL }}, + { &hf_skinny_hdr_version, + { + "Header version", "skinny.hdr_version", FT_UINT32, BASE_HEX, VALS(header_version), 0x0, + NULL, HFILL }}, + { &hf_skinny_messageId, + { + "Message ID", "skinny.messageId", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &message_id_ext, 0x0, + NULL, HFILL }}, + { &hf_skinny_xmlData, + { + "XML data", "skinny.xmlData", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_skinny_ipv4or6, + { + "IPv4or6", "skinny.ipv4or6", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &IpAddrType_ext, 0x0, + NULL, HFILL }}, + { &hf_skinny_response_in, + { + "Response In", "skinny.response_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, + "The response to this SKINNY request is in this frame", HFILL }}, + { &hf_skinny_response_to, + { + "Request In", "skinny.response_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, + "This is a response to the SKINNY request in this frame", HFILL }}, + { &hf_skinny_response_time, + { + "Response Time", "skinny.response_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, + "The time between the Call and the Reply", HFILL }}, + /* [[[cog + for valuestr in sorted(xml2skinny.fieldsArray.values()): + cog.out('%s' %valuestr) + ]]]*/ + /*[[[end]]]*/ + }; + + /* Setup protocol subtree array */ + static int *ett[] = { + &ett_skinny, + &ett_skinny_tree, + }; + + module_t *skinny_module; + + /* Register the protocol name and description */ + proto_skinny = proto_register_protocol("Skinny Client Control Protocol", + "SKINNY", "skinny"); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_skinny, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + skinny_module = prefs_register_protocol(proto_skinny, NULL); + prefs_register_bool_preference(skinny_module, "desegment", + "Reassemble SKINNY messages spanning multiple TCP segments", + "Whether the SKINNY dissector should reassemble messages spanning multiple TCP segments." + " To use this option, you must also enable" + " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", + &global_skinny_desegment); + + skinny_handle = register_dissector("skinny", dissect_skinny, proto_skinny); + + skinny_tap = register_tap("skinny"); +} + +void +proto_reg_handoff_skinny(void) +{ + /* Skinny content type and internet media type used by other dissectors are the same */ + xml_handle = find_dissector_add_dependency("xml", proto_skinny); + dissector_add_uint_with_preference("tcp.port", TCP_PORT_SKINNY, skinny_handle); + ssl_dissector_add(SSL_PORT_SKINNY, skinny_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */ |