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