wireshark/epan/dissectors/packet-tfp.c

420 lines
8.7 KiB
C

/* packet-tfp.c
* Routines for Tinkerforge protocol packet disassembly
* By Ishraq Ibne Ashraf <ishraq@tinkerforge.com>
* Copyright 2013 Ishraq Ibne Ashraf
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <epan/packet.h>
#include "packet-usb.h"
/* defines */
#define tfp_PORT 4223 /* Not IANA registered */
#define tfp_USB_VENDOR_ID 0x16D0
#define tfp_USB_PRODUCT_ID 0x063D
#define BASE58_MAX_STR_SIZE 13
void proto_reg_handoff_tfp(void);
void proto_register_tfp(void);
/* variables for creating the tree */
static gint proto_tfp = -1;
static gint ett_tfp = -1;
/* header field variables */
static gint hf_tfp_uid = -1;
static gint hf_tfp_uid_numeric = -1;
static gint hf_tfp_len = -1;
static gint hf_tfp_fid = -1;
static gint hf_tfp_seq = -1;
static gint hf_tfp_r = -1;
static gint hf_tfp_a = -1;
static gint hf_tfp_oo = -1;
static gint hf_tfp_e = -1;
static gint hf_tfp_future_use = -1;
static gint hf_tfp_payload = -1;
/* bit and byte offsets for dissection */
static const gint byte_offset_len = 4;
static const gint byte_offset_fid = 5;
static const gint byte_count_tfp_uid = 4;
static const gint byte_count_tfp_len = 1;
static const gint byte_count_tfp_fid = 1;
static const gint byte_count_tfp_flags = 2;
static const gint bit_count_tfp_seq = 4;
static const gint bit_count_tfp_r = 1;
static const gint bit_count_tfp_a = 1;
static const gint bit_count_tfp_oo = 2;
static const gint bit_count_tfp_e = 2;
static const gint bit_count_tfp_future_use = 6;
/* base58 encoding variable */
static const char BASE58_ALPHABET[] =
"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
/* function for encoding a number to base58 string */
static void
base58_encode(guint32 value, char *str) {
guint32 mod;
gint i = 0;
gint k;
gchar reverse_str[BASE58_MAX_STR_SIZE] = {'\0'};
while (value >= 58) {
mod = value % 58;
reverse_str[i] = BASE58_ALPHABET[mod];
value = value / 58;
++i;
}
reverse_str[i] = BASE58_ALPHABET[value];
for (k = 0; k <= i; k++) {
str[k] = reverse_str[i - k];
}
for (; k < BASE58_MAX_STR_SIZE; k++) {
str[k] = '\0';
}
}
/* common dissector function for dissecting TFP payloads */
static void
dissect_tfp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
gint byte_offset = 0;
gint bit_offset = 48;
guint8 hv_tfp_len;
guint8 hv_tfp_fid;
guint8 hv_tfp_seq;
gchar tfp_uid_string[BASE58_MAX_STR_SIZE];
base58_encode(tvb_get_letohl(tvb, 0), &tfp_uid_string[0]);
hv_tfp_len = tvb_get_guint8(tvb, byte_offset_len);
hv_tfp_fid = tvb_get_guint8(tvb, byte_offset_fid);
hv_tfp_seq = tvb_get_bits8(tvb, bit_offset, bit_count_tfp_seq);
col_add_fstr(pinfo->cinfo, COL_INFO,
"UID: %s, Len: %d, FID: %d, Seq: %d",
&tfp_uid_string[0], hv_tfp_len, hv_tfp_fid, hv_tfp_seq);
/* call for details */
if (tree) {
proto_tree *tfp_tree;
proto_item *ti;
ti = proto_tree_add_protocol_format(tree, proto_tfp, tvb, 0, -1,
"Tinkerforge Protocol, UID: %s, Len: %d, FID: %d, Seq: %d",
&tfp_uid_string[0], hv_tfp_len, hv_tfp_fid, hv_tfp_seq);
tfp_tree = proto_item_add_subtree(ti, ett_tfp);
/* Use ...string_format_value() so we can show the complete generated string but specify */
/* the field length as being just the 4 bytes from which the string is generated. */
ti = proto_tree_add_string_format_value(tfp_tree,
hf_tfp_uid,
tvb, byte_offset, byte_count_tfp_uid,
&tfp_uid_string[0], "%s", &tfp_uid_string[0]);
proto_item_set_generated(ti);
proto_tree_add_item(tfp_tree,
hf_tfp_uid_numeric,
tvb,
byte_offset,
byte_count_tfp_uid,
ENC_LITTLE_ENDIAN);
byte_offset += byte_count_tfp_uid;
proto_tree_add_item(tfp_tree,
hf_tfp_len,
tvb,
byte_offset,
byte_count_tfp_len,
ENC_LITTLE_ENDIAN);
byte_offset += byte_count_tfp_len;
proto_tree_add_item(tfp_tree,
hf_tfp_fid,
tvb,
byte_offset,
byte_count_tfp_fid,
ENC_LITTLE_ENDIAN);
byte_offset += byte_count_tfp_fid;
proto_tree_add_bits_item(tfp_tree,
hf_tfp_seq,
tvb,
bit_offset,
bit_count_tfp_seq,
ENC_LITTLE_ENDIAN);
bit_offset += bit_count_tfp_seq;
proto_tree_add_bits_item(tfp_tree,
hf_tfp_r,
tvb,
bit_offset,
bit_count_tfp_r,
ENC_LITTLE_ENDIAN);
bit_offset += bit_count_tfp_r;
proto_tree_add_bits_item(tfp_tree,
hf_tfp_a,
tvb,
bit_offset,
bit_count_tfp_a,
ENC_LITTLE_ENDIAN);
bit_offset += bit_count_tfp_a;
proto_tree_add_bits_item(tfp_tree,
hf_tfp_oo,
tvb,
bit_offset,
bit_count_tfp_oo,
ENC_LITTLE_ENDIAN);
bit_offset += bit_count_tfp_oo;
proto_tree_add_bits_item(tfp_tree,
hf_tfp_e,
tvb,
bit_offset,
bit_count_tfp_e,
ENC_LITTLE_ENDIAN);
bit_offset += bit_count_tfp_e;
proto_tree_add_bits_item(tfp_tree,
hf_tfp_future_use,
tvb,
bit_offset,
bit_count_tfp_future_use,
ENC_LITTLE_ENDIAN);
/*bit_offset += bit_count_tfp_future_use;*/
if ((tvb_reported_length(tvb)) > 8) {
byte_offset += byte_count_tfp_flags;
proto_tree_add_item(tfp_tree, hf_tfp_payload, tvb, byte_offset, -1, ENC_NA);
}
}
}
/* dissector function for dissecting TCP payloads */
static int
dissect_tfp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFP over TCP");
col_clear(pinfo->cinfo, COL_INFO);
dissect_tfp_common(tvb, pinfo, tree);
return tvb_captured_length(tvb);
}
/* dissector function for dissecting USB payloads */
static gboolean
dissect_tfp_bulk_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
usb_conv_info_t *usb_conv_info = (usb_conv_info_t *)data;
if ((usb_conv_info != NULL) &&
(usb_conv_info->deviceVendor == tfp_USB_VENDOR_ID) &&
(usb_conv_info->deviceProduct == tfp_USB_PRODUCT_ID)) {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFP over USB");
col_clear(pinfo->cinfo, COL_INFO);
dissect_tfp_common(tvb, pinfo, tree);
return TRUE;
}
return FALSE;
}
/* protocol register function */
void
proto_register_tfp(void)
{
/* defining header formats */
static hf_register_info hf_tfp[] = {
{ &hf_tfp_uid,
{ "UID (String)",
"tfp.uid",
FT_STRINGZ,
BASE_NONE,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_uid_numeric,
{ "UID (Numeric)",
"tfp.uid_numeric",
FT_UINT32,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_len,
{ "Length",
"tfp.len",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_fid,
{ "Function ID",
"tfp.fid",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_seq,
{ "Sequence Number",
"tfp.seq",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_r,
{ "Response Expected",
"tfp.r",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_a,
{ "Authentication",
"tfp.a",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_oo,
{ "Other Options",
"tfp.oo",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_e,
{ "Error Code",
"tfp.e",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_future_use,
{ "Future Use",
"tfp.future_use",
FT_UINT8,
BASE_DEC,
NULL,
0x0,
NULL,
HFILL
}
},
{ &hf_tfp_payload,
{ "Payload",
"tfp.payload",
FT_BYTES,
BASE_NONE,
NULL,
0x0,
NULL,
HFILL
}
}
};
/* setup protocol subtree array */
static gint *ett[] = {
&ett_tfp
};
/* defining the protocol and its names */
proto_tfp = proto_register_protocol (
"Tinkerforge Protocol",
"TFP",
"tfp"
);
proto_register_field_array(proto_tfp, hf_tfp, array_length(hf_tfp));
proto_register_subtree_array(ett, array_length(ett));
}
/* handoff function */
void
proto_reg_handoff_tfp(void) {
dissector_handle_t tfp_handle_tcp;
tfp_handle_tcp = create_dissector_handle(dissect_tfp_tcp, proto_tfp);
dissector_add_uint_with_preference("tcp.port", tfp_PORT, tfp_handle_tcp);
heur_dissector_add("usb.bulk", dissect_tfp_bulk_heur, "Tinkerforge USB bulk endpoint", "tfp_usb_bulk", proto_tfp, HEURISTIC_ENABLE);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/