1 /* packet-lwm.c
2 * Dissector routines for the ATMEL Lightweight Mesh 1.1.1
3 * Copyright 2013 Martin Leixner <info@sewio.net>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 *------------------------------------------------------------
11 */
12
13 #include "config.h"
14
15 #include <epan/packet.h>
16 #include <epan/expert.h>
17
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>
23
24 /*LwMesh lengths*/
25 #define LWM_HEADER_BASE_LEN 7
26 #define LWM_MIC_LEN 4
27 #define LWM_MULTI_HEADER_LEN 2
28
29 /* Bit-masks for the FCF */
30 #define LWM_FCF_ACK_REQUEST 0x01
31 #define LWM_FCF_SEC_EN 0x02
32
33 #define LWM_FCF_LINK_LOCAL 0x04
34 #define LWM_FCF_MULTICAST 0x08
35
36 #define LWM_FCF_RESERVED 0xF0
37
38 #define LWM_MULTI_NON_MEM_RAD_MASK 0x000F
39 #define LWM_MULTI_NON_MEM_RAD_OFFSET 0
40
41 #define LWM_MULTI_MAX_NON_MEM_RAD_MASK 0x00F0
42 #define LWM_MULTI_MAX_NON_MEM_RAD_OFFSET 4
43
44 #define LWM_MULTI_MEM_RAD_MASK 0x0F00
45 #define LWM_MULTI_MEM_RAD_OFFSET 8
46
47 #define LWM_MULTI_MAX_MEM_RAD_MASK 0xF000
48 #define LWM_MULTI_MAX_MEM_RAD_OFFSET 12
49
50 /*Endpoints*/
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
55
56 /*Defined addresses*/
57 #define LWM_BCAST_ADDR 0xFFFF
58
59 /*Command IDs*/
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
64
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
70
71 /*Values for multicast field*/
72 #define LWM_CMD_MULTI_ADDR_FALSE 0
73 #define LWM_CMD_MULTI_ADDR_TRUE 1
74
75 /*Defined strings*/
76 #define LWM_CMD_LINKQ_STRING "(Sent by Originate node)"
77 #define LWM_CMD_UNKNOWN_VAL_STRING "Unknown command (0x%02x)"
78
79 #define LWM_MULTI_UNICAST_STRING "(Unicast)"
80 #define LWM_MULTI_GROUP_STRING "(Group ID)"
81
82 /* Function declarations */
83 void proto_register_lwm(void);
84 void proto_reg_handoff_lwm(void);
85
86 /* User string with the decryption key. */
87 static const gchar *lwmes_key_str = NULL;
88 static gboolean lwmes_key_valid;
89 static guint8 lwmes_key[16];
90
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 *);
97
98 /* Initialize protocol and registered fields. */
99 static int proto_lwm = -1;
100
101 static int hf_lwm_fcf = -1;
102 static int hf_lwm_fcf_ack_req = -1;
103 static int hf_lwm_fcf_security = -1;
104 static int hf_lwm_fcf_linklocal = -1;
105 static int hf_lwm_fcf_multicast = -1;
106 static int hf_lwm_fcf_reserved = -1;
107 static int hf_lwm_seq = -1;
108 static int hf_lwm_src_addr = -1;
109 static int hf_lwm_dst_addr = -1;
110 static int hf_lwm_src_endp = -1;
111 static int hf_lwm_dst_endp = -1;
112 static int hf_lwm_multi_nmrad = -1;
113 static int hf_lwm_multi_mnmrad = -1;
114 static int hf_lwm_multi_mrad = -1;
115 static int hf_lwm_multi_mmrad = -1;
116 static int hf_lwm_mic = -1;
117 static int hf_lwm_cmd = -1;
118 static int hf_lwm_cmd_seq = -1;
119 static int hf_lwm_cmd_cm = -1;
120 static int hf_lwm_cmd_route_src = -1;
121 static int hf_lwm_cmd_route_dst = -1;
122 static int hf_lwm_cmd_route_multi = -1;
123 static int hf_lwm_cmd_linkquality = -1;
124 static int hf_lwm_cmd_forwlinkquality = -1;
125 static int hf_lwm_cmd_revlinkquality = -1;
126
127 /* Initialize protocol subtrees. */
128 static gint ett_lwm = -1;
129 static gint ett_lwm_fcf = -1;
130 static gint ett_lwm_cmd_tree = -1;
131 static gint ett_lwm_multi_tree = -1;
132
133 static expert_field ei_lwm_mal_error = EI_INIT;
134 static expert_field ei_lwm_n_src_broad = EI_INIT;
135 static expert_field ei_lwm_mismatch_endp = EI_INIT;
136 static expert_field ei_lwm_empty_payload = EI_INIT;
137 static expert_field ei_lwm_no_decryption_key = EI_INIT;
138 static expert_field ei_lwm_decryption_failed = EI_INIT;
139
140 static dissector_handle_t lwm_handle;
141
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" },
147 { 0, NULL }
148 };
149
150 static const value_string lwm_cmd_multi_names[] = {
151 { LWM_CMD_MULTI_ADDR_FALSE, "FALSE" },
152 { LWM_CMD_MULTI_ADDR_TRUE, "TRUE" },
153 { 0, NULL }
154 };
155
156 /*FUNCTION:------------------------------------------------------
157 * NAME
158 * dissect_lwm_heur
159 * DESCRIPTION
160 * Heuristic interpreter for the Lightweight Mesh.
161 * PARAMETERS
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.
165 * RETURNS
166 * Boolean value, whether it handles the packet or not.
167 *---------------------------------------------------------------
168 */
169 static gboolean
dissect_lwm_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)170 dissect_lwm_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
171 {
172 guint8 endpt, srcep, dstep;
173
174 /* 1) first byte must have bits 0000xxxx */
175 if(tvb_get_guint8(tvb, 0) & LWM_FCF_RESERVED)
176 return (FALSE);
177
178 /* The header should be at least long enough for the base header. */
179 if (tvb_reported_length(tvb) < LWM_HEADER_BASE_LEN)
180 return (FALSE);
181
182 /* The endpoints should either both be zero, or both non-zero. */
183 endpt = tvb_get_guint8(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))
187 return (FALSE);
188 if ((srcep != 0) && (dstep == 0))
189 return (FALSE);
190
191 dissect_lwm(tvb, pinfo, tree, data);
192 return (TRUE);
193 } /* dissect_lwm_heur */
194
195 /*FUNCTION:------------------------------------------------------
196 * NAME
197 * dissect_lwm
198 * DESCRIPTION
199 * Lightweight Mesh packet dissection routine for Wireshark.
200 * PARAMETERS
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.
204 * RETURNS
205 * int - length of data processed, or 0 if not LWM.
206 *---------------------------------------------------------------
207 */
dissect_lwm(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)208 static int dissect_lwm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
209 {
210 guint lwm_header_len;
211
212 guint8 lwm_fcf;
213 gboolean lwm_fcf_security;
214 gboolean lwm_fcf_multicast;
215
216
217 guint8 lwm_seq;
218 guint16 lwm_src_addr;
219 guint16 lwm_dst_addr;
220 guint8 lwm_endp_field;
221 guint8 lwm_src_endp;
222 guint8 lwm_dst_endp;
223
224 proto_tree *lwm_tree = NULL;
225 proto_item *ti_proto = NULL;
226 proto_item *ti;
227 tvbuff_t *new_tvb;
228
229 /*---------------------------------------------------------*/
230
231 /*Enter name of protocol to info field*/
232 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LwMesh");
233 col_clear(pinfo->cinfo, COL_INFO);
234
235 /*Set base length of LWM header*/
236 lwm_header_len = LWM_HEADER_BASE_LEN;
237
238 /*--------------------------------------------------*/
239 /* */
240 /* Create LwMesh dissector tree */
241 /* */
242 /*--------------------------------------------------*/
243 if(tree){
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);
247 }
248
249 col_add_fstr(pinfo->cinfo, COL_INFO, "Lightweight Mesh");
250
251 /*--------------------------------------------------*/
252 /* */
253 /* Display LwMesh dissector tree */
254 /* */
255 /*--------------------------------------------------*/
256
257 /*Frame control fields*/
258 lwm_fcf = tvb_get_guint8(tvb, 0);
259
260 lwm_fcf_security = (lwm_fcf & LWM_FCF_SEC_EN);
261 lwm_fcf_multicast = (lwm_fcf & LWM_FCF_MULTICAST);
262
263 if(tree){
264 proto_tree *field_tree;
265 ti = proto_tree_add_uint(lwm_tree, hf_lwm_fcf, tvb, 0, 1, lwm_fcf);
266
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);
269
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);
274 }
275
276 /*Sequence number*/
277 lwm_seq = tvb_get_guint8(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);
280
281 /*Network addresses*/
282
283 /*Parse Source address*/
284 lwm_src_addr = tvb_get_letohs(tvb, 2);
285
286 ti = proto_tree_add_uint(lwm_tree, hf_lwm_src_addr, tvb, 2, 2, lwm_src_addr);
287
288 if(lwm_src_addr < 0x8000){
289 proto_item_append_text(ti, " (Routing node)");
290 }else{
291 proto_item_append_text(ti, " (Non-routing node)");
292 }
293
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);
297 }
298
299 /*Parse Destination address*/
300 lwm_dst_addr = tvb_get_letohs(tvb, 4);
301
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);
305 }else{
306 ti = proto_tree_add_uint(lwm_tree, hf_lwm_dst_addr, tvb, 4, 2, lwm_dst_addr);
307
308 if(lwm_fcf_multicast){
309 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
310 }else{
311 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
312
313 if(lwm_dst_addr < 0x8000){
314 proto_item_append_text(ti, " (Routing node)");
315 }else{
316 proto_item_append_text(ti, " (Non-routing node)");
317 }
318 }
319 }
320
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);
323
324 /*Endpoints*/
325 lwm_endp_field = tvb_get_guint8(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;
328
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)");
332 }
333
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)");
337 }
338
339 if( (lwm_src_endp == 0) && (lwm_dst_endp == 0)){
340 /*stack command endpoints*/
341
342 }
343 else if( (lwm_src_endp == 0) || (lwm_dst_endp == 0)){
344 /*If only one endpoint is 0, alert about that*/
345
346 col_append_str(pinfo->cinfo, COL_INFO, "[Stack command Endpoints mismatch]");
347
348 expert_add_info(pinfo, lwm_tree, &ei_lwm_mismatch_endp);
349 }
350
351 /*Multicast header*/
352 if( (lwm_fcf_multicast) ){
353
354 lwm_header_len += LWM_MULTI_HEADER_LEN;
355
356 if(tree){
357 proto_tree *multi_tree;
358 guint16 lwm_multi_header;
359
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");
362
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);
371 }
372 }
373
374
375 /*------------------------------*/
376 /* */
377 /* Dissect payload */
378 /* */
379 /*------------------------------*/
380
381 /*Note: exception will already have occurred if "short header"*/
382
383 if (tvb_reported_length(tvb) <= lwm_header_len) {
384 /*Empty payload*/
385 expert_add_info(pinfo, lwm_tree, &ei_lwm_empty_payload);
386 col_append_str(pinfo->cinfo, COL_INFO, "[Empty LwMesh Payload]");
387
388 return tvb_captured_length(tvb);
389 }
390
391 new_tvb = tvb_new_subset_remaining(tvb, lwm_header_len);
392
393 /*Encrypted data*/
394 if(lwm_fcf_security){
395 guint rlen;
396 gint start;
397 guint32 lwm_mic;
398
399 /*MIC field*/
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);
404
405 if(lwmes_key_valid)
406 {
407 ieee802154_packet *ieee_packet = NULL;
408 gint payload_length = 0;
409 gint length = 0;
410 gint payload_offset = 0;
411 guint8 block;
412 tvbuff_t *decrypted_tvb;
413 gcry_cipher_hd_t cypher_hd;
414 guint8* vector = NULL;
415 guint8* text =NULL;
416 guint8* text_dec =NULL;
417 guint8 i;
418 guint32 vmic;
419 guint32 nwkSecurityVector[4];
420 int gcrypt_err;
421
422 ieee_packet = (ieee802154_packet *)data;
423
424 memset(&nwkSecurityVector, 0, sizeof(nwkSecurityVector));
425 nwkSecurityVector[0] = lwm_seq;
426 nwkSecurityVector[1] = ((guint32)lwm_dst_addr<< 16) | lwm_dst_endp;
427 nwkSecurityVector[2]= ((guint32) lwm_src_addr<< 16) | lwm_src_endp;
428 nwkSecurityVector[3] = ((guint32)ieee_packet->dst_pan << 16) | (guint8)lwm_fcf;
429
430 payload_length=tvb_reported_length(new_tvb) - LWM_MIC_LEN;
431
432 /* ECB - Nwk security vector*/
433 text = (guint8 *)tvb_memdup(pinfo->pool, new_tvb, 0, payload_length);
434 payload_offset=0;
435
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)
439 {
440 if(gcrypt_err == 0) {
441 gcrypt_err = gcry_cipher_setkey(cypher_hd,(guint8 *)lwmes_key, 16);
442 }
443 if(gcrypt_err == 0) {
444 gcrypt_err = gcry_cipher_encrypt(cypher_hd,(guint8 *)nwkSecurityVector,16,(guint8 *)nwkSecurityVector,16);
445 }
446
447 if(gcrypt_err)
448 {
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);
455 }
456
457 text_dec = &text[payload_offset];
458 vector = (guint8 *)nwkSecurityVector;
459 block = (payload_length < 16) ? payload_length : 16;
460
461 for (i = 0; i < block; i++)
462 {
463 text_dec[i] ^= vector[i];
464 vector[i] ^= text_dec[i];
465 }
466
467 payload_offset += block;
468 payload_length -= block;
469 gcry_cipher_reset(cypher_hd);
470 }
471 gcry_cipher_close(cypher_hd);
472
473 vmic = nwkSecurityVector[0] ^ nwkSecurityVector[1] ^ nwkSecurityVector[2] ^ nwkSecurityVector[3];
474 length = tvb_reported_length(new_tvb) - LWM_MIC_LEN;
475
476 if(vmic == lwm_mic)
477 {
478 decrypted_tvb = tvb_new_real_data(text,length, length);
479 call_data_dissector(decrypted_tvb, pinfo, lwm_tree);
480 /* XXX - needed?
481 add_new_data_source(pinfo, decrypted_tvb, "Decrypted LWmesh Payload"); */
482 col_append_fstr(pinfo->cinfo, COL_INFO, ", MIC SUCCESS");
483
484 }
485 else
486 {
487 col_add_fstr(pinfo->cinfo, COL_INFO,
488 "Encrypted data (%i byte(s)) MIC FAILURE",
489 tvb_reported_length(new_tvb) - LWM_MIC_LEN);
490 tvb_set_reported_length(new_tvb, tvb_reported_length(new_tvb) - LWM_MIC_LEN);
491 call_data_dissector(new_tvb, pinfo, lwm_tree);
492 }
493 }
494 else
495 {
496 col_add_fstr(pinfo->cinfo, COL_INFO,
497 "Encrypted data (%i byte(s)) NO DECRYPT KEY",
498 tvb_reported_length(new_tvb) - LWM_MIC_LEN);
499
500 expert_add_info(pinfo, lwm_tree, &ei_lwm_no_decryption_key);
501 tvb_set_reported_length(new_tvb, tvb_reported_length(new_tvb) - LWM_MIC_LEN);
502 call_data_dissector(new_tvb, pinfo, lwm_tree);
503 }
504 }
505 /*stack command endpoint 0 and not secured*/
506 else if( (lwm_src_endp == 0) && (lwm_dst_endp == 0) ){
507 proto_tree *lwm_cmd_tree;
508 guint8 lwm_cmd;
509 guint len;
510
511 /*----------------------------------------------------------------------*/
512 /* */
513 /* Call command dissector (depends on value of first byte of payload) */
514 /* */
515 /*----------------------------------------------------------------------*/
516 lwm_cmd = tvb_get_guint8(new_tvb, 0);
517
518 col_clear(pinfo->cinfo, COL_INFO); /*XXX: why ?*/
519 col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
520 val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING));
521
522 lwm_cmd_tree = proto_tree_add_subtree(lwm_tree, new_tvb, 0, -1, ett_lwm_cmd_tree, &ti,
523 val_to_str(lwm_cmd, lwm_cmd_names, LWM_CMD_UNKNOWN_VAL_STRING));
524
525 proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd, new_tvb, 0, 1, lwm_cmd);
526
527 switch (lwm_cmd) {
528
529 case LWM_CMD_ACK:
530 len = dissect_lwm_cmd_frame_ack(new_tvb, pinfo, lwm_cmd_tree);
531 break;
532
533 case LWM_CMD_ROUTE_ERR:
534 len = dissect_lwm_cmd_frame_route_err(new_tvb, pinfo, lwm_cmd_tree);
535 break;
536
537 case LWM_CMD_ROUTE_REQ:
538 len = dissect_lwm_cmd_frame_route_req(new_tvb, pinfo, lwm_cmd_tree);
539 break;
540
541 case LWM_CMD_ROUTE_REPLY:
542 len = dissect_lwm_cmd_frame_route_reply(new_tvb, pinfo, lwm_cmd_tree);
543 break;
544
545 default:
546 /*Unknown command*/
547 expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error, "Unknown command");
548 call_data_dissector(new_tvb, pinfo, lwm_cmd_tree);
549 return tvb_captured_length(tvb);
550 }
551
552 proto_item_set_len(ti, len);
553
554 /*Here only if additional data after valid 'cmd' data*/
555 /*Note: exception will have already occurred if tvb was missing required bytes for 'cmd'*/
556 /* Report error if additional undissected data*/
557 if (len < tvb_reported_length(new_tvb)) {
558 /*unknown additional data*/
559 expert_add_info_format(pinfo, lwm_cmd_tree, &ei_lwm_mal_error,
560 "Size is %i byte(s), instead of %i bytes", tvb_reported_length(new_tvb), len);
561
562 new_tvb = tvb_new_subset_remaining(new_tvb, len);
563 call_data_dissector(new_tvb, pinfo, lwm_tree);
564 }
565 }
566 else{
567 /*unknown data*/
568 call_data_dissector(new_tvb, pinfo, lwm_tree);
569 }
570 return tvb_captured_length(tvb);
571 } /* dissect_lwm */
572
573 /*FUNCTION:------------------------------------------------------
574 * NAME
575 * dissect_lwm_cmd_frame_ack
576 * DESCRIPTION
577 * LwMesh command frame - Ack.
578 *
579 * PARAMETERS
580 * tvbuff_t *tvb - pointer to buffer containing raw packet.
581 * packet_info *pinfo - pointer to packet information fields
582 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
583 * RETURNS
584 * int length - amount of data processed
585 *---------------------------------------------------------------
586 */
dissect_lwm_cmd_frame_ack(tvbuff_t * tvb,packet_info * pinfo,proto_tree * lwm_cmd_tree)587 static int dissect_lwm_cmd_frame_ack(tvbuff_t *tvb, packet_info *pinfo, proto_tree *lwm_cmd_tree)
588 {
589 guint8 lwm_seq;
590
591 /*Get fields*/
592 lwm_seq = tvb_get_guint8(tvb, 1);
593
594 col_append_fstr(pinfo->cinfo, COL_INFO, ", Sequence number: %d", lwm_seq);
595
596 if(lwm_cmd_tree){
597 proto_item_append_text(proto_tree_get_parent(lwm_cmd_tree), ", Sequence number: %d", lwm_seq);
598 proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_seq, tvb, 1, 1, lwm_seq);
599 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_cm, tvb, 2, 1, ENC_NA);
600 }
601
602 return LWM_CMD_FRAME_ACK_LEN;
603
604 } /* dissect_lwm_cmd_frame_ack*/
605
606 /*FUNCTION:------------------------------------------------------
607 * NAME
608 * dissect_lwm_cmd_frame_route_err
609 * DESCRIPTION
610 * LwMesh command frame - Route error.
611 *
612 * PARAMETERS
613 * tvbuff_t *tvb - pointer to buffer containing raw packet.
614 * packet_info *pinfo - pointer to packet information fields
615 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
616 * RETURNS
617 * int length - amount of data processed
618 *---------------------------------------------------------------
619 */
dissect_lwm_cmd_frame_route_err(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * lwm_cmd_tree)620 static int dissect_lwm_cmd_frame_route_err(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *lwm_cmd_tree)
621 {
622 if(lwm_cmd_tree){
623 proto_item *ti;
624
625 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, ENC_LITTLE_ENDIAN);
626 ti = proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, ENC_LITTLE_ENDIAN);
627
628 if(tvb_get_guint8(tvb, 5) == LWM_CMD_MULTI_ADDR_TRUE){
629 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
630 }else{
631 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
632 }
633
634 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA);
635 }
636
637 return LWM_CMD_FRAME_ROUTE_ERR_LEN;
638
639 } /* dissect_lwm_cmd_frame_route_err*/
640
641 /*FUNCTION:------------------------------------------------------
642 * NAME
643 * dissect_lwm_cmd_frame_route_req
644 * DESCRIPTION
645 * LwMesh command frame - Route Request.
646 *
647 * PARAMETERS
648 * tvbuff_t *tvb - pointer to buffer containing raw packet.
649 * packet_info *pinfo - pointer to packet information fields
650 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
651 * RETURNS
652 * int length - amount of data processed
653 *---------------------------------------------------------------
654 */
dissect_lwm_cmd_frame_route_req(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * lwm_cmd_tree)655 static int dissect_lwm_cmd_frame_route_req(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *lwm_cmd_tree)
656 {
657 if(lwm_cmd_tree){
658 proto_item *ti;
659 guint8 lwm_linkqual;
660
661 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, ENC_LITTLE_ENDIAN);
662 ti = proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, ENC_LITTLE_ENDIAN);
663
664 if(tvb_get_guint8(tvb, 5) == LWM_CMD_MULTI_ADDR_TRUE){
665 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
666 }else{
667 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
668 }
669
670 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA);
671
672 lwm_linkqual = tvb_get_guint8(tvb, 6);
673 ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_linkquality, tvb, 6, 1, lwm_linkqual);
674 if(lwm_linkqual == 255){
675 proto_item_append_text(ti, " %s", LWM_CMD_LINKQ_STRING);
676 }
677 }
678
679 return LWM_CMD_FRAME_ROUTE_REQ_LEN;
680
681 } /* dissect_lwm_cmd_frame_route_req*/
682
683 /*FUNCTION:------------------------------------------------------
684 * NAME
685 * dissect_lwm_cmd_frame_route_reply
686 * DESCRIPTION
687 * LwMesh command frame - Route Reply.
688 *
689 * PARAMETERS
690 * tvbuff_t *tvb - pointer to buffer containing raw packet.
691 * packet_info *pinfo - pointer to packet information fields
692 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
693 * RETURNS
694 * int length - amount of data processed
695 *---------------------------------------------------------------
696 */
dissect_lwm_cmd_frame_route_reply(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * lwm_cmd_tree)697 static int dissect_lwm_cmd_frame_route_reply(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *lwm_cmd_tree)
698 {
699 if(lwm_cmd_tree){
700 proto_item *ti;
701 guint8 lwm_revlinkqual;
702
703 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_src, tvb, 1, 2, ENC_LITTLE_ENDIAN);
704 ti = proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_dst, tvb, 3, 2, ENC_LITTLE_ENDIAN);
705
706 if(tvb_get_guint8(tvb, 5) == LWM_CMD_MULTI_ADDR_TRUE){
707 proto_item_append_text(ti, " %s", LWM_MULTI_GROUP_STRING);
708 }else{
709 proto_item_append_text(ti, " %s", LWM_MULTI_UNICAST_STRING);
710 }
711
712 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_route_multi, tvb, 5, 1, ENC_NA);
713 proto_tree_add_item(lwm_cmd_tree, hf_lwm_cmd_forwlinkquality, tvb, 6, 1, ENC_NA);
714
715 lwm_revlinkqual = tvb_get_guint8(tvb, 7);
716 ti = proto_tree_add_uint(lwm_cmd_tree, hf_lwm_cmd_revlinkquality, tvb, 7, 1, lwm_revlinkqual);
717 if(lwm_revlinkqual == 255){
718 proto_item_append_text(ti, " %s", LWM_CMD_LINKQ_STRING);
719 }
720 }
721
722 return LWM_CMD_FRAME_ROUTE_REPLY_LEN;
723
724 } /* dissect_lwm_cmd_frame_route_reply*/
725
726 /*FUNCTION:------------------------------------------------------
727 * NAME
728 * proto_register_lwm
729 * DESCRIPTION
730 * IEEE 802.15.4 protocol registration routine.
731 * PARAMETERS
732 * none
733 * RETURNS
734 * void
735 *---------------------------------------------------------------
736 */
proto_register_lwm(void)737 void proto_register_lwm(void)
738 {
739
740 static hf_register_info hf[] = {
741
742 /*Frame control field*/
743 { &hf_lwm_fcf,
744 { "Frame control field", "lwm.fcf", FT_UINT8, BASE_HEX, NULL, 0x0,
745 "Control information for the frame.", HFILL }},
746
747 { &hf_lwm_fcf_ack_req,
748 { "Acknowledgment Request", "lwm.ack_req", FT_BOOLEAN, 8, NULL, LWM_FCF_ACK_REQUEST,
749 "Specifies whether an acknowledgment is required from the destination node.", HFILL }},
750
751 { &hf_lwm_fcf_security,
752 { "Security Enabled", "lwm.security", FT_BOOLEAN, 8, NULL, LWM_FCF_SEC_EN,
753 "Specifies whether the frame payload is encrypted.", HFILL }},
754
755 { &hf_lwm_fcf_linklocal,
756 { "Link Local", "lwm.linklocal", FT_BOOLEAN, 8, NULL, LWM_FCF_LINK_LOCAL,
757 "It may be set to one to prevent neighboring nodes from rebroadcasting a frame.", HFILL }},
758
759 { &hf_lwm_fcf_multicast,
760 { "Multicast", "lwm.multicast", FT_BOOLEAN, 8, NULL, LWM_FCF_MULTICAST,
761 "If the Multicast subfield is set to one, Multicast Header should be present and the Destination Address is a group address.", HFILL }},
762
763 { &hf_lwm_fcf_reserved,
764 { "Reserved bits", "lwm.fcf.reserved", FT_UINT8, BASE_HEX, NULL, LWM_FCF_RESERVED,
765 "The 4 bits are reserved.", HFILL }},
766
767 /*Other fields*/
768 { &hf_lwm_seq,
769 { "Sequence Number", "lwm.seq", FT_UINT8, BASE_DEC, NULL, 0x0,
770 "Specifies the sequence identifier for the frame.", HFILL }},
771
772 { &hf_lwm_src_addr,
773 { "Network Source Address", "lwm.src_addr", FT_UINT16, BASE_HEX, NULL, 0x0,
774 "Specifies the network address of the node originating the frame.", HFILL }},
775
776 { &hf_lwm_dst_addr,
777 { "Network Destination Address", "lwm.dst_addr", FT_UINT16, BASE_HEX, NULL, 0x0,
778 "Specifies the network address of the destination node or group address for multicast messages.", HFILL }},
779
780 { &hf_lwm_src_endp,
781 { "Source Endpoint", "lwm.src_endp", FT_UINT8, BASE_DEC, NULL, 0x0,
782 "Specifies the source endpoint identifier.", HFILL }},
783
784 { &hf_lwm_dst_endp,
785 { "Destination Endpoint", "lwm.dst_endp", FT_UINT8, BASE_DEC, NULL, 0x0,
786 "Specifies the destination endpoint identifier.", HFILL }},
787
788
789 /*Multicast header*/
790 { &hf_lwm_multi_nmrad,
791 { "Non-member Radius", "lwm.multi_nmrad", FT_UINT8, BASE_DEC, NULL, 0x0,
792 "Specifies remaining radius (number of hops) for Non-members of multicast group.", HFILL }},
793
794 { &hf_lwm_multi_mnmrad,
795 { "Maximum Non-member Radius", "lwm.multi_mnmrad", FT_UINT8, BASE_DEC, NULL, 0x0,
796 "Specifies maximum radius (number of hops) for Non-members of multicast group.", HFILL }},
797
798 { &hf_lwm_multi_mrad,
799 { "Member Radius", "lwm.multi_mrad", FT_UINT8, BASE_DEC, NULL, 0x0,
800 "Specifies remaining radius (number of hops) for Members of multicast group.", HFILL }},
801
802 { &hf_lwm_multi_mmrad,
803 { "Maximum Member Radius", "lwm.multi_mmrad", FT_UINT8, BASE_DEC, NULL, 0x0,
804 "Specifies maximum radius (number of hops) for Members of multicast group.", HFILL }},
805
806
807 /*MIC, security*/
808 { &hf_lwm_mic,
809 { "Message Integrity Code", "lwm.mic", FT_UINT32, BASE_HEX, NULL, 0x0,
810 "Specifies Message Integrity Code (MIC).", HFILL }},
811
812
813 /*----------------------------------*/
814 /* */
815 /* Command Frames Specific Fields */
816 /* */
817 /*----------------------------------*/
818
819 { &hf_lwm_cmd,
820 { "Command ID", "lwm.cmd", FT_UINT8, BASE_HEX, VALS(lwm_cmd_names), 0x0,
821 "It contains Command ID value.", HFILL }},
822
823 /* Command Frame - Ack */
824 { &hf_lwm_cmd_seq,
825 { "Sequence number", "lwm.cmd.seq", FT_UINT8, BASE_DEC, NULL, 0x0,
826 "It contains a network sequence number of a frame that is being acknowledged.", HFILL }},
827
828 { &hf_lwm_cmd_cm,
829 { "Control Message", "lwm.cmd.cm", FT_UINT8, BASE_HEX, NULL, 0x0,
830 "It contains an arbitrary value that can be set on the sending side.", HFILL }},
831
832 /* Part of Command Frames - Route Request, Route Reply*/
833 { &hf_lwm_cmd_route_src,
834 { "Source address", "lwm.cmd.route_src", FT_UINT16, BASE_HEX, NULL, 0x0,
835 "It contains a source network address from the frame that cannot be routed", HFILL }},
836
837 { &hf_lwm_cmd_route_dst,
838 { "Destination Address", "lwm.cmd.route_dst", FT_UINT16, BASE_HEX, NULL, 0x0,
839 "It contains a destination network address from the frame that cannot be routed", HFILL }},
840
841 { &hf_lwm_cmd_route_multi,
842 { "Multicast", "lwm.cmd.multi", FT_UINT8, BASE_HEX, VALS(lwm_cmd_multi_names), 0x0,
843 "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 }},
844
845 /* Part of Command Frame - Route Request */
846 { &hf_lwm_cmd_linkquality,
847 { "Link Quality", "lwm.cmd.linkq", FT_UINT8, BASE_DEC, NULL, 0x0,
848 "It contains a link quality value of the potential route accumulated over all hops towards the destination.", HFILL }},
849
850 /* Part of Command Frame - Route Reply */
851 { &hf_lwm_cmd_forwlinkquality,
852 { "Forward Link Quality", "lwm.cmd.flinkq", FT_UINT8, BASE_DEC, NULL, 0x0,
853 "It contains a value of the Link Quality field from the corresponding Route Request Command Frame.", HFILL }},
854
855 { &hf_lwm_cmd_revlinkquality,
856 { "Reverse Link Quality", "lwm.cmd.rlinkq", FT_UINT8, BASE_DEC, NULL, 0x0,
857 "It contains a link quality value of the discovered route accumulated over all hops towards the originator.", HFILL }},
858
859
860 };
861
862 /* Subtrees */
863 static gint *ett[] = {
864 &ett_lwm,
865 &ett_lwm_fcf,
866 &ett_lwm_multi_tree,
867 &ett_lwm_cmd_tree
868 };
869
870 static ei_register_info ei[] = {
871 { &ei_lwm_mal_error, { "lwm.malformed_error", PI_MALFORMED, PI_ERROR, "Malformed Packet", EXPFILL }},
872 { &ei_lwm_n_src_broad, { "lwm.not_src_broadcast", PI_COMMENTS_GROUP, PI_NOTE, "Source address can not be broadcast address !", EXPFILL }},
873 { &ei_lwm_mismatch_endp, { "lwm.mismatch_endp", PI_COMMENTS_GROUP, PI_WARN, "Stack command Endpoints mismatch (should be 0, both)!", EXPFILL }},
874 { &ei_lwm_empty_payload, { "lwm.empty_payload", PI_COMMENTS_GROUP, PI_WARN, "Empty LwMesh Payload!", EXPFILL }},
875 { &ei_lwm_no_decryption_key, { "lwm.no_decryption_key", PI_PROTOCOL, PI_NOTE, "No encryption key set - can't decrypt", EXPFILL }},
876 { &ei_lwm_decryption_failed, { "lwm.decryption_failed", PI_PROTOCOL, PI_WARN, "Decryption Failed", EXPFILL }},
877 };
878
879 module_t *lw_module;
880 expert_module_t* expert_lwm;
881
882 /* Register protocol name and description. */
883 proto_lwm = proto_register_protocol("Lightweight Mesh (v1.1.1)", "LwMesh", "lwm");
884
885 /* Register header fields and subtrees. */
886 proto_register_field_array(proto_lwm, hf, array_length(hf));
887 proto_register_subtree_array(ett, array_length(ett));
888 expert_lwm = expert_register_protocol(proto_lwm);
889 expert_register_field_array(expert_lwm, ei, array_length(ei));
890
891 lw_module = prefs_register_protocol(proto_lwm,proto_reg_handoff_lwm);
892
893 /* Register preferences for a decryption key */
894 /* TODO: Implement a UAT for multiple keys, and with more advanced key management. */
895 prefs_register_string_preference(lw_module, "lwmes_key", "Lw Decryption key",
896 "128-bit decryption key in hexadecimal format", (const char **)&lwmes_key_str);
897
898 /* Register dissector with Wireshark. */
899 lwm_handle = register_dissector("lwm", dissect_lwm, proto_lwm);
900
901 } /* proto_register_lwm */
902
903 /*FUNCTION:------------------------------------------------------
904 * NAME
905 * proto_reg_handoff_lwm
906 * DESCRIPTION
907 * Registers the lwm dissector with Wireshark.
908 * Will be called during Wireshark startup.
909 * PARAMETERS
910 * none
911 * RETURNS
912 * void
913 *---------------------------------------------------------------
914 */
proto_reg_handoff_lwm(void)915 void proto_reg_handoff_lwm(void)
916 {
917 GByteArray *bytes;
918 gboolean res;
919
920 /* Convert key to raw bytes */
921 bytes = g_byte_array_new();
922 res = hex_str_to_bytes(lwmes_key_str, bytes, FALSE);
923 lwmes_key_valid = (res && bytes->len >= IEEE802154_CIPHER_SIZE);
924 if (lwmes_key_valid) {
925 memcpy(lwmes_key, bytes->data, IEEE802154_CIPHER_SIZE);
926 }
927 g_byte_array_free(bytes, TRUE);
928
929
930 /* Register our dissector with IEEE 802.15.4 */
931 dissector_add_for_decode_as(IEEE802154_PROTOABBREV_WPAN_PANID, lwm_handle);
932 heur_dissector_add(IEEE802154_PROTOABBREV_WPAN, dissect_lwm_heur, "Lightweight Mesh over IEEE 802.15.4", "lwm_wlan", proto_lwm, HEURISTIC_ENABLE);
933
934 } /* proto_reg_handoff_lwm */
935
936 /*
937 * Editor modelines
938 *
939 * Local Variables:
940 * c-basic-offset: 4
941 * tab-width: 8
942 * indent-tabs-mode: nil
943 * End:
944 *
945 * ex: set shiftwidth=4 tabstop=8 expandtab:
946 * :indentSize=4:tabSize=8:noTabs=true:
947 */
948