2 * Dissector routines for the ATMEL Lightweight Mesh 1.1.1
3 * Copyright 2013 Martin Leixner <info@sewio.net>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *------------------------------------------------------------
27 #include <epan/packet.h>
28 #include <epan/expert.h>
30 #include <wsutil/filesystem.h>
31 #include "packet-ieee802154.h"
32 #include <epan/prefs.h>
33 #include <epan/strutil.h>
34 #include <wsutil/wsgcrypt.h>
37 #define LWM_HEADER_BASE_LEN 7
39 #define LWM_MULTI_HEADER_LEN 2
41 /* Bit-masks for the FCF */
42 #define LWM_FCF_ACK_REQUEST 0x01
43 #define LWM_FCF_SEC_EN 0x02
45 #define LWM_FCF_LINK_LOCAL 0x04
46 #define LWM_FCF_MULTICAST 0x08
48 #define LWM_FCF_RESERVED 0xF0
50 #define LWM_MULTI_NON_MEM_RAD_MASK 0x000F
51 #define LWM_MULTI_NON_MEM_RAD_OFFSET 0
53 #define LWM_MULTI_MAX_NON_MEM_RAD_MASK 0x00F0
54 #define LWM_MULTI_MAX_NON_MEM_RAD_OFFSET 4
56 #define LWM_MULTI_MEM_RAD_MASK 0x0F00
57 #define LWM_MULTI_MEM_RAD_OFFSET 8
59 #define LWM_MULTI_MAX_MEM_RAD_MASK 0xF000
60 #define LWM_MULTI_MAX_MEM_RAD_OFFSET 12
63 #define LWM_SRC_ENDP_MASK 0xF0
64 #define LWM_SRC_ENDP_OFFSET 4
65 #define LWM_DST_ENDP_MASK 0x0F
66 #define LWM_DST_ENDP_OFFSET 0
69 #define LWM_BCAST_ADDR 0xFFFF
72 #define LWM_CMD_ACK 0x00
73 #define LWM_CMD_ROUTE_ERR 0x01
74 #define LWM_CMD_ROUTE_REQ 0x02
75 #define LWM_CMD_ROUTE_REPLY 0x03
77 /*Lengths of command frames*/
78 #define LWM_CMD_FRAME_ACK_LEN 3
79 #define LWM_CMD_FRAME_ROUTE_ERR_LEN 6
80 #define LWM_CMD_FRAME_ROUTE_REQ_LEN 7
81 #define LWM_CMD_FRAME_ROUTE_REPLY_LEN 8
83 /*Values for multicast field*/
84 #define LWM_CMD_MULTI_ADDR_FALSE 0
85 #define LWM_CMD_MULTI_ADDR_TRUE 1
88 #define LWM_CMD_LINKQ_STRING "(Sent by Originate node)"
89 #define LWM_CMD_UNKNOWN_VAL_STRING "Unknown command (0x%02x)"
91 #define LWM_MULTI_UNICAST_STRING "(Unicast)"
92 #define LWM_MULTI_GROUP_STRING "(Group ID)"
94 /* Function declarations */
95 void proto_register_lwm(void);
96 void proto_reg_handoff_lwm(void);
98 /* Dissector handles */
99 static dissector_handle_t data_handle;
101 /* User string with the decryption key. */
102 static const gchar *lwmes_key_str = NULL;
103 static gboolean lwmes_key_valid;
104 static guint8 lwmes_key[16];
106 /* Dissection Routines. */
107 static int dissect_lwm (tvbuff_t *, packet_info *, proto_tree *, void *data);
108 static int dissect_lwm_cmd_frame_ack (tvbuff_t *, packet_info *, proto_tree *);
109 static int dissect_lwm_cmd_frame_route_err (tvbuff_t *, packet_info *, proto_tree *);
110 static int dissect_lwm_cmd_frame_route_req (tvbuff_t *, packet_info *, proto_tree *);
111 static int dissect_lwm_cmd_frame_route_reply (tvbuff_t *, packet_info *, proto_tree *);
113 /* Initialize protocol and registered fields. */
114 static int proto_lwm = -1;
116 static int hf_lwm_fcf = -1;
117 static int hf_lwm_fcf_ack_req = -1;
118 static int hf_lwm_fcf_security = -1;
119 static int hf_lwm_fcf_linklocal = -1;
120 static int hf_lwm_fcf_multicast = -1;
121 static int hf_lwm_fcf_reserved = -1;
122 static int hf_lwm_seq = -1;
123 static int hf_lwm_src_addr = -1;
124 static int hf_lwm_dst_addr = -1;
125 static int hf_lwm_src_endp = -1;
126 static int hf_lwm_dst_endp = -1;
127 static int hf_lwm_multi_nmrad = -1;
128 static int hf_lwm_multi_mnmrad = -1;
129 static int hf_lwm_multi_mrad = -1;
130 static int hf_lwm_multi_mmrad = -1;
131 static int hf_lwm_mic = -1;
132 static int hf_lwm_cmd = -1;
133 static int hf_lwm_cmd_seq = -1;
134 static int hf_lwm_cmd_cm = -1;
135 static int hf_lwm_cmd_route_src = -1;
136 static int hf_lwm_cmd_route_dst = -1;
137 static int hf_lwm_cmd_route_multi = -1;
138 static int hf_lwm_cmd_linkquality = -1;
139 static int hf_lwm_cmd_forwlinkquality = -1;
140 static int hf_lwm_cmd_revlinkquality = -1;
142 /* Initialize protocol subtrees. */
143 static gint ett_lwm = -1;
144 static gint ett_lwm_fcf = -1;
145 static gint ett_lwm_cmd_tree = -1;
146 static gint ett_lwm_multi_tree = -1;
148 static expert_field ei_lwm_mal_error = EI_INIT;
149 static expert_field ei_lwm_n_src_broad = EI_INIT;
150 static expert_field ei_lwm_mismatch_endp = EI_INIT;
151 static expert_field ei_lwm_empty_payload = EI_INIT;
152 static expert_field ei_lwm_no_decryption_key = EI_INIT;
153 static expert_field ei_lwm_decryption_failed = EI_INIT;
155 static const value_string lwm_cmd_names[] = {
156 { LWM_CMD_ACK, "LwMesh ACK" },
157 { LWM_CMD_ROUTE_ERR, "Route Error" },
158 { LWM_CMD_ROUTE_REQ, "Route Request" },
159 { LWM_CMD_ROUTE_REPLY, "Route Reply" },
163 static const value_string lwm_cmd_multi_names[] = {
164 { LWM_CMD_MULTI_ADDR_FALSE, "FALSE" },
165 { LWM_CMD_MULTI_ADDR_TRUE, "TRUE" },
169 /*FUNCTION:------------------------------------------------------
173 * Heuristic interpreter for the Lightweight Mesh.
175 * tvbuff_t *tvb - pointer to buffer containing raw packet.
176 * packet_into *pinfo - pointer to packet information fields
177 * proto_tree *tree - pointer to data tree Wireshark uses to display packet.
179 * Boolean value, whether it handles the packet or not.
180 *---------------------------------------------------------------
183 dissect_lwm_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
185 /* 1) first byte must have bits 0000xxxx */
186 if(tvb_get_guint8(tvb, 0) & LWM_FCF_RESERVED)
189 /* The header should be at least long enough for the base header. */
190 if (tvb_reported_length(tvb) < LWM_HEADER_BASE_LEN)
193 dissect_lwm(tvb, pinfo, tree, data);
195 } /* dissect_lwm_heur */
197 /*FUNCTION:------------------------------------------------------
201 * Lightweight Mesh packet dissection routine for Wireshark.
203 * tvbuff_t *tvb - pointer to buffer containing raw packet.
204 * packet_info *pinfo - pointer to packet information fields
205 * proto_tree *tree - pointer to data tree Wireshark uses to display packet.
207 * int - length of data processed, or 0 if not LWM.
208 *---------------------------------------------------------------
210 static int dissect_lwm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
212 guint lwm_header_len;
215 gboolean lwm_fcf_security;
216 gboolean lwm_fcf_multicast;
220 guint16 lwm_src_addr;
221 guint16 lwm_dst_addr;
222 guint8 lwm_endp_field;
226 proto_tree *lwm_tree = NULL;
227 proto_item *ti_proto = NULL;
231 /*---------------------------------------------------------*/
233 /*Enter name of protocol to info field*/
234 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LwMesh");
235 col_clear(pinfo->cinfo, COL_INFO);
237 /*Set base length of LWM header*/
238 lwm_header_len = LWM_HEADER_BASE_LEN;
240 /*--------------------------------------------------*/
242 /* Create LwMesh dissector tree */
244 /*--------------------------------------------------*/
246 /*Create subtree for the LwMesh*/
247 ti_proto = proto_tree_add_protocol_format(tree, proto_lwm, tvb, 0, -1, "Lightweight Mesh");
248 lwm_tree = proto_item_add_subtree(ti_proto, ett_lwm);
251 col_add_fstr(pinfo->cinfo, COL_INFO, "Lightweight Mesh");
253 /*--------------------------------------------------*/
255 /* Display LwMesh dissector tree */
257 /*--------------------------------------------------*/
259 /*Frame control fields*/
260 lwm_fcf = tvb_get_guint8(tvb, 0);
262 lwm_fcf_security = (lwm_fcf & LWM_FCF_SEC_EN);
263 lwm_fcf_multicast = (lwm_fcf & LWM_FCF_MULTICAST);
266 proto_tree *field_tree;
267 ti = proto_tree_add_uint(lwm_tree, hf_lwm_fcf, tvb, 0, 1, lwm_fcf);
269 field_tree = proto_item_add_subtree(ti, ett_lwm_fcf);
270 proto_tree_add_item(field_tree, hf_lwm_fcf_ack_req, tvb, 0, 1, ENC_NA);
272 proto_tree_add_item(field_tree, hf_lwm_fcf_security, tvb, 0, 1, ENC_NA);
273 proto_tree_add_item(field_tree, hf_lwm_fcf_linklocal, tvb, 0, 1, ENC_NA);
274 proto_tree_add_item(field_tree, hf_lwm_fcf_multicast, tvb, 0, 1, ENC_NA);
275 proto_tree_add_item(field_tree, hf_lwm_fcf_reserved, tvb, 0, 1, ENC_NA);
279 lwm_seq = tvb_get_guint8(tvb, 1);
280 proto_item_append_text(ti_proto, ", Sequence Number: %i", lwm_seq);
281 proto_tree_add_uint(lwm_tree, hf_lwm_seq, tvb, 1, 1, lwm_seq);
283 /*Network addresses*/
285 /*Parse Source address*/
286 lwm_src_addr = tvb_get_letohs(tvb, 2);
288 ti = proto_tree_add_uint(lwm_tree, hf_lwm_src_addr, tvb, 2, 2, lwm_src_addr);
290 if(lwm_src_addr < 0x8000){
291 proto_item_append_text(ti, " (Routing node)");
293 proto_item_append_text(ti, " (Non-routing node)");
296 /*Check value of source address*/
297 if(lwm_src_addr == LWM_BCAST_ADDR){
298 expert_add_info(pinfo, lwm_tree, &ei_lwm_n_src_broad);
301 /*Parse Destination address*/
302 lwm_dst_addr = tvb_get_letohs(tvb, 4);
304 if(lwm_dst_addr == LWM_BCAST_ADDR){
305 proto_tree_add_uint_format_value(lwm_tree, hf_lwm_dst_addr, tvb, 4, 2, lwm_dst_addr,
306 "Broadcast (0x%04x)", lwm_dst_addr);
308 ti = proto_tree_add_uint(lwm_tree, hf_lwm_dst_addr, tvb, 4, 2, lwm_dst_addr);
310 if(lwm_fcf_multicast){
311 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
313 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
315 if(lwm_dst_addr < 0x8000){
316 proto_item_append_text(ti, " (Routing node)");
318 proto_item_append_text(ti, " (Non-routing node)");
323 /*Enter description to info field*/
324 col_append_fstr(pinfo->cinfo, COL_INFO, ", Nwk_Dst: 0x%04x, Nwk_Src: 0x%04x", lwm_dst_addr, lwm_src_addr);
327 lwm_endp_field = tvb_get_guint8(tvb, 6);
328 lwm_src_endp = (lwm_endp_field & LWM_SRC_ENDP_MASK) >> LWM_SRC_ENDP_OFFSET;
329 lwm_dst_endp = (lwm_endp_field & LWM_DST_ENDP_MASK) >> LWM_DST_ENDP_OFFSET;
331 ti = proto_tree_add_uint(lwm_tree, hf_lwm_src_endp, tvb, 6, 1, lwm_src_endp);
332 if(lwm_src_endp == 0){
333 proto_item_append_text(ti, " (Stack command endpoint)");
336 ti = proto_tree_add_uint(lwm_tree, hf_lwm_dst_endp, tvb, 6, 1, lwm_dst_endp);
337 if(lwm_dst_endp == 0){
338 proto_item_append_text(ti, " (Stack command endpoint)");
341 if( (lwm_src_endp == 0) && (lwm_dst_endp == 0)){
342 /*stack command endpoints*/
345 else if( (lwm_src_endp == 0) || (lwm_dst_endp == 0)){
346 /*If only one endpoint is 0, alert about that*/
348 col_append_str(pinfo->cinfo, COL_INFO, "[Stack command Endpoints mismatch]");
350 expert_add_info(pinfo, lwm_tree, &ei_lwm_mismatch_endp);
354 if( (lwm_fcf_multicast) ){
356 lwm_header_len += LWM_MULTI_HEADER_LEN;
359 proto_tree *multi_tree;
360 guint16 lwm_multi_header;
362 lwm_multi_header = tvb_get_letohs(tvb, 7);
363 multi_tree = proto_tree_add_subtree(lwm_tree, tvb, 7, 2, ett_lwm_multi_tree, NULL, "Multicast Header");
365 proto_tree_add_uint(multi_tree, hf_lwm_multi_nmrad, tvb, 7, 2,
366 (lwm_multi_header & LWM_MULTI_NON_MEM_RAD_MASK) >> LWM_MULTI_NON_MEM_RAD_OFFSET);
367 proto_tree_add_uint(multi_tree, hf_lwm_multi_mnmrad, tvb, 7, 2,
368 (lwm_multi_header & LWM_MULTI_MAX_NON_MEM_RAD_MASK) >> LWM_MULTI_MAX_NON_MEM_RAD_OFFSET);
369 proto_tree_add_uint(multi_tree, hf_lwm_multi_mrad, tvb, 7, 2,
370 (lwm_multi_header & LWM_MULTI_MEM_RAD_MASK) >> LWM_MULTI_MEM_RAD_OFFSET);
371 proto_tree_add_uint(multi_tree, hf_lwm_multi_mmrad, tvb, 7, 2,
372 (lwm_multi_header & LWM_MULTI_MAX_MEM_RAD_MASK) >> LWM_MULTI_MAX_MEM_RAD_OFFSET);
377 /*------------------------------*/
379 /* Dissect payload */
381 /*------------------------------*/
383 /*Note: exception will already have occurred if "short header"*/
385 if (tvb_reported_length(tvb) <= lwm_header_len) {
387 expert_add_info(pinfo, lwm_tree, &ei_lwm_empty_payload);
388 col_append_str(pinfo->cinfo, COL_INFO, "[Empty LwMesh Payload]");
390 return tvb_captured_length(tvb);
393 new_tvb = tvb_new_subset_remaining(tvb, lwm_header_len);
396 if(lwm_fcf_security){
402 rlen = tvb_reported_length(new_tvb);
403 start = (rlen >= LWM_MIC_LEN) ? (rlen-LWM_MIC_LEN) : 0;
404 /*An exception will occur if there are not enough bytes for the MIC */
405 proto_tree_add_item_ret_uint(lwm_tree, hf_lwm_mic, new_tvb, start, LWM_MIC_LEN, ENC_LITTLE_ENDIAN, &lwm_mic);
407 #ifdef HAVE_LIBGCRYPT
410 ieee802154_packet *ieee_packet = NULL;
411 gint payload_length = 0;
413 gint payload_offset = 0;
415 tvbuff_t *decrypted_tvb;
416 gcry_cipher_hd_t cypher_hd;
417 guint8* vector = NULL;
419 guint8* text_dec =NULL;
422 guint32 nwkSecurityVector[4];
424 ieee_packet = (ieee802154_packet *)data;
426 nwkSecurityVector[0] = lwm_seq;
427 nwkSecurityVector[1] = ((guint32)lwm_dst_addr<< 16) | lwm_dst_endp;
428 nwkSecurityVector[2]= ((guint32) lwm_src_addr<< 16) | lwm_src_endp;
429 nwkSecurityVector[3] = ((guint32)ieee_packet->dst_pan << 16) | (guint8)lwm_fcf;
431 payload_length=tvb_reported_length(new_tvb) - LWM_MIC_LEN;
433 /* ECB - Nwk security vector*/
434 text = (guint8 *)tvb_memdup(NULL, new_tvb, 0, payload_length);
437 /*Decrypt the actual data */
438 while(payload_length>0)
442 gcrypt_err = gcry_cipher_open(&cypher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0);
443 if(gcrypt_err == 0) {
444 gcrypt_err = gcry_cipher_setkey(cypher_hd,(guint8 *)lwmes_key, 16);
446 if(gcrypt_err == 0) {
447 gcrypt_err = gcry_cipher_encrypt(cypher_hd,(guint8 *)nwkSecurityVector,16,(guint8 *)nwkSecurityVector,16);
452 col_add_fstr(pinfo->cinfo, COL_INFO,
453 "Encrypted data (%i byte(s)) DECRYPT FAILED",
454 tvb_reported_length(new_tvb) - LWM_MIC_LEN);
455 expert_add_info(pinfo, lwm_tree, &ei_lwm_decryption_failed);
456 tvb_set_reported_length(new_tvb, tvb_reported_length(new_tvb) - LWM_MIC_LEN);
457 call_dissector(data_handle, new_tvb, pinfo, lwm_tree);
460 text_dec = &text[payload_offset];
461 vector = (guint8 *)nwkSecurityVector;
462 block = (payload_length < 16) ? payload_length : 16;
464 for (i = 0; i < block; i++)
466 text_dec[i] ^= vector[i];
467 vector[i] ^= text_dec[i];
470 payload_offset += block;
471 payload_length -= block;
472 gcry_cipher_close(cypher_hd);
475 vmic = nwkSecurityVector[0] ^ nwkSecurityVector[1] ^ nwkSecurityVector[2] ^ nwkSecurityVector[3];
476 length = tvb_reported_length(new_tvb) - LWM_MIC_LEN;
480 decrypted_tvb = tvb_new_real_data(text,length, length);
481 call_dissector(data_handle, decrypted_tvb, pinfo, lwm_tree);
483 tvb_set_free_cb(decrypted_tvb, g_free);
484 add_new_data_source(pinfo, decrypted_tvb, "Decrypted LWmesh Payload"); */
485 col_append_fstr(pinfo->cinfo, COL_INFO, ", MIC SUCCESS");
490 col_add_fstr(pinfo->cinfo, COL_INFO,
491 "Encrypted data (%i byte(s)) MIC FAILURE",
492 tvb_reported_length(new_tvb) - LWM_MIC_LEN);
493 tvb_set_reported_length(new_tvb, tvb_reported_length(new_tvb) - LWM_MIC_LEN);
494 call_dissector(data_handle, new_tvb, pinfo, lwm_tree);
499 col_add_fstr(pinfo->cinfo, COL_INFO,
500 "Encrypted data (%i byte(s)) NO DECRYPT KEY",
501 tvb_reported_length(new_tvb) - LWM_MIC_LEN);
503 expert_add_info(pinfo, lwm_tree, &ei_lwm_no_decryption_key);
504 tvb_set_reported_length(new_tvb, tvb_reported_length(new_tvb) - LWM_MIC_LEN);
505 call_dissector(data_handle, new_tvb, pinfo, lwm_tree);
507 #else /* ! HAVE_LIBGCRYPT */
508 col_add_fstr(pinfo->cinfo, COL_INFO,
509 "Encrypted data (%i byte(s)): libgcrypt not present, cannot decrypt",
510 tvb_reported_length(new_tvb) - LWM_MIC_LEN);
512 expert_add_info(pinfo, lwm_tree, &ei_lwm_no_decryption_key);
513 tvb_set_reported_length(new_tvb, tvb_reported_length(new_tvb) - LWM_MIC_LEN);
514 call_dissector(data_handle, new_tvb, pinfo, lwm_tree);
515 #endif /* ! HAVE_LIBGCRYPT */
517 /*stack command endpoint 0 and not secured*/
518 else if( (lwm_src_endp == 0) && (lwm_dst_endp == 0) ){
519 proto_tree *lwm_cmd_tree;
523 /*----------------------------------------------------------------------*/
525 /* Call command dissector (depends on value of first byte of payload) */
527 /*----------------------------------------------------------------------*/
528 lwm_cmd = tvb_get_guint8(new_tvb, 0);
530 col_clear(pinfo->cinfo, COL_INFO); /*XXX: why ?*/
531 col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
532 val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING));
534 lwm_cmd_tree = proto_tree_add_subtree(lwm_tree, new_tvb, 0, -1, ett_lwm_cmd_tree, &ti,
535 val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING));
537 proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd, new_tvb, 0, 1, lwm_cmd);
542 len = dissect_lwm_cmd_frame_ack(new_tvb, pinfo, lwm_cmd_tree);
545 case LWM_CMD_ROUTE_ERR:
546 len = dissect_lwm_cmd_frame_route_err(new_tvb, pinfo, lwm_cmd_tree);
549 case LWM_CMD_ROUTE_REQ:
550 len = dissect_lwm_cmd_frame_route_req(new_tvb, pinfo, lwm_cmd_tree);
553 case LWM_CMD_ROUTE_REPLY:
554 len = dissect_lwm_cmd_frame_route_reply(new_tvb, pinfo, lwm_cmd_tree);
559 expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error, "Unknown command");
560 call_dissector(data_handle, new_tvb, pinfo, lwm_cmd_tree);
561 return tvb_captured_length(tvb);
564 proto_item_set_len(ti, len);
566 /*Here only if additional data after valid 'cmd' data*/
567 /*Note: exception will have already occurred if tvb was missing required bytes for 'cmd'*/
568 /* Report error if additional undissected data*/
569 if (len < tvb_reported_length(new_tvb)) {
570 /*unknown additional data*/
571 expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error,
572 "Size is %i byte(s), instead of %i bytes", tvb_reported_length(new_tvb), len);
574 new_tvb = tvb_new_subset_remaining(new_tvb, len);
575 call_dissector(data_handle, new_tvb, pinfo, lwm_tree);
580 call_dissector(data_handle, new_tvb, pinfo, lwm_tree);
582 return tvb_captured_length(tvb);
585 /*FUNCTION:------------------------------------------------------
587 * dissect_lwm_cmd_frame_ack
589 * LwMesh command frame - Ack.
592 * tvbuff_t *tvb - pointer to buffer containing raw packet.
593 * packet_info *pinfo - pointer to packet information fields
594 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
596 * int length - amount of data processed
597 *---------------------------------------------------------------
599 static int dissect_lwm_cmd_frame_ack(tvbuff_t *tvb, packet_info *pinfo, proto_tree *lwm_cmd_tree)
604 lwm_seq = tvb_get_guint8(tvb, 1);
606 col_append_fstr(pinfo->cinfo, COL_INFO, ", Sequence number: %d", lwm_seq);
609 proto_item_append_text(proto_tree_get_parent(lwm_cmd_tree), ", Sequence number: %d", lwm_seq);
610 proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_seq, tvb, 1, 1, lwm_seq);
611 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_cm, tvb, 2, 1, ENC_NA);
614 return LWM_CMD_FRAME_ACK_LEN;
616 } /* dissect_lwm_cmd_frame_ack*/
618 /*FUNCTION:------------------------------------------------------
620 * dissect_lwm_cmd_frame_route_err
622 * LwMesh command frame - Route error.
625 * tvbuff_t *tvb - pointer to buffer containing raw packet.
626 * packet_info *pinfo - pointer to packet information fields
627 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
629 * int length - amount of data processed
630 *---------------------------------------------------------------
632 static int dissect_lwm_cmd_frame_route_err(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *lwm_cmd_tree)
637 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, ENC_LITTLE_ENDIAN);
638 ti = proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, ENC_LITTLE_ENDIAN);
640 if(tvb_get_guint8(tvb, 5) == LWM_CMD_MULTI_ADDR_TRUE){
641 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
643 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
646 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA);
649 return LWM_CMD_FRAME_ROUTE_ERR_LEN;
651 } /* dissect_lwm_cmd_frame_route_err*/
653 /*FUNCTION:------------------------------------------------------
655 * dissect_lwm_cmd_frame_route_req
657 * LwMesh command frame - Route Request.
660 * tvbuff_t *tvb - pointer to buffer containing raw packet.
661 * packet_info *pinfo - pointer to packet information fields
662 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
664 * int length - amount of data processed
665 *---------------------------------------------------------------
667 static int dissect_lwm_cmd_frame_route_req(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *lwm_cmd_tree)
673 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, ENC_LITTLE_ENDIAN);
674 ti = proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, ENC_LITTLE_ENDIAN);
676 if(tvb_get_guint8(tvb, 5) == LWM_CMD_MULTI_ADDR_TRUE){
677 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
679 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
682 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA);
684 lwm_linkqual = tvb_get_guint8(tvb, 6);
685 ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_linkquality, tvb, 6, 1, lwm_linkqual);
686 if(lwm_linkqual == 255){
687 proto_item_append_text(ti, " %s", LWM_CMD_LINKQ_STRING);
691 return LWM_CMD_FRAME_ROUTE_REQ_LEN;
693 } /* dissect_lwm_cmd_frame_route_req*/
695 /*FUNCTION:------------------------------------------------------
697 * dissect_lwm_cmd_frame_route_reply
699 * LwMesh command frame - Route Reply.
702 * tvbuff_t *tvb - pointer to buffer containing raw packet.
703 * packet_info *pinfo - pointer to packet information fields
704 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
706 * int length - amount of data processed
707 *---------------------------------------------------------------
709 static int dissect_lwm_cmd_frame_route_reply(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *lwm_cmd_tree)
713 guint8 lwm_revlinkqual;
715 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, ENC_LITTLE_ENDIAN);
716 ti = proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, ENC_LITTLE_ENDIAN);
718 if(tvb_get_guint8(tvb, 5) == LWM_CMD_MULTI_ADDR_TRUE){
719 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
721 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
724 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA);
725 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_forwlinkquality, tvb, 6, 1, ENC_NA);
727 lwm_revlinkqual = tvb_get_guint8(tvb, 7);
728 ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_revlinkquality, tvb, 7, 1, lwm_revlinkqual);
729 if(lwm_revlinkqual == 255){
730 proto_item_append_text(ti, " %s", LWM_CMD_LINKQ_STRING);
734 return LWM_CMD_FRAME_ROUTE_REPLY_LEN;
736 } /* dissect_lwm_cmd_frame_route_reply*/
738 /*FUNCTION:------------------------------------------------------
742 * IEEE 802.15.4 protocol registration routine.
747 *---------------------------------------------------------------
749 void proto_register_lwm(void)
752 static hf_register_info hf[] = {
754 /*Frame control field*/
756 { "Frame control field", "lwm.fcf", FT_UINT8, BASE_HEX, NULL, 0x0,
757 "Control information for the frame.", HFILL }},
759 { &hf_lwm_fcf_ack_req,
760 { "Acknowledgment Request", "lwm.ack_req", FT_BOOLEAN, 8, NULL, LWM_FCF_ACK_REQUEST,
761 "Specifies whether an acknowledgment is required from the destination node.", HFILL }},
763 { &hf_lwm_fcf_security,
764 { "Security Enabled", "lwm.security", FT_BOOLEAN, 8, NULL, LWM_FCF_SEC_EN,
765 "Specifies whether the frame payload is encrypted.", HFILL }},
767 { &hf_lwm_fcf_linklocal,
768 { "Link Local", "lwm.linklocal", FT_BOOLEAN, 8, NULL, LWM_FCF_LINK_LOCAL,
769 "It may be set to one to prevent neighboring nodes from rebroadcasting a frame.", HFILL }},
771 { &hf_lwm_fcf_multicast,
772 { "Multicast", "lwm.multicast", FT_BOOLEAN, 8, NULL, LWM_FCF_MULTICAST,
773 "If the Multicast subfield is set to one, Multicast Header should be present and the Destination Address is a group address.", HFILL }},
775 { &hf_lwm_fcf_reserved,
776 { "Reserved bits", "lwm.fcf.reserved", FT_UINT8, BASE_HEX, NULL, LWM_FCF_RESERVED,
777 "The 4 bits are reserved.", HFILL }},
781 { "Sequence Number", "lwm.seq", FT_UINT8, BASE_DEC, NULL, 0x0,
782 "Specifies the sequence identifier for the frame.", HFILL }},
785 { "Network Source Address", "lwm.src_addr", FT_UINT16, BASE_HEX, NULL, 0x0,
786 "Specifies the network address of the node originating the frame.", HFILL }},
789 { "Network Destination Address", "lwm.dst_addr", FT_UINT16, BASE_HEX, NULL, 0x0,
790 "Specifies the network address of the destination node or group address for multicast messages.", HFILL }},
793 { "Source Endpoint", "lwm.src_endp", FT_UINT8, BASE_DEC, NULL, 0x0,
794 "Specifies the source endpoint identifier.", HFILL }},
797 { "Destination Endpoint", "lwm.dst_endp", FT_UINT8, BASE_DEC, NULL, 0x0,
798 "Specifies the destination endpoint identifier.", HFILL }},
802 { &hf_lwm_multi_nmrad,
803 { "Non-member Radius", "lwm.multi_nmrad", FT_UINT8, BASE_DEC, NULL, 0x0,
804 "Specifies remaining radius (number of hops) for Non-members of multicast group.", HFILL }},
806 { &hf_lwm_multi_mnmrad,
807 { "Maximum Non-member Radius", "lwm.multi_mnmrad", FT_UINT8, BASE_DEC, NULL, 0x0,
808 "Specifies maximum radius (number of hops) for Non-members of multicast group.", HFILL }},
810 { &hf_lwm_multi_mrad,
811 { "Member Radius", "lwm.multi_mrad", FT_UINT8, BASE_DEC, NULL, 0x0,
812 "Specifies remaining radius (number of hops) for Members of multicast group.", HFILL }},
814 { &hf_lwm_multi_mmrad,
815 { "Maximum Member Radius", "lwm.multi_mmrad", FT_UINT8, BASE_DEC, NULL, 0x0,
816 "Specifies maximum radius (number of hops) for Members of multicast group.", HFILL }},
821 { "Message Integrity Code", "lwm.mic", FT_UINT32, BASE_HEX, NULL, 0x0,
822 "Specifies Message Integrity Code (MIC).", HFILL }},
825 /*----------------------------------*/
827 /* Command Frames Specific Fields */
829 /*----------------------------------*/
832 { "Command ID", "lwm.cmd", FT_UINT8, BASE_HEX, VALS(lwm_cmd_names), 0x0,
833 "It contains Command ID value.", HFILL }},
835 /* Command Frame - Ack */
837 { "Sequence number", "lwm.cmd.seq", FT_UINT8, BASE_DEC, NULL, 0x0,
838 "It contains a network sequence number of a frame that is being acknowledged.", HFILL }},
841 { "Control Message", "lwm.cmd.cm", FT_UINT8, BASE_HEX, NULL, 0x0,
842 "It contains an arbitrary value that can be set on the sending side.", HFILL }},
844 /* Part of Command Frames - Route Request, Route Reply*/
845 { &hf_lwm_cmd_route_src,
846 { "Source address", "lwm.cmd.route_src", FT_UINT16, BASE_HEX, NULL, 0x0,
847 "It contains a source network address from the frame that cannot be routed", HFILL }},
849 { &hf_lwm_cmd_route_dst,
850 { "Destination Address", "lwm.cmd.route_dst", FT_UINT16, BASE_HEX, NULL, 0x0,
851 "It contains a destination network address from the frame that cannot be routed", HFILL }},
853 { &hf_lwm_cmd_route_multi,
854 { "Multicast", "lwm.cmd.multi", FT_UINT8, BASE_HEX, VALS(lwm_cmd_multi_names), 0x0,
855 "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 }},
857 /* Part of Command Frame - Route Request */
858 { &hf_lwm_cmd_linkquality,
859 { "Link Quality", "lwm.cmd.linkq", FT_UINT8, BASE_DEC, NULL, 0x0,
860 "It contains a link quality value of the potential route accumulated over all hops towards the destination.", HFILL }},
862 /* Part of Command Frame - Route Reply */
863 { &hf_lwm_cmd_forwlinkquality,
864 { "Forward Link Quality", "lwm.cmd.flinkq", FT_UINT8, BASE_DEC, NULL, 0x0,
865 "It contains a value of the Link Quality field from the corresponding Route Request Command Frame.", HFILL }},
867 { &hf_lwm_cmd_revlinkquality,
868 { "Reverse Link Quality", "lwm.cmd.rlinkq", FT_UINT8, BASE_DEC, NULL, 0x0,
869 "It contains a link quality value of the discovered route accumulated over all hops towards the originator.", HFILL }},
875 static gint *ett[] = {
882 static ei_register_info ei[] = {
883 { &ei_lwm_mal_error, { "lwm.malformed_error", PI_MALFORMED, PI_ERROR, "Malformed Packet", EXPFILL }},
884 { &ei_lwm_n_src_broad, { "lwm.not_src_broadcast", PI_COMMENTS_GROUP, PI_NOTE, "Source address can not be broadcast address !", EXPFILL }},
885 { &ei_lwm_mismatch_endp, { "lwm.mismatch_endp", PI_COMMENTS_GROUP, PI_WARN, "Stack command Endpoints mismatch (should be 0, both)!", EXPFILL }},
886 { &ei_lwm_empty_payload, { "lwm.empty_payload", PI_COMMENTS_GROUP, PI_WARN, "Empty LwMesh Payload!", EXPFILL }},
887 { &ei_lwm_no_decryption_key, { "lwm.no_decryption_key", PI_PROTOCOL, PI_NOTE, "No encryption key set - can't decrypt", EXPFILL }},
888 { &ei_lwm_decryption_failed, { "lwm.decryption_failed", PI_PROTOCOL, PI_WARN, "Decryption Failed", EXPFILL }},
892 expert_module_t* expert_lwm;
894 /* Register protocol name and description. */
895 proto_lwm = proto_register_protocol("Lightweight Mesh (v1.1.1)", "LwMesh", "lwm");
897 /* Register header fields and subtrees. */
898 proto_register_field_array(proto_lwm, hf, array_length(hf));
899 proto_register_subtree_array(ett, array_length(ett));
900 expert_lwm = expert_register_protocol(proto_lwm);
901 expert_register_field_array(expert_lwm, ei, array_length(ei));
903 lw_module = prefs_register_protocol(proto_lwm,proto_reg_handoff_lwm);
905 /* Register preferences for a decryption key */
906 /* TODO: Implement a UAT for multiple keys, and with more advanced key management. */
907 prefs_register_string_preference(lw_module, "lwmes_key", "Lw Decryption key",
908 "128-bit decryption key in hexadecimal format", (const char **)&lwmes_key_str);
910 /* Register dissector with Wireshark. */
911 new_register_dissector("lwm", dissect_lwm, proto_lwm);
913 } /* proto_register_lwm */
915 /*FUNCTION:------------------------------------------------------
917 * proto_reg_handoff_lwm
919 * Registers the lwm dissector with Wireshark.
920 * Will be called during Wireshark startup.
925 *---------------------------------------------------------------
927 void proto_reg_handoff_lwm(void)
932 data_handle = find_dissector("data");
934 /* Convert key to raw bytes */
935 bytes = g_byte_array_new();
936 res = hex_str_to_bytes(lwmes_key_str, bytes, FALSE);
937 lwmes_key_valid = (res && bytes->len >= IEEE802154_CIPHER_SIZE);
938 if (lwmes_key_valid) {
939 memcpy(lwmes_key, bytes->data, IEEE802154_CIPHER_SIZE);
941 g_byte_array_free(bytes, TRUE);
944 /* Register our dissector with IEEE 802.15.4 */
945 dissector_add_for_decode_as(IEEE802154_PROTOABBREV_WPAN_PANID, find_dissector("lwm"));
946 heur_dissector_add(IEEE802154_PROTOABBREV_WPAN, dissect_lwm_heur, "Lightweight Mesh over IEEE 802.15.4", "lwm_wlan", proto_lwm, HEURISTIC_ENABLE);
948 } /* proto_reg_handoff_lwm */
956 * indent-tabs-mode: nil
959 * ex: set shiftwidth=4 tabstop=8 expandtab:
960 * :indentSize=4:tabSize=8:noTabs=true: