diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-linx.c | |
parent | Initial commit. (diff) | |
download | wireshark-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.c | 1072 |
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: + */ |