summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-linx.c
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-linx.c
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-linx.c')
-rw-r--r--epan/dissectors/packet-linx.c1072
1 files changed, 1072 insertions, 0 deletions
diff --git a/epan/dissectors/packet-linx.c b/epan/dissectors/packet-linx.c
new file mode 100644
index 00000000..8ba4b804
--- /dev/null
+++ b/epan/dissectors/packet-linx.c
@@ -0,0 +1,1072 @@
+/* packet-linx.c
+ * Routines for LINX packet dissection
+ *
+ * Copyright 2006, Martin Peylo <martin.peylo@siemens.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/* The used document is:
+ * ENEA Link Protocol Specification available at
+ * http://linx.sourceforge.net
+ *
+ * Fits currently to
+ * Enea LINX for Linux
+ * Version: 2.5.0, May 16, 2011
+ *
+ * Added support for LINX ETHCM version 3 and LINX RLNH version 2.
+ * Mattias Wallin, linx@enea.com, September 23, 2007
+ *
+ * Added support for LINX TCP CM.
+ * Dejan Bucar, linx@enea.com, June 21, 2011
+ *
+ * Added support for LINX ETHCM Multicore header.
+ * Dejan Bucar, linx@enea.com, June 21, 2011
+*/
+
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/expert.h>
+#include <epan/etypes.h>
+
+void proto_register_linx(void);
+void proto_reg_handoff_linx(void);
+void proto_register_linx_tcp(void);
+void proto_reg_handoff_linx_tcp(void);
+
+static dissector_handle_t linx_handle;
+
+static int proto_linx = -1;
+static int proto_linx_tcp = -1;
+
+/* ALL */
+static int hf_linx_nexthdr = -1;
+
+/* MULTICORE */
+static int hf_linx_multicore_scoreid = -1;
+static int hf_linx_multicore_dcoreid = -1;
+static int hf_linx_multicore_reserved = -1;
+static int hf_linx_multicore_reserved1 = -1;
+
+
+/* MAIN */
+static int hf_linx_main_version = -1;
+static int hf_linx_main_reserved = -1;
+static int hf_linx_main_connection = -1;
+static int hf_linx_main_bundle = -1;
+static int hf_linx_main_pkgsize = -1;
+
+/* UDATA */
+static int hf_linx_udata_reserved = -1;
+static int hf_linx_udata_morefrags = -1;
+static int hf_linx_udata_fragno = -1;
+static int hf_linx_udata_signo = -1;
+static int hf_linx_udata_dstaddr16 = -1;
+static int hf_linx_udata_dstaddr32 = -1;
+static int hf_linx_udata_srcaddr16 = -1;
+static int hf_linx_udata_srcaddr32 = -1;
+static int hf_linx_udata_payload = -1;
+
+/* ACK */
+static int hf_linx_ack_reserved = -1;
+static int hf_linx_ack_request = -1;
+static int hf_linx_ack_ackno = -1;
+static int hf_linx_ack_seqno = -1;
+
+/* CONN */
+static int hf_linx_conn_cmd = -1;
+static int hf_linx_conn_size = -1;
+static int hf_linx_conn_reserved = -1;
+static int hf_linx_conn_srcmac = -1;
+static int hf_linx_conn_dstmac = -1;
+static int hf_linx_conn_winsize = -1;
+static int hf_linx_conn_publcid = -1;
+static int hf_linx_conn_feat_neg_str = -1;
+/* FRAG */
+static int hf_linx_frag_reserved = -1;
+static int hf_linx_frag_morefrags = -1;
+static int hf_linx_frag_fragno = -1;
+
+/* NACK */
+static int hf_linx_nack_reserv1 = -1;
+static int hf_linx_nack_reserv2 = -1;
+static int hf_linx_nack_count = -1;
+static int hf_linx_nack_seqno = -1;
+
+/* RLNH */
+static int hf_linx_rlnh_msg_type32 = -1;
+static int hf_linx_rlnh_msg_type8 = -1;
+/* static int hf_linx_rlnh_linkaddr = -1; */
+static int hf_linx_rlnh_src_linkaddr = -1;
+static int hf_linx_rlnh_version = -1;
+static int hf_linx_rlnh_status = -1;
+static int hf_linx_rlnh_name = -1;
+static int hf_linx_rlnh_peer_linkaddr = -1;
+static int hf_linx_rlnh_feat_neg_str = -1;
+static int hf_linx_rlnh_msg_reserved = -1;
+
+/* TCP CM */
+/* static int hf_linx_tcp_reserved = -1; */
+static int hf_linx_tcp_oob = -1;
+static int hf_linx_tcp_version = -1;
+static int hf_linx_tcp_type = -1;
+static int hf_linx_tcp_src = -1;
+static int hf_linx_tcp_dst = -1;
+static int hf_linx_tcp_size = -1;
+static int hf_linx_tcp_rlnh_msg_type32 = -1;
+static int hf_linx_tcp_rlnh_msg_type8 = -1;
+/* static int hf_linx_tcp_rlnh_linkaddr = -1; */
+static int hf_linx_tcp_rlnh_src_linkaddr = -1;
+static int hf_linx_tcp_rlnh_version = -1;
+static int hf_linx_tcp_rlnh_status = -1;
+static int hf_linx_tcp_rlnh_name = -1;
+static int hf_linx_tcp_rlnh_peer_linkaddr = -1;
+static int hf_linx_tcp_rlnh_feat_neg_str = -1;
+static int hf_linx_tcp_rlnh_msg_reserved = -1;
+static int hf_linx_tcp_payload = -1;
+
+
+static int rlnh_version = 0;
+
+static gint ett_linx = -1;
+static gint ett_linx_multicore = -1;
+static gint ett_linx_main = -1;
+static gint ett_linx_error = -1;
+static gint ett_linx_udata = -1;
+static gint ett_linx_ack = -1;
+static gint ett_linx_tcp = -1;
+
+static expert_field ei_linx_version = EI_INIT;
+static expert_field ei_linx_rlnh_msg = EI_INIT;
+static expert_field ei_linx_header = EI_INIT;
+
+static expert_field ei_linx_tcp_version = EI_INIT;
+static expert_field ei_linx_tcp_rlnh_msg = EI_INIT;
+
+
+
+/* Definition and Names */
+
+#define ETHCM_MAIN 0x0
+#define ETHCM_CONN 0x1
+#define ETHCM_UDATA 0x2
+#define ETHCM_FRAG 0x3
+#define ETHCM_ACK 0x4
+#define ETHCM_NACK 0x5
+#define ETHCM_NONE 0xf
+
+static const value_string linx_short_header_names[]={
+ { ETHCM_MAIN, "MAIN"},
+ { ETHCM_CONN, "CONN"},
+ { ETHCM_UDATA, "UDATA"},
+ { ETHCM_FRAG, "FRAG"},
+ { ETHCM_ACK, "ACK"},
+ { ETHCM_NACK, "NACK"},
+ { ETHCM_NONE, "NONE"},
+ { 0, NULL}
+};
+
+static const value_string linx_long_header_names[] = {
+ { ETHCM_MAIN, "Main"},
+ { ETHCM_CONN, "Connection"},
+ { ETHCM_UDATA, "Udata"},
+ { ETHCM_FRAG, "Fragmentation"},
+ { ETHCM_ACK, "Ack"},
+ { ETHCM_NACK, "Nack"},
+ { ETHCM_NONE, "None"},
+ { 0, NULL}
+};
+
+#define TCP_CM_CONN 0x43
+#define TCP_CM_UDATA 0x55
+#define TCP_CM_PING 0x50
+#define TCP_CM_PONG 0x51
+
+static const value_string linx_short_tcp_names[] = {
+ {TCP_CM_CONN, "conn"},
+ {TCP_CM_UDATA, "udata"},
+ {TCP_CM_PING, "ping"},
+ {TCP_CM_PONG, "pong"},
+ {0, NULL}
+};
+
+static const value_string linx_long_tcp_names[] = {
+ {TCP_CM_CONN, "Connection msg"},
+ {TCP_CM_UDATA, "User data"},
+ {TCP_CM_PING, "Ping msg"},
+ {TCP_CM_PONG, "Pong msg"},
+ {0, NULL}
+};
+
+/* RLNH version 1 */
+#define RLNH_LINK_ADDR 0
+#define RLNH_QUERY_NAME 1
+#define RLNH_PUBLISH 2
+#define RLNH_UNPUBLISH 3
+#define RLNH_UNPUBLISH_ACK 4
+#define RLNH_INIT 5
+#define RLNH_INIT_REPLY 6
+#define RLNH_PUBLISH_PEER 7
+
+static const value_string linx_short_rlnh_names[]={
+ { RLNH_LINK_ADDR, "link_addr"},
+ { RLNH_QUERY_NAME, "query_name"},
+ { RLNH_PUBLISH, "publish"},
+ { RLNH_UNPUBLISH, "unpublish"},
+ { RLNH_UNPUBLISH_ACK, "unpublish_ack"},
+ { RLNH_INIT, "init"},
+ { RLNH_INIT_REPLY, "init_reply"},
+ { RLNH_PUBLISH_PEER, "publish_peer"},
+ { 0, NULL}
+};
+
+static const value_string linx_long_rlnh_names[]={
+ { RLNH_LINK_ADDR, "Link Address"},
+ { RLNH_QUERY_NAME, "Query Name"},
+ { RLNH_PUBLISH, "Publish"},
+ { RLNH_UNPUBLISH, "Unpublish"},
+ { RLNH_UNPUBLISH_ACK, "Unpublish Ack"},
+ { RLNH_INIT, "Init"},
+ { RLNH_INIT_REPLY, "Init Reply"},
+ { RLNH_PUBLISH_PEER, "Publish Peer"},
+ { 0, NULL}
+};
+
+static const value_string linx_rlnh_reply[] = {
+ { 0, "Version supported"},
+ { 1, "Version NOT supported"},
+ { 0, NULL}
+};
+
+static const value_string linx_nofragment[] = {
+ { 0x7fff, "No Fragment"},
+ { 0, NULL}
+};
+
+static const value_string linx_coreid[]= {
+ {0xff, "None"},
+ {0, NULL}
+};
+
+#define CONN_RESET 1
+#define CONN_CONNECT 2
+#define CONN_CONNECT_ACK 3
+#define CONN_ACK 4
+
+static const value_string linx_conn_cmd[] = {
+ { CONN_RESET, "Reset"},
+ { CONN_CONNECT, "Connect"},
+ { CONN_CONNECT_ACK, "Connect_Ack"},
+ { CONN_ACK, "Ack"},
+ { 0, NULL}
+};
+
+static int
+dissect_linx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ guint32 dword;
+ int offset = 0;
+ int nexthdr;
+ int thishdr;
+ int size;
+ int pkgsize;
+ int payloadsize;
+ int version;
+ int conntype;
+ proto_tree *multicore_header_tree;
+ proto_tree *main_header_tree;
+ proto_tree *conn_header_tree;
+ proto_tree *ack_header_tree;
+ proto_tree *udata_header_tree;
+ proto_tree *nack_header_tree;
+ proto_tree *frag_header_tree;
+ proto_tree *rlnh_header_tree;
+
+ /* Show name in protocol column */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "LINX");
+ /* Clear out stuff in the info column */
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ { /* Work out the details */
+ proto_item *ti = NULL;
+ proto_tree *linx_tree = NULL;
+ proto_item *ver_item, *msg_item;
+
+ ti = proto_tree_add_item(tree, proto_linx, tvb, 0, -1, ENC_NA);
+ linx_tree = proto_item_add_subtree(ti, ett_linx);
+
+ dword = tvb_get_ntohl(tvb, offset);
+ nexthdr = (dword >> 28) & 0xf;
+
+ /* check if we have multicore header*/
+ if (nexthdr == ETHCM_MAIN)
+ {
+ multicore_header_tree = proto_tree_add_subtree(linx_tree, tvb, 0, 4, ett_linx_multicore, NULL, "Multicore Header");
+
+ /* Multicore header */
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | R | Dest Coreid | Source Coreid | R |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ proto_tree_add_item(multicore_header_tree, hf_linx_nexthdr, tvb, 0, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(multicore_header_tree, hf_linx_multicore_reserved, tvb, 0, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(multicore_header_tree, hf_linx_multicore_dcoreid, tvb, 0, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(multicore_header_tree, hf_linx_multicore_scoreid, tvb, 0, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(multicore_header_tree, hf_linx_multicore_reserved1, tvb, 0, 4, ENC_BIG_ENDIAN);
+
+ offset += 4;
+ /* read main header*/
+ dword = tvb_get_ntohl(tvb, offset);
+ }
+
+ version = (dword >> 25) & 0x7;
+ nexthdr = (dword >> 28) & 0xf;
+ pkgsize = dword & 0x3fff;
+
+ /* Main header */
+ main_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "Main Header");
+
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | Ver | R | Connection |R| Packet size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ proto_tree_add_item(main_header_tree, hf_linx_nexthdr , tvb, offset, 4, ENC_BIG_ENDIAN);
+ ver_item = proto_tree_add_item(main_header_tree, hf_linx_main_version , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(main_header_tree, hf_linx_main_reserved , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(main_header_tree, hf_linx_main_connection, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(main_header_tree, hf_linx_main_bundle , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(main_header_tree, hf_linx_main_pkgsize , tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ /* Supports version 2 and 3 so far */
+ if (version < 2 || version > 3) {
+ expert_add_info(pinfo, ver_item, &ei_linx_version);
+ }
+
+ while (nexthdr != ETHCM_NONE) {
+
+ dword = tvb_get_ntohl(tvb, offset);
+ thishdr = nexthdr;
+ nexthdr = (dword >>28) & 0xf;
+ conntype = (dword >>24) & 0xf;
+ /* Write non trivial header name to info column */
+ if ((thishdr != ETHCM_NONE) && (thishdr != ETHCM_MAIN)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(thishdr, linx_short_header_names, "unknown"));
+ if(thishdr == ETHCM_CONN)
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(conntype, linx_conn_cmd, "unknown"));
+ }
+
+ switch (thishdr) {
+
+ case ETHCM_CONN:
+ /* Connect header */
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | Type |Size |Winsize| Reserved |Publish conn id|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : :
+ : dst hw addr followed by src hw addr :
+ : :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : :
+ : Feature negotiation string (null terminated) :
+ : :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ size = (dword >>21) & 0x7;
+ conn_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, (4+2*size), ett_linx_main, NULL, "Connection Header");
+ proto_tree_add_item(conn_header_tree, hf_linx_nexthdr , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_cmd , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_size , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_winsize , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_publcid , tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ /* MEDIA ADDRESS */
+ if (size == 6) {
+ /* Most likely ETHERNET */
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_dstmac, tvb, offset, 6, ENC_NA);
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_srcmac, tvb, offset + 6, 6, ENC_NA);
+ }
+
+ offset += (2*size);
+ /* Feature Negotiation String */
+ if(version > 2) {
+ proto_tree_add_item(conn_header_tree, hf_linx_conn_feat_neg_str, tvb, offset, -1, ENC_ASCII);
+ offset += tvb_strnlen(tvb, offset, -1);
+ }
+ break;
+
+ case ETHCM_NACK:
+ /* Nack header */
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | Res | Count | Res | Seqno |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ /* how many sequence numbers will be there? */
+ /* this is not implemented due to a lack of documentation with */
+ /* longer sequence numbers. */
+ /* guess there will be padding if the Seqno doesn't reach */
+ /* a 32bit boundary */
+
+ nack_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "NACK Header");
+ proto_tree_add_item(nack_header_tree, hf_linx_nexthdr , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(nack_header_tree, hf_linx_nack_reserv1, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(nack_header_tree, hf_linx_nack_count , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(nack_header_tree, hf_linx_nack_reserv2, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(nack_header_tree, hf_linx_nack_seqno , tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ break;
+
+ case ETHCM_UDATA:
+ /* User data / fragment header => Version 3 */
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | Reserved |M| Frag no |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Destination |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Source |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ * User data / fragment header => Version 2
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | Reserved |M| Frag no |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Dst | Src |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ - fragments (not first fragment)
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | Reserved |M| Frag no |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+
+ udata_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 12, ett_linx_main, NULL, "Udata Header");
+ proto_tree_add_item(udata_header_tree, hf_linx_nexthdr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_reserved , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_morefrags, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_fragno , tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ /* signo removed in version 3 and linkaddresses extended to 32 bits */
+ if(version == 2) {
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_signo , tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_dstaddr16, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_srcaddr16, tvb, offset, 4, ENC_BIG_ENDIAN);
+ dword = tvb_get_ntohl(tvb, offset);
+ } else {
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_dstaddr32, tvb, offset, 4, ENC_BIG_ENDIAN);
+ dword = tvb_get_ntohl(tvb, offset);
+ offset += 4;
+ proto_tree_add_item(udata_header_tree, hf_linx_udata_srcaddr32, tvb, offset, 4, ENC_BIG_ENDIAN);
+ if(dword == 0 && tvb_get_ntohl(tvb, offset) == 0) {
+ dword = 0;
+ } else {
+ dword = 1;
+ }
+ }
+ offset += 4;
+ if (dword == 0) {
+ /* (dstaddr == srcaddr == 0) -> RLNH Protocol Message */
+
+ dword = tvb_get_ntohl(tvb, offset);
+
+ /* Write to info column */
+ col_append_fstr(pinfo->cinfo, COL_INFO, "rlnh:%s ", val_to_str_const(dword, linx_short_rlnh_names, "unknown"));
+
+ /* create new paragraph for RLNH */
+ rlnh_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "RLNH");
+
+ if(version == 1) {
+ msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_msg_type32, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ } else {
+ /* in version 2 of the rlnh protocol the length of the message type is restricted to 8 bits */
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_msg_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
+ msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_msg_type8, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ }
+
+ switch (dword) {
+ case RLNH_LINK_ADDR:
+ /* XXX what is this? */
+ break;
+ case RLNH_QUERY_NAME:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_name, tvb, offset, -1, ENC_ASCII);
+ offset += tvb_strnlen(tvb, offset, -1);
+ break;
+ case RLNH_PUBLISH:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_name, tvb, offset, -1, ENC_ASCII);
+ offset += tvb_strnlen(tvb, offset, -1);
+ break;
+ case RLNH_UNPUBLISH:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ break;
+ case RLNH_UNPUBLISH_ACK:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ break;
+ case RLNH_INIT:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_version, tvb, offset, 4, ENC_BIG_ENDIAN);
+ /* This is not working if nodes are at different versions. Only the latest value will be saved in rlnh_version */
+ rlnh_version = tvb_get_ntohl(tvb, offset);
+ offset += 4;
+ break;
+ case RLNH_INIT_REPLY:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_status, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ if(rlnh_version > 1) {
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_feat_neg_str, tvb, offset, -1, ENC_ASCII);
+ offset += tvb_strnlen(tvb, offset, -1);
+ }
+ break;
+ case RLNH_PUBLISH_PEER:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_peer_linkaddr, tvb, offset, -1, ENC_BIG_ENDIAN);
+ offset += tvb_strnlen(tvb, offset, -1);
+ break;
+ default:
+ /* no known Message type... */
+ expert_add_info(pinfo, msg_item, &ei_linx_rlnh_msg);
+ break;
+ }
+ } else {
+ /* Is there payload? */
+ /* anything better to do with that? */
+ payloadsize = pkgsize-offset;
+ if (payloadsize) {
+ proto_tree_add_item(linx_tree, hf_linx_udata_payload, tvb, offset, payloadsize, ENC_NA);
+ }
+ }
+ break;
+
+ case ETHCM_ACK:
+ /* Reliable header */
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next |R| Res.| Ackno | Seqno |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ ack_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "Ack Header");
+ proto_tree_add_item(ack_header_tree, hf_linx_nexthdr , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(ack_header_tree, hf_linx_ack_request , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(ack_header_tree, hf_linx_ack_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(ack_header_tree, hf_linx_ack_ackno , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(ack_header_tree, hf_linx_ack_seqno , tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ break;
+
+ case ETHCM_FRAG:
+ /*
+ - fragments (not first fragment)
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next | Reserved |M| Frag no |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ frag_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "Fragmentation Header");
+ proto_tree_add_item(frag_header_tree, hf_linx_nexthdr , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(frag_header_tree, hf_linx_frag_reserved , tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(frag_header_tree, hf_linx_frag_morefrags, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(frag_header_tree, hf_linx_frag_fragno , tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ break;
+
+ default:
+ proto_tree_add_expert_format(linx_tree, pinfo, &ei_linx_header, tvb, offset, 4, "ERROR: Header \"%u\" not recognized", thishdr);
+ nexthdr = ETHCM_NONE; /* avoid endless loop with faulty packages */
+ break;
+ }
+ }
+
+ }
+ return tvb_captured_length(tvb);
+}
+
+
+/* Protocol Initialisation */
+void
+proto_register_linx(void)
+{
+
+ /* Registering Data Structures */
+
+ static hf_register_info hf[] = {
+ { &hf_linx_nexthdr,
+ { "Next Header", "linx.nexthdr", FT_UINT32, BASE_DEC, VALS(linx_long_header_names), 0xf0000000, NULL, HFILL },
+ },
+ { &hf_linx_multicore_scoreid, /* in ETHCM_MULTICORE */
+ { "Source coreid", "linx.scoreid", FT_UINT32, BASE_DEC, VALS(linx_coreid), 0x0000ff00, "Multicore source core id", HFILL },
+ },
+ { &hf_linx_multicore_dcoreid, /* in ETHCM_MULTICORE */
+ { "Destination coreid", "linx.dcoreid", FT_UINT32, BASE_DEC, VALS(linx_coreid), 0x00ff0000, "Multicore destination core id", HFILL},
+ },
+ { &hf_linx_multicore_reserved, /* in ETHCM_MULTICORE */
+ { "Reserved", "linx.reserved8", FT_UINT32, BASE_DEC, NULL, 0x0f000000, "Multicore Hdr Reserved", HFILL},
+ },
+ { &hf_linx_multicore_reserved1, /* in ETHCM_MULTICORE */
+ { "Reserved", "linx.reserved9", FT_UINT32, BASE_DEC, NULL, 0x000000ff, "Multicore Hdr Reserved", HFILL},
+ },
+ { &hf_linx_main_version, /* in ETHCM_MAIN */
+ { "Version", "linx.version", FT_UINT32, BASE_DEC, NULL, 0x0e000000, "LINX Version", HFILL },
+ },
+ { &hf_linx_main_reserved, /* in ETHCM_MAIN */
+ { "Reserved", "linx.reserved1", FT_UINT32, BASE_DEC, NULL, 0x01800000, "Main Hdr Reserved", HFILL },
+ },
+ { &hf_linx_main_connection, /* in ETHCM_MAIN */
+ { "Connection", "linx.connection", FT_UINT32, BASE_DEC, NULL, 0x007f8000, NULL, HFILL },
+ },
+ { &hf_linx_main_bundle, /* in ETHCM_MAIN */
+ { "Bundle", "linx.bundle", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00004000, NULL, HFILL },
+ },
+ { &hf_linx_main_pkgsize, /* in ETHCM_MAIN */
+ { "Package Size", "linx.pcksize", FT_UINT32, BASE_DEC, NULL, 0x00003fff, NULL, HFILL },
+ },
+ { &hf_linx_udata_reserved, /* in ETHCM_UDATA */
+ { "Reserved", "linx.reserved5", FT_UINT32, BASE_DEC, NULL, 0x0fff0000, "Udata Hdr Reserved", HFILL },
+ },
+ { &hf_linx_udata_morefrags, /* in ETHCM_UDATA */
+ { "More Fragments", "linx.morefra", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00008000, "More fragments follow", HFILL },
+ },
+ { &hf_linx_udata_fragno, /* in ETHCM_UDATA */
+ { "Fragment Number", "linx.fragno", FT_UINT32, BASE_DEC, VALS(linx_nofragment), 0x00007fff, NULL, HFILL },
+ },
+ { &hf_linx_udata_signo, /* in ETHCM_UDATA */
+ { "Signal Number", "linx.signo", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_udata_dstaddr16, /* in ETHCM_UDATA - protocol version 2 */
+ { "Receiver Address", "linx.dstaddr", FT_UINT32, BASE_DEC, NULL, 0xffff0000, NULL, HFILL },
+ },
+ { &hf_linx_udata_dstaddr32, /* in ETHCM_UDATA - protocol version 3 */
+ { "Receiver Address", "linx.dstaddr32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_udata_srcaddr16, /* in ETHCM_UDATA - protocol version 2 */
+ { "Sender Address", "linx.srcaddr", FT_UINT32, BASE_DEC, NULL, 0x0000ffff, NULL, HFILL },
+ },
+ { &hf_linx_udata_srcaddr32, /* in ETHCM_UDATA - protocol version 3 */
+ { "Sender Address", "linx.srcaddr32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_udata_payload, /* in ETHCM_UDATA */
+ { "Payload", "linx.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_ack_request, /* in ETHCM_ACK */
+ { "ACK-request", "linx.ackreq", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x08000000, NULL, HFILL },
+ },
+ { &hf_linx_ack_reserved, /* in ETHCM_ACK */
+ { "Reserved", "linx.reserved7", FT_UINT32, BASE_DEC, NULL, 0x07000000, "ACK Hdr Reserved", HFILL },
+ },
+ { &hf_linx_ack_ackno, /* in ETHCM_ACK */
+ { "ACK Number", "linx.ackno", FT_UINT32, BASE_DEC, NULL, 0x00fff000, NULL, HFILL },
+ },
+ { &hf_linx_ack_seqno, /* in ETHCM_ACK */
+ { "Sequence Number", "linx.seqno", FT_UINT32, BASE_DEC, NULL, 0x00000fff, NULL, HFILL },
+ },
+ { &hf_linx_conn_cmd, /* in ETHCM_CONN */
+ { "Command", "linx.cmd", FT_UINT32, BASE_DEC, VALS(linx_conn_cmd), 0x0f000000, NULL, HFILL },
+ },
+ { &hf_linx_conn_size, /* in ETHCM_CONN */
+ { "Size", "linx.size", FT_UINT32, BASE_DEC, NULL, 0x00e00000, NULL, HFILL },
+ },
+ { &hf_linx_conn_winsize, /* in ETHCM_CONN */
+ { "WinSize", "linx.winsize", FT_UINT32, BASE_DEC, NULL, 0x001e0000, "Window Size", HFILL },
+ },
+ { &hf_linx_conn_reserved, /* in ETHCM_CONN */
+ { "Reserved", "linx.reserved3", FT_UINT32, BASE_DEC, NULL, 0x0001ff00, "Conn Hdr Reserved", HFILL },
+ },
+ { &hf_linx_conn_publcid, /* in ETHCM_CONN */
+ { "Publish Conn ID", "linx.publcid", FT_UINT32, BASE_DEC, NULL, 0x000000ff, NULL, HFILL },
+ },
+ { &hf_linx_conn_srcmac, /* in ETHCM_CONN */
+ { "Source", "linx.srcmaddr_ether", FT_ETHER, BASE_NONE, NULL, 0x0, "Source Media Address (ethernet)", HFILL },
+ },
+ { &hf_linx_conn_dstmac, /* in ETHCM_CONN */
+ { "Destination", "linx.destmaddr_ether", FT_ETHER, BASE_NONE, NULL, 0x0, "Destination Media Address (ethernet)", HFILL },
+ },
+ { &hf_linx_conn_feat_neg_str, /* in ETHCM_CONN */
+ { "Feature Negotiation String", "linx.feat_neg_str", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_frag_reserved, /* in ETHCM_FRAG */
+ { "Reserved", "linx.reserved6", FT_UINT32, BASE_DEC, NULL, 0x0fff0000, "Frag Hdr Reserved", HFILL },
+ },
+ { &hf_linx_frag_morefrags, /* in ETHCM_FRAG */
+ { "More Fragments", "linx.morefr2", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00008000, NULL, HFILL },
+ },
+ { &hf_linx_frag_fragno, /* in ETHCM_FRAG */
+ { "Fragment Number", "linx.fragno2", FT_UINT32, BASE_DEC, NULL, 0x00007fff, NULL, HFILL },
+ },
+ { &hf_linx_nack_reserv1, /* in ETHCM_NACK */
+ { "Reserved", "linx.nack_reserv", FT_UINT32, BASE_DEC, NULL, 0x0f000000, "Nack Hdr Reserved", HFILL },
+ },
+ { &hf_linx_nack_count, /* in ETHCM_NACK */
+ { "Count", "linx.nack_count", FT_UINT32, BASE_DEC, NULL, 0x00ff0000, NULL, HFILL },
+ },
+ { &hf_linx_nack_reserv2, /* in ETHCM_NACK */
+ { "Reserved", "linx.nack_reserv", FT_UINT32, BASE_DEC, NULL, 0x0000f000, "Nack Hdr Reserved", HFILL },
+ },
+ { &hf_linx_nack_seqno, /* in ETHCM_NACK */
+ { "Sequence Number", "linx.nack_seqno", FT_UINT32, BASE_DEC, NULL, 0x00000fff, NULL, HFILL },
+ },
+
+ /* RLNH */
+ { &hf_linx_rlnh_msg_type32, /* in RLNH */
+ { "RLNH msg type", "linx.rlnh_msg_type", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x0, "RLNH message type", HFILL },
+ },
+ { &hf_linx_rlnh_msg_type8, /* in RLNH */
+ { "RLNH msg type", "linx.rlnh_msg_type8", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x000000ff, "RLNH message type", HFILL },
+ },
+ { &hf_linx_rlnh_msg_reserved, /* in RLNH */
+ { "RLNH msg reserved", "linx.rlnh_msg_reserved", FT_UINT32, BASE_DEC, NULL, 0xffffff00, "RLNH message reserved", HFILL },
+ },
+#if 0
+ { &hf_linx_rlnh_linkaddr, /* in RLNH */
+ { "RLNH linkaddr", "linx.rlnh_linkaddr", FT_UINT32, BASE_DEC, NULL, 0xffffffff, "RLNH linkaddress", HFILL },
+ },
+#endif
+ { &hf_linx_rlnh_src_linkaddr, /* in RLNH */
+ { "RLNH src linkaddr", "linx.rlnh_src_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH source linkaddress", HFILL },
+ },
+ { &hf_linx_rlnh_peer_linkaddr, /* in RLNH */
+ { "RLNH peer linkaddr", "linx.rlnh_peer_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH peer linkaddress", HFILL },
+ },
+ { &hf_linx_rlnh_version, /* in RLNH */
+ { "RLNH version", "linx.rlnh_version", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_rlnh_status, /* in RLNH */
+ { "RLNH reply", "linx.rlnh_status", FT_UINT32, BASE_DEC, VALS(linx_rlnh_reply), 0x0, NULL, HFILL },
+ },
+ { &hf_linx_rlnh_name, /* in RLNH */
+ { "RLNH name", "linx.rlnh_name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_rlnh_feat_neg_str, /* in RLNH */
+ { "RLNH Feature Negotiation String", "linx.rlnh_feat_neg_str", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
+ }
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_linx,
+ &ett_linx_multicore,
+ &ett_linx_main,
+ &ett_linx_error,
+ &ett_linx_udata,
+ &ett_linx_ack
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_linx_version, { "linx.version.unknown", PI_PROTOCOL, PI_WARN, "Version not yet supported and might be dissected incorrectly!", EXPFILL }},
+ { &ei_linx_rlnh_msg, { "linx.rlnh_msg.unknown", PI_PROTOCOL, PI_WARN, "Message type not recognized", EXPFILL }},
+ { &ei_linx_header, { "linx.header_not_recognized", PI_PROTOCOL, PI_WARN, "Header not recognized", EXPFILL }},
+ };
+
+ expert_module_t* expert_linx;
+
+ proto_linx = proto_register_protocol (
+ "ENEA LINX", /* name */
+ "LINX", /* short name */
+ "linx" /* abbrev */
+ );
+
+ /* Protocol Registering data structures. */
+ proto_register_field_array(proto_linx, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_linx = expert_register_protocol(proto_linx);
+ expert_register_field_array(expert_linx, ei, array_length(ei));
+
+ /* Register the dissector */
+ linx_handle = register_dissector("linx", dissect_linx, proto_linx);
+}
+
+
+/* Protocol Handoff */
+void
+proto_reg_handoff_linx(void)
+{
+ dissector_add_uint("ethertype", ETHERTYPE_LINX, linx_handle);
+}
+
+/************ TCP CM **************/
+
+static int
+dissect_linx_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ guint32 dword;
+ int offset = 0;
+ proto_item *ti, *ver_item, *msg_item;
+ proto_tree *linx_tcp_tree;
+ proto_tree *tcp_header_tree;
+ proto_tree *rlnh_header_tree;
+ int payloadsize;
+ int version;
+ int size;
+ int type;
+
+ /* Show name in protocol column */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "LINX/TCP");
+
+ /* Clear out stuff in the info column */
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ dword = tvb_get_ntohl(tvb, 0);
+ version = (dword >> 16) & 0xFF;
+ type = (dword >> 24) & 0xFF;
+
+ /* size of linx tcp cm header */
+ size = 16;
+
+ if (type == 0x55) {
+ dword = tvb_get_ntohl(tvb, 12);
+ size += (dword & 0xFFFFFFFF);
+ }
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "tcpcm:%s ", val_to_str_const(type, linx_short_tcp_names, "unknown"));
+
+ ti = proto_tree_add_item(tree, proto_linx_tcp, tvb, 0, -1, ENC_NA);
+ linx_tcp_tree = proto_item_add_subtree(ti, ett_linx_tcp);
+
+ tcp_header_tree = proto_tree_add_subtree(linx_tcp_tree, tvb, 0, 16, ett_linx_tcp, NULL, "TCP CM Header");
+
+ proto_tree_add_item(tcp_header_tree, hf_linx_tcp_type, tvb, 0, 4, ENC_BIG_ENDIAN);
+ ver_item = proto_tree_add_item(tcp_header_tree, hf_linx_tcp_version, tvb, 0, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tcp_header_tree, hf_linx_tcp_oob, tvb, 0, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tcp_header_tree, hf_linx_tcp_src, tvb, 4, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tcp_header_tree, hf_linx_tcp_dst, tvb, 8, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tcp_header_tree, hf_linx_tcp_size, tvb, 12, 4, ENC_BIG_ENDIAN);
+
+ if (version != 3) {
+ expert_add_info(pinfo, ver_item, &ei_linx_tcp_version);
+ }
+
+ offset += 16;
+
+ if (type == 0x55) { /* UDATA */
+ dword = tvb_get_ntohl(tvb, 8);
+ if (dword == 0) { /* RLNH Message*/
+
+ dword = tvb_get_ntohl(tvb, offset);
+
+ /* Write to info column */
+ col_append_fstr(pinfo->cinfo, COL_INFO, "rlnh:%s ", val_to_str_const(dword, linx_short_rlnh_names, "unknown"));
+
+ /* create new paragraph for RLNH */
+ rlnh_header_tree = proto_tree_add_subtree(linx_tcp_tree, tvb, offset, 4, ett_linx_tcp, NULL, "RLNH");
+
+ if(version == 1) {
+ msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_msg_type32, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ } else {
+ /*
+ * In version 2 of the rlnh protocol the length of the message type is
+ * restricted to 8 bits.
+ */
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_msg_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
+ msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_msg_type8, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ }
+
+ switch (dword) {
+ case RLNH_LINK_ADDR:
+ break;
+ case RLNH_QUERY_NAME:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_name, tvb, offset, -1, ENC_ASCII);
+ /*offset += tvb_strnlen(tvb, offset, -1);*/
+ break;
+ case RLNH_PUBLISH:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_name, tvb, offset, -1, ENC_ASCII);
+ /*offset += tvb_strnlen(tvb, offset, -1);*/
+ break;
+ case RLNH_UNPUBLISH:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ /*offset += 4;*/
+ break;
+ case RLNH_UNPUBLISH_ACK:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ /*offset += 4;*/
+ break;
+ case RLNH_INIT:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_version, tvb, offset, 4, ENC_BIG_ENDIAN);
+ rlnh_version = tvb_get_ntohl(tvb, offset);
+ /*offset += 4;*/
+ break;
+ case RLNH_INIT_REPLY:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_status, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ if(rlnh_version > 1) {
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_feat_neg_str, tvb, offset, -1, ENC_ASCII);
+ /*offset += tvb_strnlen(tvb, offset, -1);*/
+ }
+ break;
+ case RLNH_PUBLISH_PEER:
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_peer_linkaddr, tvb, offset, -1, ENC_BIG_ENDIAN);
+ /*offset += tvb_strnlen(tvb, offset, -1);*/
+ break;
+ default:
+ /* No known Message type */
+ expert_add_info(pinfo, msg_item, &ei_linx_tcp_rlnh_msg);
+ break;
+ }
+ } else {
+ /* User payload */
+ payloadsize = size-offset;
+ if (payloadsize) {
+ proto_tree_add_item(linx_tcp_tree, hf_linx_tcp_payload, tvb, offset, payloadsize, ENC_NA);
+ }
+ }
+ }
+ return tvb_captured_length(tvb);
+}
+
+void
+proto_register_linx_tcp(void)
+{
+ static hf_register_info hf[] = {
+#if 0
+ { &hf_linx_tcp_reserved,
+ { "Reserved", "linxtcp.reserved", FT_UINT32, BASE_DEC, NULL, 0x00007FFF, "TCP CM reserved", HFILL },
+ },
+#endif
+ { &hf_linx_tcp_oob,
+ { "Out-of-band", "linxtcp.oob", FT_UINT32, BASE_DEC, NULL, 0x00008000, "TCP CM oob", HFILL },
+ },
+ { &hf_linx_tcp_version,
+ { "Version", "linxtcp.version", FT_UINT32, BASE_DEC, NULL, 0x00FF0000, "TCP CM version", HFILL },
+ },
+ { &hf_linx_tcp_type,
+ { "Type", "linxtcp.type", FT_UINT32, BASE_HEX, VALS(linx_long_tcp_names), 0xFF000000, "TCP CM type", HFILL },
+ },
+ { &hf_linx_tcp_src,
+ { "Source", "linxtcp.src", FT_UINT32, BASE_DEC, NULL, 0x0, "TCP CM source", HFILL },
+ },
+ { &hf_linx_tcp_dst,
+ { "Destination", "linxtcp.dst", FT_UINT32, BASE_DEC, NULL, 0x0, "TCP CM destination", HFILL },
+ },
+ { &hf_linx_tcp_size,
+ { "Size", "linxtcp.size", FT_UINT32, BASE_DEC, NULL, 0x0, "TCP CM size", HFILL },
+ },
+
+ /* RLNH */
+ { &hf_linx_tcp_rlnh_msg_type32,
+ { "RLNH msg type", "linxtcp.rlnh_msg_type", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x0, "RLNH message type", HFILL },
+ },
+ { &hf_linx_tcp_rlnh_msg_type8,
+ { "RLNH msg type", "linxtcp.rlnh_msg_type8", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x000000ff, "RLNH message type", HFILL },
+ },
+ { &hf_linx_tcp_rlnh_msg_reserved,
+ { "RLNH msg reserved", "linxtcp.rlnh_msg_reserved", FT_UINT32, BASE_DEC, NULL, 0xffffff00, "RLNH message reserved", HFILL },
+ },
+#if 0
+ { &hf_linx_tcp_rlnh_linkaddr,
+ { "RLNH linkaddr", "linxtcp.rlnh_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH linkaddress", HFILL },
+ },
+#endif
+ { &hf_linx_tcp_rlnh_src_linkaddr,
+ { "RLNH src linkaddr", "linxtcp.rlnh_src_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH source linkaddress", HFILL },
+ },
+ { &hf_linx_tcp_rlnh_peer_linkaddr,
+ { "RLNH peer linkaddr", "linxtcp.rlnh_peer_linkaddr", FT_UINT32,
+ BASE_DEC, NULL, 0x0, "RLNH peer linkaddress", HFILL },
+ },
+ { &hf_linx_tcp_rlnh_version,
+ { "RLNH version", "linxtcp.rlnh_version", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_tcp_rlnh_status,
+ { "RLNH reply", "linxtcp.rlnh_status", FT_UINT32, BASE_DEC, VALS(linx_rlnh_reply), 0x0, NULL, HFILL },
+ },
+ { &hf_linx_tcp_rlnh_name,
+ { "RLNH name", "linxtcp.rlnh_name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_tcp_rlnh_feat_neg_str,
+ { "RLNH Feature Negotiation String", "linxtcp.rlnh_feat_neg_str", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
+ },
+ { &hf_linx_tcp_payload,
+ { "Payload", "linxtcp.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
+ }
+ };
+
+ static gint *ett[] = {
+ &ett_linx_tcp,
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_linx_tcp_version, { "linxtcp.version.unknown", PI_PROTOCOL, PI_WARN, "Version not yet supported and might be dissected incorrectly!", EXPFILL }},
+ { &ei_linx_tcp_rlnh_msg, { "linxtcp.rlnh_msg.unknown", PI_PROTOCOL, PI_WARN, "Message type not recognized", EXPFILL }},
+ };
+
+ expert_module_t* expert_linx_tcp;
+
+ proto_linx_tcp = proto_register_protocol("ENEA LINX over TCP", "LINX/TCP", "linxtcp");
+ proto_register_field_array(proto_linx_tcp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_linx_tcp = expert_register_protocol(proto_linx_tcp);
+ expert_register_field_array(expert_linx_tcp, ei, array_length(ei));
+}
+
+void
+proto_reg_handoff_linx_tcp(void)
+{
+ dissector_handle_t linx_tcp_handle;
+
+ linx_tcp_handle = create_dissector_handle(dissect_linx_tcp, proto_linx_tcp);
+
+ dissector_add_for_decode_as_with_preference("tcp.port", linx_tcp_handle);
+}
+
+/*
+ * 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:
+ */