From d2410336b8539d65fae563aa919032c4ce2f77b2 Mon Sep 17 00:00:00 2001 From: Alexis La Goutte Date: Mon, 20 Jan 2014 18:35:45 +0000 Subject: From Lubos via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9638 New Dissector For Lightweight Mesh protocol A dissector for ATMEL Lightweight Mesh protocol (lwm). The protocol is carried on the top of 802.15.4 frame. From me: * Add Modelines info * Fix indent (use 4 spaces) * Remove trailing whitespace svn path=/trunk/; revision=54856 --- epan/dissectors/packet-lwm.c | 977 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 977 insertions(+) create mode 100644 epan/dissectors/packet-lwm.c (limited to 'epan/dissectors/packet-lwm.c') diff --git a/epan/dissectors/packet-lwm.c b/epan/dissectors/packet-lwm.c new file mode 100644 index 0000000000..0bd3eea8cb --- /dev/null +++ b/epan/dissectors/packet-lwm.c @@ -0,0 +1,977 @@ +/* packet-lwm.c + * Dissector routines for the ATMEL Lightweight Mesh 1.1.1 + * Copyright 2013 Martin Leixner + * + * $Id: packet-lwm.c v0.1.0 2013-12-15 16:49:22 $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *------------------------------------------------------------ +*/ + +#include "config.h" + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include + +#include + +#include + +#include +#include +#include + + +/*LwMesh lengths*/ +#define LWM_HEADER_BASE_LEN 7 +#define LWM_MIC_LEN 4 +#define LWM_MULTI_HEADER_LEN 2 + +/* Bit-masks for the FCF */ +#define LWM_FCF_ACK_REQUEST 0x01 +#define LWM_FCF_SEC_EN 0x02 + +#define LWM_FCF_LINK_LOCAL 0x04 +#define LWM_FCF_MULTICAST 0x08 + +#define LWM_FCF_RESERVED 0xF0 + +#define LWM_MULTI_NON_MEM_RAD_MASK 0x000F +#define LWM_MULTI_NON_MEM_RAD_OFFSET 0 + +#define LWM_MULTI_MAX_NON_MEM_RAD_MASK 0x00F0 +#define LWM_MULTI_MAX_NON_MEM_RAD_OFFSET 4 + +#define LWM_MULTI_MEM_RAD_MASK 0x0F00 +#define LWM_MULTI_MEM_RAD_OFFSET 8 + +#define LWM_MULTI_MAX_MEM_RAD_MASK 0xF000 +#define LWM_MULTI_MAX_MEM_RAD_OFFSET 12 + +/*Endpoints*/ +#define LWM_SRC_ENDP_MASK 0xF0 +#define LWM_SRC_ENDP_OFFSET 4 +#define LWM_DST_ENDP_MASK 0x0F +#define LWM_DST_ENDP_OFFSET 0 + +/*Defined addresses*/ +#define LWM_BCAST_ADDR 0xFFFF + +/*Command IDs*/ +#define LWM_CMD_ACK 0x00 +#define LWM_CMD_ROUTE_ERR 0x01 +#define LWM_CMD_ROUTE_REQ 0x02 +#define LWM_CMD_ROUTE_REPLY 0x03 + +/*Lengths of command frames*/ +#define LWM_CMD_FRAME_ACK_LEN 3 +#define LWM_CMD_FRAME_ROUTE_ERR_LEN 6 +#define LWM_CMD_FRAME_ROUTE_REQ_LEN 7 +#define LWM_CMD_FRAME_ROUTE_REPLY_LEN 8 + +/*Values for multicast field*/ +#define LWM_CMD_MULTI_ADDR_FALSE 0 +#define LWM_CMD_MULTI_ADDR_TRUE 1 + +/*Defined strings*/ +#define LWM_CMD_LINKQ_STRING "(Sent by Originate node)" +#define LWM_CMD_UNKNOWN_VAL_STRING "Unknown command (0x%02x)" + +#define LWM_MULTI_UNICAST_STRING "(Unicast)" +#define LWM_MULTI_GROUP_STRING "(Group ID)" + +/* Function declarations */ +void proto_reg_handoff_lwm(void); + +/* Dissector handles */ +static dissector_handle_t data_handle; + +/* Dissection Routines. */ +static void dissect_lwm (tvbuff_t *, packet_info *, proto_tree *); +static void dissect_lwm_cmd_frame_ack (tvbuff_t *, packet_info *, proto_tree *); +static void dissect_lwm_cmd_frame_route_err (tvbuff_t *, packet_info *, proto_tree *); +static void dissect_lwm_cmd_frame_route_req (tvbuff_t *, packet_info *, proto_tree *); +static void dissect_lwm_cmd_frame_route_reply (tvbuff_t *, packet_info *, proto_tree *); + +/* Initialize protocol and registered fields. */ +static int proto_lwm = -1; + +static int hf_lwm_fcf = -1; +static int hf_lwm_fcf_ack_req = -1; +static int hf_lwm_fcf_security = -1; +static int hf_lwm_fcf_linklocal = -1; +static int hf_lwm_fcf_multicast = -1; +static int hf_lwm_fcf_reserved = -1; +static int hf_lwm_seq = -1; +static int hf_lwm_src_addr = -1; +static int hf_lwm_dst_addr = -1; +static int hf_lwm_src_endp = -1; +static int hf_lwm_dst_endp = -1; +static int hf_lwm_multi_nmrad = -1; +static int hf_lwm_multi_mnmrad = -1; +static int hf_lwm_multi_mrad = -1; +static int hf_lwm_multi_mmrad = -1; +static int hf_lwm_mic = -1; +static int hf_lwm_cmd = -1; +static int hf_lwm_cmd_seq = -1; +static int hf_lwm_cmd_cm = -1; +static int hf_lwm_cmd_route_src = -1; +static int hf_lwm_cmd_route_dst = -1; +static int hf_lwm_cmd_route_multi = -1; +static int hf_lwm_cmd_linkquality = -1; +static int hf_lwm_cmd_forwlinkquality = -1; +static int hf_lwm_cmd_revlinkquality = -1; + +/* Initialize protocol subtrees. */ +static gint ett_lwm = -1; +static gint ett_lwm_fcf = -1; +static gint ett_lwm_cmd_tree = -1; +static gint ett_lwm_multi_tree = -1; + +static expert_field ei_lwm_mal_error = EI_INIT; +static expert_field ei_lwm_n_src_broad = EI_INIT; +static expert_field ei_lwm_missmatch_endp = EI_INIT; +static expert_field ei_lwm_empty_payload = EI_INIT; + + +static const value_string lwm_cmd_names[] = { + { LWM_CMD_ACK, "LwMesh ACK" }, + { LWM_CMD_ROUTE_ERR, "Route Error" }, + { LWM_CMD_ROUTE_REQ, "Route Request" }, + { LWM_CMD_ROUTE_REPLY, "Route Reply" }, + { 0, NULL } +}; + +static const value_string lwm_cmd_multi_names[] = { + { LWM_CMD_MULTI_ADDR_FALSE, "FALSE" }, + { LWM_CMD_MULTI_ADDR_TRUE, "TRUE" }, + { 0, NULL } +}; + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_lwm_heur + * DESCRIPTION + * Heuristic interpreter for the Lightweight Mesh. + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_into *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree Wireshark uses to display packet. + * RETURNS + * Boolean value, whether it handles the packet or not. + *--------------------------------------------------------------- + */ +static gboolean +dissect_lwm_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + + /* 1) first byte must have bits 0000xxxx */ + if (tvb_get_guint8(tvb, 0) & LWM_FCF_RESERVED ) + return (FALSE); + + dissect_lwm(tvb, pinfo, tree); + return (TRUE); + +} /* dissect_lwm_heur */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_lwm + * DESCRIPTION + * Lightweight Mesh packet dissection routine for Wireshark. + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree Wireshark uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void dissect_lwm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + gint lwm_len = 0; + gint lwm_header_len = 0; + gint lwm_payload_len = 0; + + guint8 lwm_fcf; + guint8 lwm_fcf_security; + guint8 lwm_fcf_multicast; + + guint16 lwm_multi_header; + + guint8 lwm_seq; + guint16 lwm_src_addr; + guint16 lwm_dst_addr; + guint8 lwm_endp_field; + guint8 lwm_src_endp; + guint8 lwm_dst_endp; + guint32 lwm_mic; + guint8 lwm_cmd; + + proto_item *proto_root, *ti; + proto_tree *lwm_tree = NULL; + proto_tree *multi_tree = NULL; + proto_tree *field_tree = NULL; + + /*---------------------------------------------------------*/ + + /*Get totaly length of LWM bytes (header + payload)*/ + lwm_len = tvb_length(tvb); + + /*Set base length of LWM header*/ + lwm_header_len = LWM_HEADER_BASE_LEN; + lwm_payload_len = lwm_len - lwm_header_len; + + + /*--------------------------------------------------*/ + /* */ + /* Load dissector bytes */ + /* */ + /*--------------------------------------------------*/ + + lwm_fcf = tvb_get_guint8(tvb, 0); + lwm_fcf_security = (lwm_fcf & LWM_FCF_SEC_EN); + + /*Check if security MIC is present*/ + if(lwm_fcf_security & LWM_FCF_SEC_EN){ + lwm_mic = tvb_get_ntohl(tvb, (lwm_len - LWM_MIC_LEN)); + lwm_payload_len -= LWM_MIC_LEN; + } + + lwm_fcf_multicast = (lwm_fcf & LWM_FCF_MULTICAST); + + lwm_seq = tvb_get_guint8(tvb, 1); + + lwm_src_addr = tvb_get_letohs(tvb, 2); + lwm_dst_addr = tvb_get_letohs(tvb, 4); + + lwm_endp_field = tvb_get_guint8(tvb, 6); + + lwm_src_endp = (lwm_endp_field & LWM_SRC_ENDP_MASK) >> LWM_SRC_ENDP_OFFSET; + lwm_dst_endp = (lwm_endp_field & LWM_DST_ENDP_MASK) >> LWM_DST_ENDP_OFFSET; + + /*If multicast field is set to one, multicast header is present*/ + if(lwm_fcf_multicast & LWM_FCF_MULTICAST){ + + lwm_multi_header = tvb_get_letohs(tvb, 7); + + lwm_header_len += LWM_MULTI_HEADER_LEN; + lwm_payload_len -= LWM_MULTI_HEADER_LEN; + } + + /*--------------------------------------------------*/ + /* */ + /* Create LwMesh dissector tree */ + /* */ + /*--------------------------------------------------*/ + if(tree){ + /* Create subtree for the LwMesh*/ + proto_root = proto_tree_add_protocol_format(tree, proto_lwm, tvb, 0, lwm_len, "Lightweight Mesh, Sequence Number: %i", lwm_seq); + lwm_tree = proto_item_add_subtree(proto_root, ett_lwm); + } + + /*Check wrong values of lengths*/ + if(lwm_payload_len < 0){ + expert_add_info_format(pinfo, lwm_tree, &ei_lwm_mal_error,"Wrong size of LwMesh packet (missing bytes or wrong field values)"); + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO,"Lightweight Mesh[Malformed data!]"); + + return; + } + + /*Enter name of protocol to info field*/ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LwMesh"); + + + /*Enter description to info field*/ + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO,"Lightweight Mesh, Nwk_Dst: 0x%04x, Nwk_Src: 0x%04x",lwm_dst_addr,lwm_src_addr); + + + if(tree){ + /*--------------------------------------------------*/ + /* */ + /* Display LwMesh dissector tree */ + /* */ + /*--------------------------------------------------*/ + + /*Frame control fields*/ + ti = proto_tree_add_uint(lwm_tree, hf_lwm_fcf, tvb, 0, 1, lwm_fcf); + + field_tree = proto_item_add_subtree(ti, ett_lwm_fcf); + proto_tree_add_boolean(field_tree, hf_lwm_fcf_ack_req, tvb, 0, 1, (lwm_fcf & LWM_FCF_ACK_REQUEST)); + + + proto_tree_add_boolean(field_tree, hf_lwm_fcf_security, tvb, 0, 1, lwm_fcf_security); + proto_tree_add_boolean(field_tree, hf_lwm_fcf_linklocal, tvb, 0, 1, (lwm_fcf & LWM_FCF_LINK_LOCAL)); + proto_tree_add_boolean(field_tree, hf_lwm_fcf_multicast, tvb, 0, 1, lwm_fcf_multicast); + proto_tree_add_item(field_tree, hf_lwm_fcf_reserved, tvb, 0, 1, ENC_NA); + + /*Sequence number*/ + proto_tree_add_uint(lwm_tree, hf_lwm_seq, tvb, 1, 1, lwm_seq); + + /*Network addresses*/ + ti=proto_tree_add_uint(lwm_tree, hf_lwm_src_addr, tvb, 2, 2, lwm_src_addr); + + /*Check value of source address*/ + if(lwm_src_addr==LWM_BCAST_ADDR){ + expert_add_info(pinfo, lwm_tree, &ei_lwm_n_src_broad); + } + + /*Parse Source address*/ + if(lwm_src_addr < 0x8000){ + proto_item_append_text(ti, " (Routing node)"); + }else{ + proto_item_append_text(ti, " (Non-routing node)"); + } + + /*Parse Destination address*/ + if(lwm_dst_addr==LWM_BCAST_ADDR){ + + proto_tree_add_uint_format_value(lwm_tree, hf_lwm_dst_addr, tvb, 4, 2, lwm_dst_addr, + "Broadcast (0x%04x)",lwm_dst_addr); + + }else{ + ti=proto_tree_add_uint(lwm_tree, hf_lwm_dst_addr, tvb, 4, 2, lwm_dst_addr); + + if(lwm_fcf_multicast & LWM_FCF_MULTICAST){ + proto_item_append_text(ti, " %s",LWM_MULTI_GROUP_STRING); + }else{ + proto_item_append_text(ti, " %s",LWM_MULTI_UNICAST_STRING); + + if(lwm_dst_addr < 0x8000){ + proto_item_append_text(ti, " (Routing node)"); + }else{ + proto_item_append_text(ti, " (Non-routing node)"); + } + } + } + + /*Endpoints*/ + ti = proto_tree_add_uint(lwm_tree, hf_lwm_src_endp, tvb, 6, 1, lwm_src_endp); + if(lwm_src_endp == 0){ + proto_item_append_text(ti, " (Stack command endpoint)"); + } + + ti = proto_tree_add_uint(lwm_tree, hf_lwm_dst_endp, tvb, 6, 1, lwm_dst_endp); + if(lwm_dst_endp == 0){ + proto_item_append_text(ti, " (Stack command endpoint)"); + } + + if( (lwm_src_endp == 0) && (lwm_dst_endp == 0)){ + /*stack command endpoints*/ + + } + else if( (lwm_src_endp == 0) || (lwm_dst_endp == 0)){ + /*If only one endpoint is 0, alert about that*/ + + col_append_fstr(pinfo->cinfo, COL_INFO,"[Stack command Endpoints missmatch]"); + + expert_add_info(pinfo, lwm_tree,&ei_lwm_missmatch_endp); + } + + /*Multicast header*/ + if( (lwm_fcf_multicast & LWM_FCF_MULTICAST) ){ + + ti = proto_tree_add_text(lwm_tree, tvb, 7,2, "Multicast Header"); + multi_tree = proto_item_add_subtree(ti, ett_lwm_multi_tree); + + proto_tree_add_uint(multi_tree, hf_lwm_multi_nmrad, tvb, 7, 2, (lwm_multi_header & LWM_MULTI_NON_MEM_RAD_MASK) >> LWM_MULTI_NON_MEM_RAD_OFFSET); + proto_tree_add_uint(multi_tree, hf_lwm_multi_mnmrad, tvb, 7, 2, (lwm_multi_header & LWM_MULTI_MAX_NON_MEM_RAD_MASK) >> LWM_MULTI_MAX_NON_MEM_RAD_OFFSET); + proto_tree_add_uint(multi_tree, hf_lwm_multi_mrad, tvb, 7, 2, (lwm_multi_header & LWM_MULTI_MEM_RAD_MASK) >> LWM_MULTI_MEM_RAD_OFFSET); + proto_tree_add_uint(multi_tree, hf_lwm_multi_mmrad, tvb, 7, 2, (lwm_multi_header & LWM_MULTI_MAX_MEM_RAD_MASK) >> LWM_MULTI_MAX_MEM_RAD_OFFSET); + } + + /*MIC field*/ + if(lwm_fcf_security & LWM_FCF_SEC_EN){ + proto_tree_add_uint(lwm_tree, hf_lwm_mic, tvb, (lwm_len - LWM_MIC_LEN), LWM_MIC_LEN, lwm_mic); + } + + + }/*END OF: If(tree)*/ + + /*------------------------------*/ + /* */ + /* Dissect payload */ + /* */ + /*------------------------------*/ + if(lwm_payload_len > 0){ + + tvbuff_t *new_tvb; + + new_tvb = tvb_new_subset(tvb, lwm_header_len, lwm_payload_len, lwm_len); + + /*Encrypted data*/ + if(lwm_fcf_security & LWM_FCF_SEC_EN){ + + /*Enter name info protocol field*/ + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO,"Encrypted data (%i byte(s)) ",lwm_payload_len); + + + call_dissector(data_handle, new_tvb, pinfo, tree); + return; + } + /*stack command endpoint 0 and not secured*/ + else if( (lwm_src_endp == 0) && (lwm_dst_endp == 0) ){ + + /*----------------------------------------------------------------------*/ + /* */ + /* Call command dissector (depends on value of first byte of payload) */ + /* */ + /*----------------------------------------------------------------------*/ + lwm_cmd = tvb_get_guint8(tvb, lwm_header_len); + + switch (lwm_cmd) { + + case LWM_CMD_ACK: + dissect_lwm_cmd_frame_ack(new_tvb, pinfo, tree); + break; + + case LWM_CMD_ROUTE_ERR: + dissect_lwm_cmd_frame_route_err(new_tvb, pinfo, tree); + break; + + case LWM_CMD_ROUTE_REQ: + dissect_lwm_cmd_frame_route_req(new_tvb, pinfo, tree); + break; + + case LWM_CMD_ROUTE_REPLY: + dissect_lwm_cmd_frame_route_reply(new_tvb, pinfo, tree); + break; + + default: + /*Unknown command*/ + col_append_fstr(pinfo->cinfo, COL_INFO,", Unknown command (0x%02x bytes)",lwm_cmd); + + call_dissector(data_handle, new_tvb, pinfo, tree); + return; + break; + + } + } + + else{ + /*unknown data*/ + call_dissector(data_handle, new_tvb, pinfo, tree); + return; + + } + + }else{ + /*------------------*/ + /* */ + /* Empty payload */ + /* */ + /*------------------*/ + expert_add_info(pinfo, lwm_tree, &ei_lwm_empty_payload); + + col_append_fstr(pinfo->cinfo, COL_INFO,"[Empty LwMesh Payload]"); + + } + +} /* dissect_lwm*/ +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_lwm_cmd_frame_ack + * DESCRIPTION + * LwMesh command frame - Ack. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree wireshark uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void dissect_lwm_cmd_frame_ack(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *proto_root; + proto_tree *lwm_cmd_tree = NULL; + + guint frame_len = 0; + guint8 lwm_cmd; + guint8 lwm_seq; + + /*Get length command frame*/ + frame_len = tvb_length(tvb); + + /*Get fields*/ + lwm_cmd = tvb_get_guint8(tvb, 0); + lwm_seq = tvb_get_guint8(tvb, 1); + + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "%s, Sequence number: %d", val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING),lwm_seq); + + + if(tree){ + proto_root = proto_tree_add_protocol_format(tree, proto_lwm, tvb, 0, -1, "%s, Sequence number: %d", + val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING),lwm_seq); + + lwm_cmd_tree = proto_item_add_subtree(proto_root, ett_lwm_cmd_tree); + + } + + if(frame_len ==LWM_CMD_FRAME_ACK_LEN){ + + /* Create subtree for the Ack frame*/ + if(tree){ + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd, tvb, 0, 1, lwm_cmd); + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_seq, tvb, 1, 1, lwm_seq); + proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_cm, tvb, 2, 1, ENC_NA); + } + + }else{ + expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error, + "Size is %i byte(s), instead of %i bytes",frame_len,LWM_CMD_FRAME_ACK_LEN); + } + +} /* dissect_lwm_cmd_frame_ack*/ +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_lwm_cmd_frame_route_err + * DESCRIPTION + * LwMesh command frame - Route error. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree wireshark uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void dissect_lwm_cmd_frame_route_err(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *proto_root, *ti; + proto_tree *lwm_cmd_tree = NULL; + + guint frame_len = 0; + guint8 lwm_cmd; + guint8 lwm_cmd_multi; + guint16 lwm_src_addr; + guint16 lwm_dst_addr; + + + frame_len = tvb_length(tvb); + + + lwm_cmd = tvb_get_guint8(tvb, 0); + lwm_src_addr = tvb_get_letohs(tvb, 1); + lwm_dst_addr = tvb_get_letohs(tvb, 3); + lwm_cmd_multi = tvb_get_guint8(tvb, 5); + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING)); + + + if(tree){ + proto_root = proto_tree_add_protocol_format(tree, proto_lwm, tvb, 0, -1, "%s", val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING)); + lwm_cmd_tree = proto_item_add_subtree(proto_root, ett_lwm_cmd_tree); + } + + + if(frame_len ==LWM_CMD_FRAME_ROUTE_ERR_LEN){ + + /* Create subtree for the Ack frame*/ + if(tree){ + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd, tvb, 0, 1, lwm_cmd); + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, lwm_src_addr); + ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, lwm_dst_addr); + + if(lwm_cmd_multi == LWM_CMD_MULTI_ADDR_TRUE){ + proto_item_append_text(ti, " %s",LWM_MULTI_GROUP_STRING); + }else{ + proto_item_append_text(ti, " %s",LWM_MULTI_UNICAST_STRING); + } + + proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA); + } + + }else{ + expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error, + "Size is %i byte(s), instead of %i bytes",frame_len,LWM_CMD_FRAME_ROUTE_ERR_LEN); + } + +} /* dissect_lwm_cmd_frame_route_err*/ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_lwm_cmd_frame_route_req + * DESCRIPTION + * LwMesh command frame - Route Request. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree wireshark uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void dissect_lwm_cmd_frame_route_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *proto_root, *ti; + proto_tree *lwm_cmd_tree = NULL; + + guint frame_len = 0; + guint8 lwm_cmd; + guint8 lwm_cmd_multi; + guint16 lwm_src_addr; + guint16 lwm_dst_addr; + guint8 lwm_linkqual; + + frame_len = tvb_length(tvb); + + + lwm_cmd = tvb_get_guint8(tvb, 0); + lwm_src_addr = tvb_get_letohs(tvb, 1); + lwm_dst_addr = tvb_get_letohs(tvb, 3); + lwm_cmd_multi = tvb_get_guint8(tvb, 5); + lwm_linkqual = tvb_get_guint8(tvb, 6); + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING)); + + + if(tree){ + proto_root = proto_tree_add_protocol_format(tree, proto_lwm, tvb, 0, -1, "%s", val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING)); + lwm_cmd_tree = proto_item_add_subtree(proto_root, ett_lwm_cmd_tree); + } + + + if(frame_len ==LWM_CMD_FRAME_ROUTE_REQ_LEN){ + + /* Create subtree for the Ack frame*/ + if(tree){ + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd, tvb, 0, 1, lwm_cmd); + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, lwm_src_addr); + ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, lwm_dst_addr); + + if(lwm_cmd_multi == LWM_CMD_MULTI_ADDR_TRUE){ + proto_item_append_text(ti, " %s",LWM_MULTI_GROUP_STRING); + }else{ + proto_item_append_text(ti, " %s",LWM_MULTI_UNICAST_STRING); + } + + proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA); + ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_linkquality, tvb, 6, 1, lwm_linkqual); + if(lwm_linkqual == 255){ + proto_item_append_text(ti, " %s",LWM_CMD_LINKQ_STRING); + } + } + + }else{ + expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error, + "Size is %i byte(s), instead of %i bytes",frame_len,LWM_CMD_FRAME_ROUTE_REQ_LEN); + } + +} /* dissect_lwm_cmd_frame_route_req*/ + + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_lwm_cmd_frame_route_reply + * DESCRIPTION + * LwMesh command frame - Route Reply. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree wireshark uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void dissect_lwm_cmd_frame_route_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *proto_root, *ti; + proto_tree *lwm_cmd_tree = NULL; + + guint frame_len = 0; + guint8 lwm_cmd; + guint8 lwm_cmd_multi; + guint16 lwm_src_addr; + guint16 lwm_dst_addr; + guint8 lwm_revlinkqual; + + + frame_len = tvb_length(tvb); + + lwm_cmd = tvb_get_guint8(tvb, 0); + lwm_src_addr = tvb_get_letohs(tvb, 1); + lwm_dst_addr = tvb_get_letohs(tvb, 3); + lwm_cmd_multi = tvb_get_guint8(tvb, 5); + lwm_revlinkqual = tvb_get_guint8(tvb, 7); + + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING)); + + + if(tree){ + proto_root = proto_tree_add_protocol_format(tree, proto_lwm, tvb, 0, -1, "%s", val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING)); + lwm_cmd_tree = proto_item_add_subtree(proto_root, ett_lwm_cmd_tree); + } + + + if(frame_len ==LWM_CMD_FRAME_ROUTE_REPLY_LEN){ + + /* Create subtree for the Ack frame*/ + if(tree){ + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd, tvb, 0, 1, lwm_cmd); + proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, lwm_src_addr); + ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, lwm_dst_addr); + + if(lwm_cmd_multi == LWM_CMD_MULTI_ADDR_TRUE){ + proto_item_append_text(ti, " %s",LWM_MULTI_GROUP_STRING); + }else{ + proto_item_append_text(ti, " %s",LWM_MULTI_UNICAST_STRING); + } + + proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA); + proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_forwlinkquality, tvb, 6, 1, ENC_NA); + ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_revlinkquality, tvb, 7, 1, lwm_revlinkqual); + if(lwm_revlinkqual == 255){ + proto_item_append_text(ti, " %s",LWM_CMD_LINKQ_STRING); + } + } + + }else{ + expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error, + "Size is %i byte(s), instead of %i bytes",frame_len,LWM_CMD_FRAME_ROUTE_REPLY_LEN); + } + +} /* dissect_lwm_cmd_frame_route_reply*/ + +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_register_lwm + * DESCRIPTION + * IEEE 802.15.4 protocol registration routine. + * PARAMETERS + * none + * RETURNS + * void + *--------------------------------------------------------------- + */ +void proto_register_lwm(void) +{ + + static hf_register_info hf[] = { + + /*Frame control field*/ + { &hf_lwm_fcf, + { "Frame control field", "lwm.fcf", FT_UINT8, BASE_HEX, NULL, 0x0, + "Control information for the frame.", HFILL }}, + + { &hf_lwm_fcf_ack_req, + { "Acknowledgment Request", "lwm.ack_req", FT_BOOLEAN, 8, NULL, LWM_FCF_ACK_REQUEST, + "Specifies whether an acknowledgment is required from the destination node.", HFILL }}, + + { &hf_lwm_fcf_security, + { "Security Enabled", "lwm.security", FT_BOOLEAN, 8, NULL, LWM_FCF_SEC_EN, + "Specifies whether the frame payload is encrypted.", HFILL }}, + + { &hf_lwm_fcf_linklocal, + { "Link Local", "lwm.linklocal", FT_BOOLEAN, 8, NULL, LWM_FCF_LINK_LOCAL, + "It may be set to one to prevent neighboring nodes from rebroadcasting a frame.", HFILL }}, + + { &hf_lwm_fcf_multicast, + { "Multicast", "lwm.multicast", FT_BOOLEAN, 8, NULL, LWM_FCF_MULTICAST, + "If the Multicast subfield is set to one, Multicast Header should be present and the Destination Address is a group address.", HFILL }}, + + { &hf_lwm_fcf_reserved, + { "Reserved bits", "lwm.fcf.reserved",FT_UINT8, BASE_HEX, NULL, LWM_FCF_RESERVED, + "The 4 bits are reserved.", HFILL }}, + + /*Other fields*/ + { &hf_lwm_seq, + { "Sequence Number", "lwm.seq", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies the sequence identifier for the frame.", HFILL }}, + + { &hf_lwm_src_addr, + { "Network Source Address", "lwm.src_addr", FT_UINT16, BASE_HEX, NULL, 0x0, + "Specifies the network address of the node originating the frame.", HFILL }}, + + { &hf_lwm_dst_addr, + { "Network Destination Address", "lwm.dst_addr", FT_UINT16, BASE_HEX, NULL, 0x0, + "Specifies the network address of the destination node or group address for multicast messages.", HFILL }}, + + { &hf_lwm_src_endp, + { "Source Endpoint", "lwm.src_endp", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies the source endpoint identifier.", HFILL }}, + + { &hf_lwm_dst_endp, + { "Destination Endpoint", "lwm.dst_endp", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies the destination endpoint identifier.", HFILL }}, + + + /*Multicast header*/ + { &hf_lwm_multi_nmrad, + { "Non-member Radius", "lwm.multi_nmrad", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies remaining radius (number of hops) for Non-members of multicast group.", HFILL }}, + + { &hf_lwm_multi_mnmrad, + { "Maximum Non-member Radius", "lwm.multi_mnmrad", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies maximum radius (number of hops) for Non-members of multicast group.", HFILL }}, + + { &hf_lwm_multi_mrad, + { "Member Radius", "lwm.multi_mrad", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies remaining radius (number of hops) for Members of multicast group.", HFILL }}, + + { &hf_lwm_multi_mmrad, + { "Maximum Member Radius", "lwm.multi_mmrad", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies maximum radius (number of hops) for Members of multicast group.", HFILL }}, + + + /*MIC, security*/ + { &hf_lwm_mic, + { "Message Integrity Code", "lwm.mic", FT_UINT32, BASE_HEX, NULL, 0x0, + "Specifies Message Integrity Code (MIC).", HFILL }}, + + + /*----------------------------------*/ + /* */ + /* Command Frames Specific Fields */ + /* */ + /*----------------------------------*/ + + { &hf_lwm_cmd, + { "Command ID", "lwm.cmd", FT_UINT8, BASE_HEX, VALS(lwm_cmd_names), 0x0, + "It contains Command ID value.", HFILL }}, + + /* Command Frame - Ack */ + { &hf_lwm_cmd_seq, + { "Sequence number", "lwm.cmd.seq", FT_UINT8, BASE_DEC, NULL, 0x0, + "It contains a network sequence number of a frame that is being acknowledged.", HFILL }}, + + { &hf_lwm_cmd_cm, + { "Control Message", "lwm.cmd.cm", FT_UINT8, BASE_HEX, NULL, 0x0, + "It contains an arbitrary value that can be set on the sending side.", HFILL }}, + + /* Part of Command Frames - Route Request, Route Reply*/ + { &hf_lwm_cmd_route_src, + { "Source address", "lwm.cmd.route_src", FT_UINT16, BASE_HEX, NULL, 0x0, + "It contains a source network address from the frame that cannot be routed", HFILL }}, + + { &hf_lwm_cmd_route_dst, + { "Destination Address", "lwm.cmd.route_dst", FT_UINT16, BASE_HEX, NULL, 0x0, + "It contains a destination network address from the frame that cannot be routed", HFILL }}, + + { &hf_lwm_cmd_route_multi, + { "Multicast", "lwm.cmd.multi", FT_UINT8, BASE_HEX, VALS(&lwm_cmd_multi_names), 0x0, + "If it set to 0, Destination Address field contains a network address. If it set to 1, Destination Address field contains a group ID.", HFILL }}, + + /* Part of Command Frame - Route Request */ + { &hf_lwm_cmd_linkquality, + { "Link Quality", "lwm.cmd.linkq", FT_UINT8, BASE_DEC, NULL, 0x0, + "It contains a link quality value of the potential route accumulated over all hops towards the destination.", HFILL }}, + + /* Part of Command Frame - Route Reply */ + { &hf_lwm_cmd_forwlinkquality, + { "Forward Link Quality", "lwm.cmd.flinkq", FT_UINT8, BASE_DEC, NULL, 0x0, + "It contains a value of the Link Quality field from the corresponding Route Request Command Frame.", HFILL }}, + + { &hf_lwm_cmd_revlinkquality, + { "Reverse Link Quality", "lwm.cmd.rlinkq", FT_UINT8, BASE_DEC, NULL, 0x0, + "It contains a link quality value of the discovered route accumulated over all hops towards the originator.", HFILL }}, + + + }; + + /* Subtrees */ + static gint *ett[] = { + &ett_lwm, + &ett_lwm_fcf, + &ett_lwm_multi_tree, + &ett_lwm_cmd_tree + }; + + static ei_register_info ei[] = { + { &ei_lwm_mal_error, { "lwm.malformed_error", PI_MALFORMED, PI_ERROR, "Malformed Packet", EXPFILL }}, + { &ei_lwm_n_src_broad, { "lwm.not_src_broadcast", PI_COMMENTS_GROUP, PI_NOTE, "Source address can not be broadcast address !", EXPFILL }}, + { &ei_lwm_missmatch_endp, { "lwm.missmatch_endp", PI_COMMENTS_GROUP, PI_WARN, "Stack command Endpoints missmatch (should be 0, both)!", EXPFILL }}, + { &ei_lwm_empty_payload, { "lwm.empty_payload", PI_COMMENTS_GROUP, PI_WARN, "Empty LwMesh Payload!", EXPFILL }}, + + + + }; + + expert_module_t* expert_lwm; + + /* Register protocol name and description. */ + proto_lwm = proto_register_protocol("Lightweight Mesh (v1.1.1)", "LwMesh", "lwm"); + + /* Register header fields and subtrees. */ + proto_register_field_array(proto_lwm, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_lwm = expert_register_protocol(proto_lwm); + expert_register_field_array(expert_lwm, ei, array_length(ei)); + + /* Register dissector with Wireshark. */ + register_dissector("lwm", dissect_lwm, proto_lwm); + +} /* proto_register_lwm */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_reg_handoff_lwm + * DESCRIPTION + * Registers the zigbee dissector with Wireshark. + * Will be called every time 'apply' is pressed in the preferences menu. + * PARAMETERS + * none + * RETURNS + * void + *--------------------------------------------------------------- + */ +void proto_reg_handoff_lwm(void) +{ + static gboolean lwm_inited = FALSE; + + if ( !lwm_inited ) + { + data_handle = find_dissector("data"); + + /* Register our dissector with IEEE 802.15.4 */ + heur_dissector_add("wpan", dissect_lwm_heur, proto_lwm); + + lwm_inited = TRUE; + } + +} /* proto_reg_handoff_lwm */ + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ -- cgit v1.2.3