2013-10-28 20:07:58 +00:00
|
|
|
/* 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
|
|
|
|
*
|
2018-02-12 11:23:27 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2013-10-28 20:07:58 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <epan/packet.h>
|
2014-12-20 21:23:59 +00:00
|
|
|
#include "packet-usb.h"
|
2013-10-28 20:07:58 +00:00
|
|
|
|
|
|
|
/* defines */
|
2016-10-07 20:25:01 +00:00
|
|
|
#define tfp_PORT 4223 /* Not IANA registered */
|
2013-10-28 20:07:58 +00:00
|
|
|
|
|
|
|
#define tfp_USB_VENDOR_ID 0x16D0
|
|
|
|
#define tfp_USB_PRODUCT_ID 0x063D
|
|
|
|
|
|
|
|
#define BASE58_MAX_STR_SIZE 13
|
|
|
|
|
2013-12-10 21:30:13 +00:00
|
|
|
void proto_reg_handoff_tfp(void);
|
|
|
|
void proto_register_tfp(void);
|
|
|
|
|
2013-10-28 20:07:58 +00:00
|
|
|
/* 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]);
|
2019-04-03 21:32:30 +00:00
|
|
|
proto_item_set_generated(ti);
|
2013-10-28 20:07:58 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-11-03 11:19:10 +00:00
|
|
|
/*bit_offset += bit_count_tfp_future_use;*/
|
2013-10-28 20:07:58 +00:00
|
|
|
|
|
|
|
if ((tvb_reported_length(tvb)) > 8) {
|
|
|
|
|
|
|
|
byte_offset += byte_count_tfp_flags;
|
|
|
|
|
2013-11-12 13:46:51 +00:00
|
|
|
proto_tree_add_item(tfp_tree, hf_tfp_payload, tvb, byte_offset, -1, ENC_NA);
|
2013-10-28 20:07:58 +00:00
|
|
|
}
|
2013-11-12 13:46:51 +00:00
|
|
|
}
|
2013-10-28 20:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* dissector function for dissecting TCP payloads */
|
2015-11-18 01:16:06 +00:00
|
|
|
static int
|
|
|
|
dissect_tfp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
2013-10-28 20:07:58 +00:00
|
|
|
{
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFP over TCP");
|
2013-11-12 13:46:51 +00:00
|
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
2013-10-28 20:07:58 +00:00
|
|
|
|
|
|
|
dissect_tfp_common(tvb, pinfo, tree);
|
2015-11-18 01:16:06 +00:00
|
|
|
return tvb_captured_length(tvb);
|
2013-10-28 20:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* dissector function for dissecting USB payloads */
|
2013-11-12 13:46:51 +00:00
|
|
|
static gboolean
|
|
|
|
dissect_tfp_bulk_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
2013-10-28 20:07:58 +00:00
|
|
|
{
|
2013-11-12 13:46:51 +00:00
|
|
|
usb_conv_info_t *usb_conv_info = (usb_conv_info_t *)data;
|
2013-10-28 20:07:58 +00:00
|
|
|
|
2013-11-12 13:46:51 +00:00
|
|
|
if ((usb_conv_info != NULL) &&
|
|
|
|
(usb_conv_info->deviceVendor == tfp_USB_VENDOR_ID) &&
|
|
|
|
(usb_conv_info->deviceProduct == tfp_USB_PRODUCT_ID)) {
|
2013-10-28 20:07:58 +00:00
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFP over USB");
|
2013-11-12 13:46:51 +00:00
|
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
|
|
|
dissect_tfp_common(tvb, pinfo, tree);
|
|
|
|
return TRUE;
|
2013-10-28 20:07:58 +00:00
|
|
|
}
|
2013-11-12 13:46:51 +00:00
|
|
|
|
|
|
|
return FALSE;
|
2013-10-28 20:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
|
2013-11-12 13:46:51 +00:00
|
|
|
dissector_handle_t tfp_handle_tcp;
|
2013-10-28 20:07:58 +00:00
|
|
|
|
2015-12-09 03:49:44 +00:00
|
|
|
tfp_handle_tcp = create_dissector_handle(dissect_tfp_tcp, proto_tfp);
|
2013-10-28 20:07:58 +00:00
|
|
|
|
2016-10-07 20:25:01 +00:00
|
|
|
dissector_add_uint_with_preference("tcp.port", tfp_PORT, tfp_handle_tcp);
|
2015-07-13 00:40:31 +00:00
|
|
|
heur_dissector_add("usb.bulk", dissect_tfp_bulk_heur, "Tinkerforge USB bulk endpoint", "tfp_usb_bulk", proto_tfp, HEURISTIC_ENABLE);
|
2013-10-28 20:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Editor modelines - http://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:
|
|
|
|
*/
|