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 * SPDX-License-Identifier: GPL-2.0-or-later
10 *------------------------------------------------------------
15 #include <epan/packet.h>
16 #include <epan/expert.h>
18 #include <wsutil/filesystem.h>
19 #include "packet-ieee802154.h"
20 #include <epan/prefs.h>
21 #include <epan/strutil.h>
22 #include <wsutil/wsgcrypt.h>
25 #define LWM_HEADER_BASE_LEN 7
27 #define LWM_MULTI_HEADER_LEN 2
29 /* Bit-masks for the FCF */
30 #define LWM_FCF_ACK_REQUEST 0x01
31 #define LWM_FCF_SEC_EN 0x02
33 #define LWM_FCF_LINK_LOCAL 0x04
34 #define LWM_FCF_MULTICAST 0x08
36 #define LWM_FCF_RESERVED 0xF0
38 #define LWM_MULTI_NON_MEM_RAD_MASK 0x000F
39 #define LWM_MULTI_NON_MEM_RAD_OFFSET 0
41 #define LWM_MULTI_MAX_NON_MEM_RAD_MASK 0x00F0
42 #define LWM_MULTI_MAX_NON_MEM_RAD_OFFSET 4
44 #define LWM_MULTI_MEM_RAD_MASK 0x0F00
45 #define LWM_MULTI_MEM_RAD_OFFSET 8
47 #define LWM_MULTI_MAX_MEM_RAD_MASK 0xF000
48 #define LWM_MULTI_MAX_MEM_RAD_OFFSET 12
51 #define LWM_SRC_ENDP_MASK 0xF0
52 #define LWM_SRC_ENDP_OFFSET 4
53 #define LWM_DST_ENDP_MASK 0x0F
54 #define LWM_DST_ENDP_OFFSET 0
57 #define LWM_BCAST_ADDR 0xFFFF
60 #define LWM_CMD_ACK 0x00
61 #define LWM_CMD_ROUTE_ERR 0x01
62 #define LWM_CMD_ROUTE_REQ 0x02
63 #define LWM_CMD_ROUTE_REPLY 0x03
65 /*Lengths of command frames*/
66 #define LWM_CMD_FRAME_ACK_LEN 3
67 #define LWM_CMD_FRAME_ROUTE_ERR_LEN 6
68 #define LWM_CMD_FRAME_ROUTE_REQ_LEN 7
69 #define LWM_CMD_FRAME_ROUTE_REPLY_LEN 8
71 /*Values for multicast field*/
72 #define LWM_CMD_MULTI_ADDR_FALSE 0
73 #define LWM_CMD_MULTI_ADDR_TRUE 1
76 #define LWM_CMD_LINKQ_STRING "(Sent by Originate node)"
77 #define LWM_CMD_UNKNOWN_VAL_STRING "Unknown command (0x%02x)"
79 #define LWM_MULTI_UNICAST_STRING "(Unicast)"
80 #define LWM_MULTI_GROUP_STRING "(Group ID)"
82 /* Function declarations */
83 void proto_register_lwm(void);
84 void proto_reg_handoff_lwm(void);
86 /* User string with the decryption key. */
87 static const char *lwmes_key_str
;
88 static bool lwmes_key_valid
;
89 static uint8_t lwmes_key
[16];
91 /* Dissection Routines. */
92 static int dissect_lwm (tvbuff_t
*, packet_info
*, proto_tree
*, void *data
);
93 static int dissect_lwm_cmd_frame_ack (tvbuff_t
*, packet_info
*, proto_tree
*);
94 static int dissect_lwm_cmd_frame_route_err (tvbuff_t
*, packet_info
*, proto_tree
*);
95 static int dissect_lwm_cmd_frame_route_req (tvbuff_t
*, packet_info
*, proto_tree
*);
96 static int dissect_lwm_cmd_frame_route_reply (tvbuff_t
*, packet_info
*, proto_tree
*);
98 /* Initialize protocol and registered fields. */
101 static int hf_lwm_fcf
;
102 static int hf_lwm_fcf_ack_req
;
103 static int hf_lwm_fcf_security
;
104 static int hf_lwm_fcf_linklocal
;
105 static int hf_lwm_fcf_multicast
;
106 static int hf_lwm_fcf_reserved
;
107 static int hf_lwm_seq
;
108 static int hf_lwm_src_addr
;
109 static int hf_lwm_dst_addr
;
110 static int hf_lwm_src_endp
;
111 static int hf_lwm_dst_endp
;
112 static int hf_lwm_multi_nmrad
;
113 static int hf_lwm_multi_mnmrad
;
114 static int hf_lwm_multi_mrad
;
115 static int hf_lwm_multi_mmrad
;
116 static int hf_lwm_mic
;
117 static int hf_lwm_cmd
;
118 static int hf_lwm_cmd_seq
;
119 static int hf_lwm_cmd_cm
;
120 static int hf_lwm_cmd_route_src
;
121 static int hf_lwm_cmd_route_dst
;
122 static int hf_lwm_cmd_route_multi
;
123 static int hf_lwm_cmd_linkquality
;
124 static int hf_lwm_cmd_forwlinkquality
;
125 static int hf_lwm_cmd_revlinkquality
;
127 /* Initialize protocol subtrees. */
129 static int ett_lwm_fcf
;
130 static int ett_lwm_cmd_tree
;
131 static int ett_lwm_multi_tree
;
133 static expert_field ei_lwm_mal_error
;
134 static expert_field ei_lwm_n_src_broad
;
135 static expert_field ei_lwm_mismatch_endp
;
136 static expert_field ei_lwm_empty_payload
;
137 static expert_field ei_lwm_no_decryption_key
;
138 static expert_field ei_lwm_decryption_failed
;
140 static dissector_handle_t lwm_handle
;
142 static const value_string lwm_cmd_names
[] = {
143 { LWM_CMD_ACK
, "LwMesh ACK" },
144 { LWM_CMD_ROUTE_ERR
, "Route Error" },
145 { LWM_CMD_ROUTE_REQ
, "Route Request" },
146 { LWM_CMD_ROUTE_REPLY
, "Route Reply" },
150 static const value_string lwm_cmd_multi_names
[] = {
151 { LWM_CMD_MULTI_ADDR_FALSE
, "FALSE" },
152 { LWM_CMD_MULTI_ADDR_TRUE
, "TRUE" },
156 /*FUNCTION:------------------------------------------------------
160 * Heuristic interpreter for the Lightweight Mesh.
162 * tvbuff_t *tvb - pointer to buffer containing raw packet.
163 * packet_into *pinfo - pointer to packet information fields
164 * proto_tree *tree - pointer to data tree Wireshark uses to display packet.
166 * Boolean value, whether it handles the packet or not.
167 *---------------------------------------------------------------
170 dissect_lwm_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
172 uint8_t endpt
, srcep
, dstep
;
174 /* 1) first byte must have bits 0000xxxx */
175 if(tvb_get_uint8(tvb
, 0) & LWM_FCF_RESERVED
)
178 /* The header should be at least long enough for the base header. */
179 if (tvb_reported_length(tvb
) < LWM_HEADER_BASE_LEN
)
182 /* The endpoints should either both be zero, or both non-zero. */
183 endpt
= tvb_get_uint8(tvb
, 6);
184 srcep
= (endpt
& LWM_SRC_ENDP_MASK
) >> LWM_SRC_ENDP_OFFSET
;
185 dstep
= (endpt
& LWM_DST_ENDP_MASK
) >> LWM_DST_ENDP_OFFSET
;
186 if ((srcep
== 0) && (dstep
!= 0))
188 if ((srcep
!= 0) && (dstep
== 0))
191 dissect_lwm(tvb
, pinfo
, tree
, data
);
193 } /* dissect_lwm_heur */
195 /*FUNCTION:------------------------------------------------------
199 * Lightweight Mesh packet dissection routine for Wireshark.
201 * tvbuff_t *tvb - pointer to buffer containing raw packet.
202 * packet_info *pinfo - pointer to packet information fields
203 * proto_tree *tree - pointer to data tree Wireshark uses to display packet.
205 * int - length of data processed, or 0 if not LWM.
206 *---------------------------------------------------------------
208 static int dissect_lwm(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
210 unsigned lwm_header_len
;
213 bool lwm_fcf_security
;
214 bool lwm_fcf_multicast
;
218 uint16_t lwm_src_addr
;
219 uint16_t lwm_dst_addr
;
220 uint8_t lwm_endp_field
;
221 uint8_t lwm_src_endp
;
222 uint8_t lwm_dst_endp
;
224 proto_tree
*lwm_tree
= NULL
;
225 proto_item
*ti_proto
= NULL
;
229 /*---------------------------------------------------------*/
231 /*Enter name of protocol to info field*/
232 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LwMesh");
233 col_clear(pinfo
->cinfo
, COL_INFO
);
235 /*Set base length of LWM header*/
236 lwm_header_len
= LWM_HEADER_BASE_LEN
;
238 /*--------------------------------------------------*/
240 /* Create LwMesh dissector tree */
242 /*--------------------------------------------------*/
244 /*Create subtree for the LwMesh*/
245 ti_proto
= proto_tree_add_protocol_format(tree
, proto_lwm
, tvb
, 0, -1, "Lightweight Mesh");
246 lwm_tree
= proto_item_add_subtree(ti_proto
, ett_lwm
);
249 col_set_str(pinfo
->cinfo
, COL_INFO
, "Lightweight Mesh");
251 /*--------------------------------------------------*/
253 /* Display LwMesh dissector tree */
255 /*--------------------------------------------------*/
257 /*Frame control fields*/
258 lwm_fcf
= tvb_get_uint8(tvb
, 0);
260 lwm_fcf_security
= (lwm_fcf
& LWM_FCF_SEC_EN
);
261 lwm_fcf_multicast
= (lwm_fcf
& LWM_FCF_MULTICAST
);
264 proto_tree
*field_tree
;
265 ti
= proto_tree_add_uint(lwm_tree
, hf_lwm_fcf
, tvb
, 0, 1, lwm_fcf
);
267 field_tree
= proto_item_add_subtree(ti
, ett_lwm_fcf
);
268 proto_tree_add_item(field_tree
, hf_lwm_fcf_ack_req
, tvb
, 0, 1, ENC_NA
);
270 proto_tree_add_item(field_tree
, hf_lwm_fcf_security
, tvb
, 0, 1, ENC_NA
);
271 proto_tree_add_item(field_tree
, hf_lwm_fcf_linklocal
, tvb
, 0, 1, ENC_NA
);
272 proto_tree_add_item(field_tree
, hf_lwm_fcf_multicast
, tvb
, 0, 1, ENC_NA
);
273 proto_tree_add_item(field_tree
, hf_lwm_fcf_reserved
, tvb
, 0, 1, ENC_NA
);
277 lwm_seq
= tvb_get_uint8(tvb
, 1);
278 proto_item_append_text(ti_proto
, ", Sequence Number: %i", lwm_seq
);
279 proto_tree_add_uint(lwm_tree
, hf_lwm_seq
, tvb
, 1, 1, lwm_seq
);
281 /*Network addresses*/
283 /*Parse Source address*/
284 lwm_src_addr
= tvb_get_letohs(tvb
, 2);
286 ti
= proto_tree_add_uint(lwm_tree
, hf_lwm_src_addr
, tvb
, 2, 2, lwm_src_addr
);
288 if(lwm_src_addr
< 0x8000){
289 proto_item_append_text(ti
, " (Routing node)");
291 proto_item_append_text(ti
, " (Non-routing node)");
294 /*Check value of source address*/
295 if(lwm_src_addr
== LWM_BCAST_ADDR
){
296 expert_add_info(pinfo
, lwm_tree
, &ei_lwm_n_src_broad
);
299 /*Parse Destination address*/
300 lwm_dst_addr
= tvb_get_letohs(tvb
, 4);
302 if(lwm_dst_addr
== LWM_BCAST_ADDR
){
303 proto_tree_add_uint_format_value(lwm_tree
, hf_lwm_dst_addr
, tvb
, 4, 2, lwm_dst_addr
,
304 "Broadcast (0x%04x)", lwm_dst_addr
);
306 ti
= proto_tree_add_uint(lwm_tree
, hf_lwm_dst_addr
, tvb
, 4, 2, lwm_dst_addr
);
308 if(lwm_fcf_multicast
){
309 proto_item_append_text(ti
, " %s", LWM_MULTI_GROUP_STRING
);
311 proto_item_append_text(ti
, " %s", LWM_MULTI_UNICAST_STRING
);
313 if(lwm_dst_addr
< 0x8000){
314 proto_item_append_text(ti
, " (Routing node)");
316 proto_item_append_text(ti
, " (Non-routing node)");
321 /*Enter description to info field*/
322 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Nwk_Dst: 0x%04x, Nwk_Src: 0x%04x", lwm_dst_addr
, lwm_src_addr
);
325 lwm_endp_field
= tvb_get_uint8(tvb
, 6);
326 lwm_src_endp
= (lwm_endp_field
& LWM_SRC_ENDP_MASK
) >> LWM_SRC_ENDP_OFFSET
;
327 lwm_dst_endp
= (lwm_endp_field
& LWM_DST_ENDP_MASK
) >> LWM_DST_ENDP_OFFSET
;
329 ti
= proto_tree_add_uint(lwm_tree
, hf_lwm_src_endp
, tvb
, 6, 1, lwm_src_endp
);
330 if(lwm_src_endp
== 0){
331 proto_item_append_text(ti
, " (Stack command endpoint)");
334 ti
= proto_tree_add_uint(lwm_tree
, hf_lwm_dst_endp
, tvb
, 6, 1, lwm_dst_endp
);
335 if(lwm_dst_endp
== 0){
336 proto_item_append_text(ti
, " (Stack command endpoint)");
339 if( (lwm_src_endp
== 0) && (lwm_dst_endp
== 0)){
340 /*stack command endpoints*/
343 else if( (lwm_src_endp
== 0) || (lwm_dst_endp
== 0)){
344 /*If only one endpoint is 0, alert about that*/
346 col_append_str(pinfo
->cinfo
, COL_INFO
, "[Stack command Endpoints mismatch]");
348 expert_add_info(pinfo
, lwm_tree
, &ei_lwm_mismatch_endp
);
352 if( (lwm_fcf_multicast
) ){
354 lwm_header_len
+= LWM_MULTI_HEADER_LEN
;
357 proto_tree
*multi_tree
;
358 uint16_t lwm_multi_header
;
360 lwm_multi_header
= tvb_get_letohs(tvb
, 7);
361 multi_tree
= proto_tree_add_subtree(lwm_tree
, tvb
, 7, 2, ett_lwm_multi_tree
, NULL
, "Multicast Header");
363 proto_tree_add_uint(multi_tree
, hf_lwm_multi_nmrad
, tvb
, 7, 2,
364 (lwm_multi_header
& LWM_MULTI_NON_MEM_RAD_MASK
) >> LWM_MULTI_NON_MEM_RAD_OFFSET
);
365 proto_tree_add_uint(multi_tree
, hf_lwm_multi_mnmrad
, tvb
, 7, 2,
366 (lwm_multi_header
& LWM_MULTI_MAX_NON_MEM_RAD_MASK
) >> LWM_MULTI_MAX_NON_MEM_RAD_OFFSET
);
367 proto_tree_add_uint(multi_tree
, hf_lwm_multi_mrad
, tvb
, 7, 2,
368 (lwm_multi_header
& LWM_MULTI_MEM_RAD_MASK
) >> LWM_MULTI_MEM_RAD_OFFSET
);
369 proto_tree_add_uint(multi_tree
, hf_lwm_multi_mmrad
, tvb
, 7, 2,
370 (lwm_multi_header
& LWM_MULTI_MAX_MEM_RAD_MASK
) >> LWM_MULTI_MAX_MEM_RAD_OFFSET
);
375 /*------------------------------*/
377 /* Dissect payload */
379 /*------------------------------*/
381 /*Note: exception will already have occurred if "short header"*/
383 if (tvb_reported_length(tvb
) <= lwm_header_len
) {
385 expert_add_info(pinfo
, lwm_tree
, &ei_lwm_empty_payload
);
386 col_append_str(pinfo
->cinfo
, COL_INFO
, "[Empty LwMesh Payload]");
388 return tvb_captured_length(tvb
);
391 new_tvb
= tvb_new_subset_remaining(tvb
, lwm_header_len
);
394 if(lwm_fcf_security
){
400 rlen
= tvb_reported_length(new_tvb
);
401 start
= (rlen
>= LWM_MIC_LEN
) ? (rlen
-LWM_MIC_LEN
) : 0;
402 /*An exception will occur if there are not enough bytes for the MIC */
403 proto_tree_add_item_ret_uint(lwm_tree
, hf_lwm_mic
, new_tvb
, start
, LWM_MIC_LEN
, ENC_LITTLE_ENDIAN
, &lwm_mic
);
407 ieee802154_packet
*ieee_packet
= NULL
;
408 int payload_length
= 0;
410 int payload_offset
= 0;
412 tvbuff_t
*decrypted_tvb
;
413 gcry_cipher_hd_t cypher_hd
;
414 uint8_t* vector
= NULL
;
416 uint8_t* text_dec
=NULL
;
419 uint32_t nwkSecurityVector
[4];
422 ieee_packet
= (ieee802154_packet
*)data
;
424 memset(&nwkSecurityVector
, 0, sizeof(nwkSecurityVector
));
425 nwkSecurityVector
[0] = lwm_seq
;
426 nwkSecurityVector
[1] = ((uint32_t)lwm_dst_addr
<< 16) | lwm_dst_endp
;
427 nwkSecurityVector
[2]= ((uint32_t) lwm_src_addr
<< 16) | lwm_src_endp
;
428 nwkSecurityVector
[3] = ((uint32_t)ieee_packet
->dst_pan
<< 16) | (uint8_t)lwm_fcf
;
430 payload_length
=tvb_reported_length(new_tvb
) - LWM_MIC_LEN
;
432 /* ECB - Nwk security vector*/
433 text
= (uint8_t *)tvb_memdup(pinfo
->pool
, new_tvb
, 0, payload_length
);
436 gcrypt_err
= gcry_cipher_open(&cypher_hd
, GCRY_CIPHER_AES128
, GCRY_CIPHER_MODE_ECB
, 0);
437 /*Decrypt the actual data */
438 while(payload_length
>0)
440 if(gcrypt_err
== 0) {
441 gcrypt_err
= gcry_cipher_setkey(cypher_hd
,(uint8_t *)lwmes_key
, 16);
443 if(gcrypt_err
== 0) {
444 gcrypt_err
= gcry_cipher_encrypt(cypher_hd
,(uint8_t *)nwkSecurityVector
,16,(uint8_t *)nwkSecurityVector
,16);
449 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
450 "Encrypted data (%i byte(s)) DECRYPT FAILED",
451 tvb_reported_length(new_tvb
) - LWM_MIC_LEN
);
452 expert_add_info(pinfo
, lwm_tree
, &ei_lwm_decryption_failed
);
453 tvb_set_reported_length(new_tvb
, tvb_reported_length(new_tvb
) - LWM_MIC_LEN
);
454 call_data_dissector(new_tvb
, pinfo
, lwm_tree
);
457 text_dec
= &text
[payload_offset
];
458 vector
= (uint8_t *)nwkSecurityVector
;
459 block
= (payload_length
< 16) ? payload_length
: 16;
461 for (i
= 0; i
< block
; i
++)
463 text_dec
[i
] ^= vector
[i
];
465 * GCC 12.2.0 gives a false positive Wstringop-overflow warning.
466 * https://gitlab.com/wireshark/wireshark/-/issues/18383
468 DIAG_OFF_STRINGOP_OVERFLOW()
469 vector
[i
] ^= text_dec
[i
];
470 DIAG_ON_STRINGOP_OVERFLOW()
473 payload_offset
+= block
;
474 payload_length
-= block
;
475 gcry_cipher_reset(cypher_hd
);
477 gcry_cipher_close(cypher_hd
);
479 vmic
= nwkSecurityVector
[0] ^ nwkSecurityVector
[1] ^ nwkSecurityVector
[2] ^ nwkSecurityVector
[3];
480 length
= tvb_reported_length(new_tvb
) - LWM_MIC_LEN
;
484 decrypted_tvb
= tvb_new_real_data(text
,length
, length
);
485 call_data_dissector(decrypted_tvb
, pinfo
, lwm_tree
);
487 add_new_data_source(pinfo, decrypted_tvb, "Decrypted LWmesh Payload"); */
488 col_append_str(pinfo
->cinfo
, COL_INFO
, ", MIC SUCCESS");
493 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
494 "Encrypted data (%i byte(s)) MIC FAILURE",
495 tvb_reported_length(new_tvb
) - LWM_MIC_LEN
);
496 tvb_set_reported_length(new_tvb
, tvb_reported_length(new_tvb
) - LWM_MIC_LEN
);
497 call_data_dissector(new_tvb
, pinfo
, lwm_tree
);
502 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
503 "Encrypted data (%i byte(s)) NO DECRYPT KEY",
504 tvb_reported_length(new_tvb
) - LWM_MIC_LEN
);
506 expert_add_info(pinfo
, lwm_tree
, &ei_lwm_no_decryption_key
);
507 tvb_set_reported_length(new_tvb
, tvb_reported_length(new_tvb
) - LWM_MIC_LEN
);
508 call_data_dissector(new_tvb
, pinfo
, lwm_tree
);
511 /*stack command endpoint 0 and not secured*/
512 else if( (lwm_src_endp
== 0) && (lwm_dst_endp
== 0) ){
513 proto_tree
*lwm_cmd_tree
;
517 /*----------------------------------------------------------------------*/
519 /* Call command dissector (depends on value of first byte of payload) */
521 /*----------------------------------------------------------------------*/
522 lwm_cmd
= tvb_get_uint8(new_tvb
, 0);
524 col_clear(pinfo
->cinfo
, COL_INFO
); /*XXX: why ?*/
525 col_add_str(pinfo
->cinfo
, COL_INFO
,
526 val_to_str(lwm_cmd
, lwm_cmd_names
, LWM_CMD_UNKNOWN_VAL_STRING
));
528 lwm_cmd_tree
= proto_tree_add_subtree(lwm_tree
, new_tvb
, 0, -1, ett_lwm_cmd_tree
, &ti
,
529 val_to_str(lwm_cmd
, lwm_cmd_names
, LWM_CMD_UNKNOWN_VAL_STRING
));
531 proto_tree_add_uint(lwm_cmd_tree
, hf_lwm_cmd
, new_tvb
, 0, 1, lwm_cmd
);
536 len
= dissect_lwm_cmd_frame_ack(new_tvb
, pinfo
, lwm_cmd_tree
);
539 case LWM_CMD_ROUTE_ERR
:
540 len
= dissect_lwm_cmd_frame_route_err(new_tvb
, pinfo
, lwm_cmd_tree
);
543 case LWM_CMD_ROUTE_REQ
:
544 len
= dissect_lwm_cmd_frame_route_req(new_tvb
, pinfo
, lwm_cmd_tree
);
547 case LWM_CMD_ROUTE_REPLY
:
548 len
= dissect_lwm_cmd_frame_route_reply(new_tvb
, pinfo
, lwm_cmd_tree
);
553 expert_add_info_format(pinfo
, lwm_cmd_tree
, &ei_lwm_mal_error
, "Unknown command");
554 call_data_dissector(new_tvb
, pinfo
, lwm_cmd_tree
);
555 return tvb_captured_length(tvb
);
558 proto_item_set_len(ti
, len
);
560 /*Here only if additional data after valid 'cmd' data*/
561 /*Note: exception will have already occurred if tvb was missing required bytes for 'cmd'*/
562 /* Report error if additional undissected data*/
563 if (len
< tvb_reported_length(new_tvb
)) {
564 /*unknown additional data*/
565 expert_add_info_format(pinfo
, lwm_cmd_tree
, &ei_lwm_mal_error
,
566 "Size is %i byte(s), instead of %i bytes", tvb_reported_length(new_tvb
), len
);
568 new_tvb
= tvb_new_subset_remaining(new_tvb
, len
);
569 call_data_dissector(new_tvb
, pinfo
, lwm_tree
);
574 call_data_dissector(new_tvb
, pinfo
, lwm_tree
);
576 return tvb_captured_length(tvb
);
579 /*FUNCTION:------------------------------------------------------
581 * dissect_lwm_cmd_frame_ack
583 * LwMesh command frame - Ack.
586 * tvbuff_t *tvb - pointer to buffer containing raw packet.
587 * packet_info *pinfo - pointer to packet information fields
588 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
590 * int length - amount of data processed
591 *---------------------------------------------------------------
593 static int dissect_lwm_cmd_frame_ack(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*lwm_cmd_tree
)
598 lwm_seq
= tvb_get_uint8(tvb
, 1);
600 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Sequence number: %d", lwm_seq
);
603 proto_item_append_text(proto_tree_get_parent(lwm_cmd_tree
), ", Sequence number: %d", lwm_seq
);
604 proto_tree_add_uint(lwm_cmd_tree
, hf_lwm_cmd_seq
, tvb
, 1, 1, lwm_seq
);
605 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_cm
, tvb
, 2, 1, ENC_NA
);
608 return LWM_CMD_FRAME_ACK_LEN
;
610 } /* dissect_lwm_cmd_frame_ack*/
612 /*FUNCTION:------------------------------------------------------
614 * dissect_lwm_cmd_frame_route_err
616 * LwMesh command frame - Route error.
619 * tvbuff_t *tvb - pointer to buffer containing raw packet.
620 * packet_info *pinfo - pointer to packet information fields
621 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
623 * int length - amount of data processed
624 *---------------------------------------------------------------
626 static int dissect_lwm_cmd_frame_route_err(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*lwm_cmd_tree
)
631 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_src
, tvb
, 1, 2, ENC_LITTLE_ENDIAN
);
632 ti
= proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_dst
, tvb
, 3, 2, ENC_LITTLE_ENDIAN
);
634 if(tvb_get_uint8(tvb
, 5) == LWM_CMD_MULTI_ADDR_TRUE
){
635 proto_item_append_text(ti
, " %s", LWM_MULTI_GROUP_STRING
);
637 proto_item_append_text(ti
, " %s", LWM_MULTI_UNICAST_STRING
);
640 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_multi
, tvb
, 5, 1, ENC_NA
);
643 return LWM_CMD_FRAME_ROUTE_ERR_LEN
;
645 } /* dissect_lwm_cmd_frame_route_err*/
647 /*FUNCTION:------------------------------------------------------
649 * dissect_lwm_cmd_frame_route_req
651 * LwMesh command frame - Route Request.
654 * tvbuff_t *tvb - pointer to buffer containing raw packet.
655 * packet_info *pinfo - pointer to packet information fields
656 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
658 * int length - amount of data processed
659 *---------------------------------------------------------------
661 static int dissect_lwm_cmd_frame_route_req(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*lwm_cmd_tree
)
665 uint8_t lwm_linkqual
;
667 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_src
, tvb
, 1, 2, ENC_LITTLE_ENDIAN
);
668 ti
= proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_dst
, tvb
, 3, 2, ENC_LITTLE_ENDIAN
);
670 if(tvb_get_uint8(tvb
, 5) == LWM_CMD_MULTI_ADDR_TRUE
){
671 proto_item_append_text(ti
, " %s", LWM_MULTI_GROUP_STRING
);
673 proto_item_append_text(ti
, " %s", LWM_MULTI_UNICAST_STRING
);
676 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_multi
, tvb
, 5, 1, ENC_NA
);
678 lwm_linkqual
= tvb_get_uint8(tvb
, 6);
679 ti
= proto_tree_add_uint(lwm_cmd_tree
, hf_lwm_cmd_linkquality
, tvb
, 6, 1, lwm_linkqual
);
680 if(lwm_linkqual
== 255){
681 proto_item_append_text(ti
, " %s", LWM_CMD_LINKQ_STRING
);
685 return LWM_CMD_FRAME_ROUTE_REQ_LEN
;
687 } /* dissect_lwm_cmd_frame_route_req*/
689 /*FUNCTION:------------------------------------------------------
691 * dissect_lwm_cmd_frame_route_reply
693 * LwMesh command frame - Route Reply.
696 * tvbuff_t *tvb - pointer to buffer containing raw packet.
697 * packet_info *pinfo - pointer to packet information fields
698 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
700 * int length - amount of data processed
701 *---------------------------------------------------------------
703 static int dissect_lwm_cmd_frame_route_reply(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*lwm_cmd_tree
)
707 uint8_t lwm_revlinkqual
;
709 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_src
, tvb
, 1, 2, ENC_LITTLE_ENDIAN
);
710 ti
= proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_dst
, tvb
, 3, 2, ENC_LITTLE_ENDIAN
);
712 if(tvb_get_uint8(tvb
, 5) == LWM_CMD_MULTI_ADDR_TRUE
){
713 proto_item_append_text(ti
, " %s", LWM_MULTI_GROUP_STRING
);
715 proto_item_append_text(ti
, " %s", LWM_MULTI_UNICAST_STRING
);
718 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_route_multi
, tvb
, 5, 1, ENC_NA
);
719 proto_tree_add_item(lwm_cmd_tree
, hf_lwm_cmd_forwlinkquality
, tvb
, 6, 1, ENC_NA
);
721 lwm_revlinkqual
= tvb_get_uint8(tvb
, 7);
722 ti
= proto_tree_add_uint(lwm_cmd_tree
, hf_lwm_cmd_revlinkquality
, tvb
, 7, 1, lwm_revlinkqual
);
723 if(lwm_revlinkqual
== 255){
724 proto_item_append_text(ti
, " %s", LWM_CMD_LINKQ_STRING
);
728 return LWM_CMD_FRAME_ROUTE_REPLY_LEN
;
730 } /* dissect_lwm_cmd_frame_route_reply*/
732 /*FUNCTION:------------------------------------------------------
736 * IEEE 802.15.4 protocol registration routine.
741 *---------------------------------------------------------------
743 void proto_register_lwm(void)
746 static hf_register_info hf
[] = {
748 /*Frame control field*/
750 { "Frame control field", "lwm.fcf", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
751 "Control information for the frame.", HFILL
}},
753 { &hf_lwm_fcf_ack_req
,
754 { "Acknowledgment Request", "lwm.ack_req", FT_BOOLEAN
, 8, NULL
, LWM_FCF_ACK_REQUEST
,
755 "Specifies whether an acknowledgment is required from the destination node.", HFILL
}},
757 { &hf_lwm_fcf_security
,
758 { "Security Enabled", "lwm.security", FT_BOOLEAN
, 8, NULL
, LWM_FCF_SEC_EN
,
759 "Specifies whether the frame payload is encrypted.", HFILL
}},
761 { &hf_lwm_fcf_linklocal
,
762 { "Link Local", "lwm.linklocal", FT_BOOLEAN
, 8, NULL
, LWM_FCF_LINK_LOCAL
,
763 "It may be set to one to prevent neighboring nodes from rebroadcasting a frame.", HFILL
}},
765 { &hf_lwm_fcf_multicast
,
766 { "Multicast", "lwm.multicast", FT_BOOLEAN
, 8, NULL
, LWM_FCF_MULTICAST
,
767 "If the Multicast subfield is set to one, Multicast Header should be present and the Destination Address is a group address.", HFILL
}},
769 { &hf_lwm_fcf_reserved
,
770 { "Reserved bits", "lwm.fcf.reserved", FT_UINT8
, BASE_HEX
, NULL
, LWM_FCF_RESERVED
,
771 "The 4 bits are reserved.", HFILL
}},
775 { "Sequence Number", "lwm.seq", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
776 "Specifies the sequence identifier for the frame.", HFILL
}},
779 { "Network Source Address", "lwm.src_addr", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
780 "Specifies the network address of the node originating the frame.", HFILL
}},
783 { "Network Destination Address", "lwm.dst_addr", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
784 "Specifies the network address of the destination node or group address for multicast messages.", HFILL
}},
787 { "Source Endpoint", "lwm.src_endp", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
788 "Specifies the source endpoint identifier.", HFILL
}},
791 { "Destination Endpoint", "lwm.dst_endp", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
792 "Specifies the destination endpoint identifier.", HFILL
}},
796 { &hf_lwm_multi_nmrad
,
797 { "Non-member Radius", "lwm.multi_nmrad", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
798 "Specifies remaining radius (number of hops) for Non-members of multicast group.", HFILL
}},
800 { &hf_lwm_multi_mnmrad
,
801 { "Maximum Non-member Radius", "lwm.multi_mnmrad", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
802 "Specifies maximum radius (number of hops) for Non-members of multicast group.", HFILL
}},
804 { &hf_lwm_multi_mrad
,
805 { "Member Radius", "lwm.multi_mrad", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
806 "Specifies remaining radius (number of hops) for Members of multicast group.", HFILL
}},
808 { &hf_lwm_multi_mmrad
,
809 { "Maximum Member Radius", "lwm.multi_mmrad", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
810 "Specifies maximum radius (number of hops) for Members of multicast group.", HFILL
}},
815 { "Message Integrity Code", "lwm.mic", FT_UINT32
, BASE_HEX
, NULL
, 0x0,
816 "Specifies Message Integrity Code (MIC).", HFILL
}},
819 /*----------------------------------*/
821 /* Command Frames Specific Fields */
823 /*----------------------------------*/
826 { "Command ID", "lwm.cmd", FT_UINT8
, BASE_HEX
, VALS(lwm_cmd_names
), 0x0,
827 "It contains Command ID value.", HFILL
}},
829 /* Command Frame - Ack */
831 { "Sequence number", "lwm.cmd.seq", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
832 "It contains a network sequence number of a frame that is being acknowledged.", HFILL
}},
835 { "Control Message", "lwm.cmd.cm", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
836 "It contains an arbitrary value that can be set on the sending side.", HFILL
}},
838 /* Part of Command Frames - Route Request, Route Reply*/
839 { &hf_lwm_cmd_route_src
,
840 { "Source address", "lwm.cmd.route_src", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
841 "It contains a source network address from the frame that cannot be routed", HFILL
}},
843 { &hf_lwm_cmd_route_dst
,
844 { "Destination Address", "lwm.cmd.route_dst", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
845 "It contains a destination network address from the frame that cannot be routed", HFILL
}},
847 { &hf_lwm_cmd_route_multi
,
848 { "Multicast", "lwm.cmd.multi", FT_UINT8
, BASE_HEX
, VALS(lwm_cmd_multi_names
), 0x0,
849 "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
}},
851 /* Part of Command Frame - Route Request */
852 { &hf_lwm_cmd_linkquality
,
853 { "Link Quality", "lwm.cmd.linkq", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
854 "It contains a link quality value of the potential route accumulated over all hops towards the destination.", HFILL
}},
856 /* Part of Command Frame - Route Reply */
857 { &hf_lwm_cmd_forwlinkquality
,
858 { "Forward Link Quality", "lwm.cmd.flinkq", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
859 "It contains a value of the Link Quality field from the corresponding Route Request Command Frame.", HFILL
}},
861 { &hf_lwm_cmd_revlinkquality
,
862 { "Reverse Link Quality", "lwm.cmd.rlinkq", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
863 "It contains a link quality value of the discovered route accumulated over all hops towards the originator.", HFILL
}},
869 static int *ett
[] = {
876 static ei_register_info ei
[] = {
877 { &ei_lwm_mal_error
, { "lwm.malformed_error", PI_MALFORMED
, PI_ERROR
, "Malformed Packet", EXPFILL
}},
878 { &ei_lwm_n_src_broad
, { "lwm.not_src_broadcast", PI_COMMENTS_GROUP
, PI_NOTE
, "Source address can not be broadcast address !", EXPFILL
}},
879 { &ei_lwm_mismatch_endp
, { "lwm.mismatch_endp", PI_COMMENTS_GROUP
, PI_WARN
, "Stack command Endpoints mismatch (should be 0, both)!", EXPFILL
}},
880 { &ei_lwm_empty_payload
, { "lwm.empty_payload", PI_COMMENTS_GROUP
, PI_WARN
, "Empty LwMesh Payload!", EXPFILL
}},
881 { &ei_lwm_no_decryption_key
, { "lwm.no_decryption_key", PI_PROTOCOL
, PI_NOTE
, "No encryption key set - can't decrypt", EXPFILL
}},
882 { &ei_lwm_decryption_failed
, { "lwm.decryption_failed", PI_PROTOCOL
, PI_WARN
, "Decryption Failed", EXPFILL
}},
886 expert_module_t
* expert_lwm
;
888 /* Register protocol name and description. */
889 proto_lwm
= proto_register_protocol("Lightweight Mesh (v1.1.1)", "LwMesh", "lwm");
891 /* Register header fields and subtrees. */
892 proto_register_field_array(proto_lwm
, hf
, array_length(hf
));
893 proto_register_subtree_array(ett
, array_length(ett
));
894 expert_lwm
= expert_register_protocol(proto_lwm
);
895 expert_register_field_array(expert_lwm
, ei
, array_length(ei
));
897 lw_module
= prefs_register_protocol(proto_lwm
,proto_reg_handoff_lwm
);
899 /* Register preferences for a decryption key */
900 /* TODO: Implement a UAT for multiple keys, and with more advanced key management. */
901 prefs_register_string_preference(lw_module
, "lwmes_key", "Lw Decryption key",
902 "128-bit decryption key in hexadecimal format", (const char **)&lwmes_key_str
);
904 /* Register dissector with Wireshark. */
905 lwm_handle
= register_dissector("lwm", dissect_lwm
, proto_lwm
);
907 } /* proto_register_lwm */
909 /*FUNCTION:------------------------------------------------------
911 * proto_reg_handoff_lwm
913 * Registers the lwm dissector with Wireshark.
914 * Will be called during Wireshark startup, and whenever
915 * preferences are changed.
920 *---------------------------------------------------------------
922 void proto_reg_handoff_lwm(void)
924 static bool initialized
= false;
929 /* Register our dissector with IEEE 802.15.4 */
930 dissector_add_for_decode_as(IEEE802154_PROTOABBREV_WPAN_PANID
, lwm_handle
);
931 heur_dissector_add(IEEE802154_PROTOABBREV_WPAN
, dissect_lwm_heur
, "Lightweight Mesh over IEEE 802.15.4", "lwm_wlan", proto_lwm
, HEURISTIC_ENABLE
);
935 /* Convert key to raw bytes */
936 bytes
= g_byte_array_new();
937 res
= hex_str_to_bytes(lwmes_key_str
, bytes
, false);
938 lwmes_key_valid
= (res
&& bytes
->len
>= IEEE802154_CIPHER_SIZE
);
939 if (lwmes_key_valid
) {
940 memcpy(lwmes_key
, bytes
->data
, IEEE802154_CIPHER_SIZE
);
942 g_byte_array_free(bytes
, true);
944 } /* proto_reg_handoff_lwm */
952 * indent-tabs-mode: nil
955 * ex: set shiftwidth=4 tabstop=8 expandtab:
956 * :indentSize=4:tabSize=8:noTabs=true: