wireshark/epan/dissectors/packet-skinny.c.in

674 lines
23 KiB
C

/* 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 gint ett_skinny = -1;
static gint 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 guint
get_skinny_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
{
guint32 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, guint32 length, guint32 maxlength)
{
proto_item *item = NULL;
proto_tree *subtree = NULL;
proto_tree *tree = ptvcursor_tree(cursor);
guint32 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|ENC_NA);
item = proto_tree_add_item(tree, hf_skinny_xmlData, tvb, offset, length, ENC_ASCII|ENC_NA);
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)
{
guint32 ipversion = 0;
guint32 offset = ptvcursor_current_offset(cursor);
tvbuff_t *tvb = ptvcursor_tvbuff(cursor);
guint32 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)
{
guint32 ipversion = IPADDRTYPE_IPV4;
guint32 offset = ptvcursor_current_offset(cursor);
guint32 offset2 = 0;
tvbuff_t *tvb = ptvcursor_tvbuff(cursor);
guint32 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, gint length)
{
proto_item *item = NULL;
proto_tree *tree = ptvcursor_tree(cursor);
guint32 offset = ptvcursor_current_offset(cursor);
tvbuff_t *tvb = ptvcursor_tvbuff(cursor);
wmem_strbuf_t *wmem_new = NULL;
gchar *disp_string = NULL;
const gchar *replacestr = NULL;
gboolean show_replaced_str = FALSE;
gint 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 | ENC_NA);
wmem_new = wmem_strbuf_sized_new(pinfo->pool, length + 1, 0);
disp_string = (gchar*) 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 {
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 {
guint32 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_)
{
guint offset = 0;
/*gboolean 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 */
guint32 hdr_data_length;
guint32 hdr_version;
guint32 hdr_opcode;
guint16 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 */
guint32 hdr_data_length;
guint32 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 gint *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:
*/