summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-skinny.c.in
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-skinny.c.in
parentInitial commit. (diff)
downloadwireshark-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.in675
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:
+ */