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