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