For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / epan / dissectors / packet-dec-dnart.c
1 /* packet-dec-dnart.c
2  *
3  * Routines for DECnet NSP/RT  disassembly
4  *
5  * Copyright 2003-2005 Philips Medical Systems
6  * Copyright 2003-2005 Fred Hoekstra, Philips Medical Systems.
7  *                (fred.hoekstra@philips.com)
8  *
9  * $Id$
10  *
11  * Use was made of the following documentation:
12  *
13  *         DECnet DIGITAL Network Architecture
14  *      Routing Layer Functional Specification
15  *      Version 2.0.0 May, 1983
16  *
17  *         DECnet DIGITAL Network Architecture
18  *      NSP Functional Specification
19  *      Phase IV, Version 4.0.1, July 1984
20  *
21  *      DNA FS SESSION CONTROL
22  *      SECON.RNO [31,1]
23  *      EDITED 10/17/80
24  *
25  * See
26  *
27  *      http://h71000.www7.hp.com/wizard/decnet/
28  *
29  * for some DECnet specifications.
30  *
31  * Wireshark - Network traffic analyzer
32  * By Gerald Combs <gerald@wireshark.org>
33  * Copyright 1998 Gerald Combs
34  *
35  * This program is free software; you can redistribute it and/or
36  * modify it under the terms of the GNU General Public License
37  * as published by the Free Software Foundation; either version 2
38  * of the License, or (at your option) any later version.
39  *
40  * This program is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43  * GNU General Public License for more details.
44  *
45  * You should have received a copy of the GNU General Public License
46  * along with this program; if not, write to the Free Software
47  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
48  */
49
50 #ifdef HAVE_CONFIG_H
51 # include "config.h"
52 #endif
53
54 #include <glib.h>
55 #include <epan/packet.h>
56 #include <epan/emem.h>
57 #include <epan/etypes.h>
58 #include <epan/ppptypes.h>
59
60 typedef enum {
61     RT_CTL_INITIALIZATION,
62     RT_CTL_VERIFICATION,
63     RT_CTL_HELLO_TEST,
64     RT_CTL_LVL1_ROUTING,
65     RT_CTL_LVL2_ROUTING,
66     RT_CTL_ETH_ROUTER_HELLO_MSG,
67     RT_CTL_ETH_ENDNODE_HELLO_MSG
68 } ctl_msg_types;
69
70 #define DEC_RT_SIZE        27
71
72 #define DATA_SEGMENT_MSG     0x00 /* "Data segment" */
73 #define LINK_SERVICE_MSG     0x10 /* "Link service message" */
74 #define BOM_MSG              0x20 /* "Beginning of segment (BOM)message" */
75 #define EOM_MSG              0x40 /* "End of segment (EOM)message" */
76 #define BOM_EOM_MSG          0x60 /* "BOM / EOM message" */
77 #define INTERRUPT_MSG        0x30 /* "Interrupt message" */
78 #define DATA_ACK_MSG         0x04 /* "Data acknowledgement message" */
79 #define OTHER_DATA_ACK_MSG   0x14 /* "Other data acknowledgement message" */
80 #define CONN_ACK_MSG         0x24 /* "Connect acknowledgement message" */
81 #define NOP_MSG              0x08 /* "NOP" */
82 #define CONN_INITIATE_MSG    0x18 /* "Connect initiate" */
83 #define CONN_CONFIRM_MSG     0x28 /* "Connect confirm" */
84 #define DISCONN_INITIATE_MSG 0x38 /* "Disconnect initiate" */
85 #define DISCONN_CONFIRM_MSG  0x48 /* "Disconnect confirm" */
86 #define RE_XMT_CONN_INIT_MSG 0x68 /* "Retransmitted connect initiate" */
87
88 /* Flag bits */
89
90 #define RT_FLAGS_CTRL_MSG      0x01
91 #define RT_FLAGS_LONG_MSG      0x04 /* Actually: 0x06->long, 0x02->short*/
92 #define RT_FLAGS_RQR           0x08
93 #define RT_FLAGS_RTS           0x10
94 #define RT_FLAGS_INTRA_ETHER   0x20
95 #define RT_FLAGS_DISCARD       0x40
96 #define RT_FLAGS_PAD           0x80
97
98 static int proto_dec_rt = -1;
99
100 static int hf_dec_routing_flags = -1;
101 static int hf_dec_rt_ctrl_msg = -1;
102 static int hf_dec_rt_long_msg = -1;
103 static int hf_dec_rt_short_msg = -1;
104 static int hf_dec_rt_rqr = -1;
105 static int hf_dec_rt_rts = -1;
106 static int hf_dec_rt_inter_eth = -1;
107 static int hf_dec_rt_discard = -1;
108 static int hf_dec_rt_dst_addr = -1;
109 static int hf_dec_rt_src_addr = -1;
110 static int hf_dec_rt_nl2 = -1;
111 static int hf_dec_rt_service_class = -1;
112 static int hf_dec_rt_protocol_type = -1;
113 static int hf_dec_rt_visit_count = -1;
114 static int hf_dec_rt_dst_node = -1;
115 static int hf_dec_rt_src_node = -1;
116 /* Routing control messages */
117 static int hf_dec_rt_visited_nodes = -1;
118 static int hf_dec_ctl_msgs = -1;
119 static int hf_dec_ctl_msg_hdr = -1;
120 static int hf_dec_nsp_msgs = -1;
121 static int hf_dec_rt_tiinfo = -1;
122 static int hf_dec_rt_blk_size = -1;
123 static int hf_dec_rt_version = -1;
124 static int hf_dec_rt_timer = -1;
125 static int hf_dec_rt_reserved = -1;
126 static int hf_dec_rt_fcnval = -1;
127 static int hf_dec_rt_test_data = -1;
128 static int hf_dec_rt_segment = -1;
129 static int hf_dec_rt_id = -1;
130 static int hf_dec_rt_iinfo = -1;
131 static int hf_dec_rt_iinfo_node_type = -1;
132 static int hf_dec_rt_iinfo_vrf = -1;
133 static int hf_dec_rt_iinfo_rej = -1;
134 static int hf_dec_rt_iinfo_verf = -1;
135 static int hf_dec_rt_iinfo_mta = -1;
136 static int hf_dec_rt_iinfo_blkreq = -1;
137 static int hf_dec_rt_iprio = -1;
138 static int hf_dec_rt_neighbor = -1;
139 static int hf_dec_rt_seed = -1;
140 static int hf_dec_rt_elist = -1;
141 static int hf_dec_rt_ename = -1;
142 static int hf_dec_rt_router_id = -1;
143 static int hf_dec_rt_router_state = -1;
144 static int hf_dec_rt_router_prio = -1;
145 static int hf_dec_rt_seg_size = -1;
146 static int hf_dec_rt_acknum = -1;
147 static int hf_dec_rt_segnum = -1;
148 static int hf_dec_rt_delay = -1;
149 static int hf_dec_flow_control = -1;
150 static int hf_dec_rt_fc_val = -1;
151 static int hf_dec_rt_services = -1;
152 static int hf_dec_rt_info = -1;
153 static int hf_dec_disc_reason = -1;
154 static int hf_dec_conn_contents = -1;
155 static int hf_dec_sess_obj_type = -1;
156 static int hf_dec_sess_grp_code = -1;
157 static int hf_dec_sess_usr_code = -1;
158 static int hf_dec_sess_dst_name = -1;
159 static int hf_dec_sess_src_name = -1;
160 static int hf_dec_sess_menu_ver = -1;
161 static int hf_dec_sess_rqstr_id = -1;
162
163 static gint ett_dec_rt = -1;
164 static gint ett_dec_routing_flags = -1;
165 static gint ett_dec_msg_flags = -1;
166 static gint ett_dec_rt_ctl_msg = -1;
167 static gint ett_dec_rt_nsp_msg = -1;
168 static gint ett_dec_rt_info_flags = -1;
169 static gint ett_dec_rt_list = -1;
170 static gint ett_dec_rt_rlist = -1;
171 static gint ett_dec_rt_state = -1;
172 static gint ett_dec_flow_control = -1;
173 static gint ett_dec_sess_contents = -1;
174
175 static gint dec_dna_total_bytes_this_segment = 0;
176 static gint dec_dna_previous_total = 0;
177
178 /*static const value_string protocol_id_vals[] = {
179     { 0x6001, "DEC DNA dump/load" },
180     { 0x6002, "DEC DNA Remote Console" },
181     { 0x6003, "DEC DNA routing" },
182     { 0x6004, "DEC DNA Local Area Transport" },
183     { 0x6005, "DEC DNA diagnostics" },
184     { 0x6006, "DEC DNA Customer specific" },
185     { 0x6007, "DEC DNA System Communication Architecture" },
186     { 0,    NULL }
187 };*/
188
189 static const value_string rt_msg_type_vals[] = {
190     { 0x0   , "Initialization message" },
191     { 0x1   , "Verification message" },
192     { 0x2   , "Hello and test message" },
193     { 0x3   , "Level 1 routing message" },
194     { 0x4   , "Level 2 routing message" },
195     { 0x5   , "Ethernet router hello message" },
196     { 0x6   , "Ethernet endnode hello message" },
197     { 0,    NULL }
198 };
199
200 static const value_string nsp_msg_type_vals[] = {
201     { 0x00   , "Data segment continuation" },
202     { 0x04   , "Data acknowledgement message" },
203     { 0x08   , "NOP" },
204     { 0x10   , "Link service message" },
205     { 0x14   , "Other data acknowledgement message" },
206     { 0x18   , "Connect initiate" },
207     { 0x20   , "Beginning of segment message" },
208     { 0x24   , "Connect acknowledgement message" },
209     { 0x28   , "Connect confirm" },
210     { 0x30   , "Interrupt message" },
211     { 0x38   , "Disconnect initiate" },
212     { 0x40   , "End of segment message" },
213     { 0x48   , "Disconnect confirm" },
214     { 0x60   , "Begin of segment / End of segment" },
215     { 0x68   , "Retransmitted connect initiate" },
216     { 0,    NULL }
217 };
218
219 static const value_string rt_tiinfo_vals[] = {
220     {0x01,  "Level 2 router"},
221     {0x02,  "Level 1 router"},
222     {0x03,  "End node"},
223     {0x04,  "Routing layer verification required"},
224     {0x08,  "Blocking requested"},
225     {0x0,  NULL}
226 };
227
228 static const value_string rt_iinfo_node_type_vals[] = {
229     {0x01,  "Level 2 router"},
230     {0x02,  "Level 1 router"},
231     {0x03,  "End node"},
232     {0x0,  NULL}
233 };
234
235 static const value_string rt_flow_control_vals[] = {
236     {0x00,  "no change"},
237     {0x01,  "do not send data"},
238     {0x02,  "send data"},
239     {0x03,  "reserved"},
240     {0x0,  NULL}
241 };
242
243 static const value_string rt_services_vals[] = {
244     {0x00,  "none"},
245     {0x04,  "segment request count"},
246     {0x08,  "Session control message request count"},
247     {0x0c,  "reserved"},
248     {0x0,   NULL}
249 };
250
251 static const value_string rt_info_version_vals[] = {
252     {0x00,  "version 3.2"},
253     {0x01,  "version 3.1"},
254     {0x02,  "version 4.0"},
255     {0x03,   "reserved"},
256     {0x0,   NULL}
257 };
258
259 static const value_string rt_disc_reason_vals[] = {
260     { 0,    "no error"},
261     { 3,    "The node is shutting down"},
262     { 4,    "The destination end user does not exist"},
263     { 5,    "A connect message contains an invalid end user name"},
264     { 6,    "Destination end user has insufficient resources"},
265     { 7,    "Unspecified error"},
266     { 8,    "A third party has disconnected the link"},
267     { 9,    "An end user has aborted the logical link"},
268     { 32,   "The node has insufficient resources"},
269     { 33,   "Destination end user has insufficient resources"},
270     { 34,   "Connect request rejected because incorrect RQSTRID or PASSWORD"},
271     { 36,   "Connect request rejected because of unacceptable ACCOUNT info"},
272     { 38,   "End user has timed out, aborted or cancelled a connect request"},
273     { 43,   "Connect request RQSTRID, PASSWORD, ACCOUNT or USRDATA too long"},
274     { 0,    NULL}
275 };
276
277 #define RT_TYPE_TOPOLOGY_CHANGE    2
278 #define RT_TYPE_HELLO            25
279
280 #if ! defined true
281 #define true 1
282 #endif
283 #if ! defined false
284 #define false 0
285 #endif
286
287 static int
288 handle_nsp_msg(
289     tvbuff_t *tvb,
290     packet_info *pinfo,
291     proto_tree *tree,
292     guint offset,
293     guint8 nsp_msg_type);
294
295
296 static int
297 do_initialization_msg(
298     tvbuff_t *tvb,
299     packet_info *pinfo,
300     proto_tree *ctl_msg_tree,
301     guint offset);
302
303 static int
304 do_verification_msg(
305     tvbuff_t *tvb,
306     packet_info *pinfo,
307     proto_tree *ctl_msg_tree,
308     guint offset);
309
310 static int
311 do_hello_test_msg(
312     tvbuff_t *tvb,
313     packet_info *pinfo,
314     proto_tree *ctl_msg_tree,
315     guint offset);
316
317 static int
318 do_routing_msg(
319     tvbuff_t *tvb,
320     packet_info *pinfo,
321     proto_tree *ctl_msg_tree,
322     guint offset,
323     guint msg);
324
325 static int
326 do_hello_msg(
327     tvbuff_t *tvb,
328     packet_info *pinfo,
329     proto_tree *ctl_msg_tree,
330     guint offset,
331     guint msg);
332
333 static int
334 handle_connect_contents(
335     tvbuff_t *tvb,
336     proto_tree *tree,
337     guint offset);
338
339 static int
340 handle_disc_init_contents(
341     guint offset);
342
343 static char *
344 dnet_ntoa(const guint8 *data)
345 {
346     if (data[0] == 0xAA && data[1] == 0x00 && data[2] == 0x04 && data[3] == 0x00) {
347         guint16 dnet_addr = data[4] | (data[5] << 8);
348         return ep_strdup_printf("%d.%d", dnet_addr >> 10, dnet_addr & 0x03FF);
349     }
350     return NULL;
351 }
352
353 static void
354 set_dnet_address(address *paddr_src, address *paddr_tgt)
355 {
356     if (paddr_tgt->type != AT_STRINGZ && paddr_src->type == AT_ETHER) {
357         char *addr = dnet_ntoa(paddr_src->data);
358         if (addr != NULL)
359             SET_ADDRESS(paddr_tgt, AT_STRINGZ, 1, addr);
360     }
361 }
362
363 static void
364 dissect_dec_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
365 {
366     guint8  padding_length;
367     guint8  forward;
368     guint8  msg_flags;
369     guint   rt_visit_count, rt_zero = 0;
370     guint16 payload_length;
371     guint16 dst_node, src_node;
372     gint    offset;
373     gboolean  long_msg = false;
374     proto_tree *rt_tree;
375     proto_tree *flags_tree;
376     proto_item *ti;
377     char *addr;
378
379     offset = 0;
380     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DEC DNA");
381     col_clear(pinfo->cinfo, COL_INFO);
382
383     set_dnet_address(&pinfo->dl_src, &pinfo->net_src);
384     set_dnet_address(&pinfo->dl_src, &pinfo->src);
385     set_dnet_address(&pinfo->dl_dst, &pinfo->net_dst);
386     set_dnet_address(&pinfo->dl_dst, &pinfo->dst);
387
388     payload_length = tvb_get_letohs(tvb, offset);
389     offset += 2;
390     msg_flags = tvb_get_guint8(tvb, offset);
391     ti = proto_tree_add_item(tree, proto_dec_rt, tvb, 0, -1,
392                 ENC_NA);
393     rt_tree = proto_item_add_subtree(ti, ett_dec_rt);
394     /* When padding, the first byte after the padding has
395        the real routing flags */
396     if (msg_flags & 0x80) {
397         /* There is padding present, skip it */
398         padding_length = msg_flags & 0x7f;
399         offset += padding_length;
400     }
401
402     /* The real routing flag */
403     msg_flags = tvb_get_guint8(tvb, offset);
404     ti = proto_tree_add_uint(rt_tree, hf_dec_routing_flags, tvb,
405                     offset, 1, msg_flags);
406     flags_tree = proto_item_add_subtree(ti, ett_dec_routing_flags);
407
408     if (msg_flags & RT_FLAGS_CTRL_MSG) {
409         guint   new_offset;
410         guint8  ctl_msg_type;
411         proto_tree *ctl_msg_tree;
412
413         ctl_msg_type = (msg_flags >> 1) & 0x7;
414         proto_tree_add_boolean(flags_tree, hf_dec_rt_ctrl_msg, tvb, offset, 1,
415             msg_flags);
416         proto_tree_add_uint(flags_tree, hf_dec_ctl_msgs, tvb, offset, 1,
417             msg_flags);
418
419         ti = proto_tree_add_uint(rt_tree, hf_dec_ctl_msg_hdr, tvb, offset, 1,
420             ctl_msg_type);
421         ctl_msg_tree = proto_item_add_subtree(ti, ett_dec_rt_ctl_msg);
422
423         /* Get past the msg_flags */
424         offset++;
425         switch (ctl_msg_type) {
426             case RT_CTL_INITIALIZATION:
427                 new_offset =
428                     do_initialization_msg(
429                         tvb, pinfo, ctl_msg_tree, offset);
430             break;
431             case RT_CTL_VERIFICATION:
432                 new_offset =
433                     do_verification_msg(
434                         tvb, pinfo, ctl_msg_tree, offset);
435             break;
436             case RT_CTL_HELLO_TEST:
437                 new_offset =
438                     do_hello_test_msg(
439                         tvb, pinfo, ctl_msg_tree, offset);
440             break;
441             case RT_CTL_LVL1_ROUTING:
442             case RT_CTL_LVL2_ROUTING:
443                 new_offset =
444                     do_routing_msg(
445                         tvb, pinfo, ctl_msg_tree, offset, msg_flags >> 1);
446             break;
447             case RT_CTL_ETH_ROUTER_HELLO_MSG:
448             case RT_CTL_ETH_ENDNODE_HELLO_MSG:
449                 new_offset =
450                     do_hello_msg(
451                         tvb, pinfo, ctl_msg_tree, offset, msg_flags >> 1);
452             break;
453             default:
454             break;
455         }
456     } else if (msg_flags & RT_FLAGS_LONG_MSG){
457         proto_tree_add_uint(flags_tree, hf_dec_rt_long_msg,
458                 tvb, offset, 1, msg_flags);
459         proto_tree_add_boolean(flags_tree, hf_dec_rt_rqr, tvb,
460                     offset, 1, msg_flags);
461         proto_tree_add_boolean(flags_tree, hf_dec_rt_rts, tvb,
462                     offset, 1, msg_flags);
463         proto_tree_add_boolean(flags_tree, hf_dec_rt_inter_eth, tvb,
464                     offset, 1, msg_flags);
465         proto_tree_add_boolean(flags_tree, hf_dec_rt_discard, tvb,
466                     offset, 1, msg_flags);
467         long_msg = true;
468
469         /* Increment offset by three:
470                 1 to get past the flags field
471                 2 to skip the DEC area/subarea field
472          */
473         offset += 3;
474         ti = proto_tree_add_item(rt_tree, hf_dec_rt_dst_addr, tvb,
475                 offset, 6, ENC_NA);
476         addr = dnet_ntoa(ep_tvb_memdup(tvb, offset, 6));
477         if (addr != NULL) {
478             proto_item_append_text(ti, " (%s)", addr);
479         }
480
481         /* Skip 6 bytes for the MAC and
482                 2 bytes for DEC area/subarea
483             */
484         offset += 8;
485         ti = proto_tree_add_item(rt_tree, hf_dec_rt_src_addr, tvb,
486             offset, 6, ENC_NA);
487         addr = dnet_ntoa(ep_tvb_memdup(tvb, offset, 6));
488         if (addr != NULL) {
489             proto_item_append_text(ti, " (%s)", addr);
490         }
491
492         /* Proceed to the NL2 byte */
493         offset += 6;
494         proto_tree_add_uint(rt_tree, hf_dec_rt_nl2, tvb,
495             offset, 1, rt_zero);
496         offset++;
497         rt_visit_count = tvb_get_guint8(tvb, offset);
498         proto_tree_add_uint(rt_tree, hf_dec_rt_visit_count, tvb,
499             offset, 1, rt_visit_count);
500         offset++;
501         proto_tree_add_uint(rt_tree, hf_dec_rt_service_class, tvb,
502             offset, 1, rt_zero);
503         offset++;
504         proto_tree_add_uint(rt_tree, hf_dec_rt_protocol_type, tvb,
505             offset, 1, rt_zero);
506         offset++;
507     } else {
508         proto_tree_add_uint(flags_tree, hf_dec_rt_short_msg,
509                 tvb, offset, 1, msg_flags);
510         proto_tree_add_boolean(flags_tree, hf_dec_rt_rqr, tvb,
511                     offset, 1, msg_flags);
512         proto_tree_add_boolean(flags_tree, hf_dec_rt_rts, tvb,
513                     offset, 1, msg_flags);
514
515         /* Increment offset to get past the flags field
516          */
517         offset++;
518         dst_node = tvb_get_letohs(tvb, offset);
519         proto_tree_add_item(rt_tree, hf_dec_rt_dst_node, tvb,
520             offset, 2, ENC_LITTLE_ENDIAN);
521         offset += 2;
522         src_node = tvb_get_letohs(tvb, offset);
523         proto_tree_add_item(rt_tree, hf_dec_rt_src_node, tvb,
524             offset, 2, ENC_LITTLE_ENDIAN);
525         offset += 2;
526         forward = tvb_get_guint8(tvb, offset);
527         proto_tree_add_uint(rt_tree, hf_dec_rt_visited_nodes, tvb,
528             offset, 1, forward);
529         offset++;
530     }
531
532     if (!(msg_flags & RT_FLAGS_CTRL_MSG)) {
533         /* It is not a routing control message */
534         proto_tree *nsp_msg_tree;
535         proto_item *ti_local;
536         guint8     nsp_msg_type;
537         guint16    dst_node_local, src_node_local;
538
539         nsp_msg_type = tvb_get_guint8(tvb, offset);
540            ti_local = proto_tree_add_uint(
541             tree, hf_dec_nsp_msgs, tvb, offset, 1, nsp_msg_type);
542         if (nsp_msg_type == NOP_MSG) {
543             /* Only test data in this msg */
544             return;
545         }
546         nsp_msg_tree = proto_item_add_subtree(ti_local, ett_dec_rt_nsp_msg);
547         /* Get past the nsp_msg_type */
548         offset++;
549         dst_node_local = tvb_get_letohs(tvb, offset);
550         proto_tree_add_item(
551             nsp_msg_tree, hf_dec_rt_dst_node, tvb, offset, 2, ENC_LITTLE_ENDIAN);
552         offset += 2;
553         if (nsp_msg_type == CONN_ACK_MSG) {
554             col_set_str(pinfo->cinfo, COL_INFO, "NSP connect acknowledgement");
555             /* Done with this msg type */
556             return;
557         }
558         /* All other messages have a source node */
559         src_node_local = tvb_get_letohs(tvb, offset);
560         proto_tree_add_item(
561             nsp_msg_tree, hf_dec_rt_src_node, tvb, offset, 2, ENC_LITTLE_ENDIAN);
562         offset += 2;
563
564         offset =
565             handle_nsp_msg(tvb,
566                            pinfo,
567                            nsp_msg_tree,
568                            offset,
569                            nsp_msg_type);
570     }
571 }
572
573 static int
574 do_initialization_msg(
575     tvbuff_t *tvb,
576     packet_info *pinfo,
577     proto_tree *tree,
578     guint offset)
579 {
580     guint   my_offset = offset;
581     guint8  version, eco_nr, user_eco;
582     guint8  remainder_count;
583
584     col_set_str(pinfo->cinfo, COL_INFO, "Routing control, initialization message");
585     proto_tree_add_item(tree, hf_dec_rt_src_node, tvb,
586         my_offset, 2, ENC_LITTLE_ENDIAN);
587     offset += 2;
588     proto_tree_add_item(tree, hf_dec_rt_tiinfo, tvb,
589         my_offset, 2, ENC_LITTLE_ENDIAN);
590     my_offset += 2;
591     proto_tree_add_item(tree, hf_dec_rt_blk_size, tvb,
592         my_offset, 2, ENC_LITTLE_ENDIAN);
593     my_offset += 2;
594     version = tvb_get_guint8(tvb, my_offset);
595     eco_nr = tvb_get_guint8(tvb, my_offset + 1);
596     user_eco = tvb_get_guint8(tvb, my_offset + 2);
597     proto_tree_add_none_format(tree, hf_dec_rt_version, tvb,
598         my_offset, 3, "Routing Layer version: %d.%d.%d.",
599             version, eco_nr, user_eco);
600     my_offset +=3;
601     proto_tree_add_item(tree, hf_dec_rt_timer, tvb,
602         my_offset, 2, ENC_LITTLE_ENDIAN);
603     my_offset += 2;
604     remainder_count = tvb_get_guint8(tvb, my_offset);
605     if (remainder_count != 0) {
606         proto_tree_add_item(tree, hf_dec_rt_reserved, tvb,
607             my_offset, remainder_count, ENC_NA);
608         my_offset += remainder_count;
609     }
610     return (my_offset);
611 }
612
613 static int
614 do_verification_msg(
615     tvbuff_t *tvb,
616     packet_info *pinfo,
617     proto_tree *tree,
618     guint offset)
619 {
620     guint   my_offset = offset;
621     guint8  remainder_count;
622
623     col_set_str(pinfo->cinfo, COL_INFO, "Routing control, verification message");
624     proto_tree_add_item(tree, hf_dec_rt_src_node, tvb,
625         my_offset, 2, ENC_LITTLE_ENDIAN);
626     offset += 2;
627     remainder_count = tvb_get_guint8(tvb, my_offset);
628     if (remainder_count != 0) {
629         proto_tree_add_item(tree, hf_dec_rt_fcnval, tvb,
630             my_offset, remainder_count, ENC_NA);
631         my_offset += remainder_count;
632     }
633     return (my_offset);
634 }
635
636 static int
637 do_hello_test_msg(
638     tvbuff_t *tvb,
639     packet_info *pinfo,
640     proto_tree *tree,
641     guint offset)
642 {
643     guint   my_offset = offset;
644     guint   remainder_count;
645
646     col_set_str(pinfo->cinfo, COL_INFO, "Routing control, hello/test message");
647     proto_tree_add_item(tree, hf_dec_rt_src_node, tvb,
648         my_offset, 2, ENC_LITTLE_ENDIAN);
649     my_offset += 2;
650     remainder_count = tvb_length_remaining(tvb, my_offset);
651     if (remainder_count != 0) {
652         proto_tree_add_item(tree, hf_dec_rt_test_data, tvb,
653             my_offset, remainder_count, ENC_NA);
654         my_offset += remainder_count;
655     }
656     return (my_offset);
657 }
658
659 static int
660 do_routing_msg(
661     tvbuff_t *tvb,
662     packet_info *pinfo,
663     proto_tree *tree,
664     guint offset,
665     guint msg)
666 {
667     guint   my_offset = offset;
668     guint32 my_checksum = 1;
669     guint16 checksum;
670     guint16 count, startid, rtginfo;
671     guint   remainder_count;
672
673     proto_tree_add_item(tree, hf_dec_rt_src_node, tvb,
674         my_offset, 2, ENC_LITTLE_ENDIAN);
675     /* Skip the 1-byte reserved field */
676     my_offset += 3;
677     remainder_count = tvb_length_remaining(tvb, my_offset);
678     do {
679         /* if the remainder_count == 1, only the checksum remains */
680         count = tvb_get_letohs(tvb, my_offset);
681         startid = tvb_get_letohs(tvb, my_offset + 2);
682         rtginfo = tvb_get_letohs(tvb, my_offset + 4);
683         if (msg == 3) {
684             col_set_str(pinfo->cinfo, COL_INFO, "Routing control, Level 1 routing message");
685             proto_tree_add_none_format(tree, hf_dec_rt_segment, tvb,
686                 my_offset, 6,
687                 "Segment: count:%d, start Id: %d, hops:%d, cost: %d",
688                 count, startid, (rtginfo & 0x7c00) >> 10, rtginfo & 0x3ff);
689         } else {
690             col_set_str(pinfo->cinfo, COL_INFO, "Routing control, Level 2 routing message");
691             proto_tree_add_none_format(tree, hf_dec_rt_segment, tvb,
692                 my_offset, 6,
693                 "Segment: count:%d, start area: %d, hops:%d, cost: %d",
694                 count, startid, (rtginfo & 0x7c00) >> 10, rtginfo & 0x3ff);
695         };
696         my_checksum += (count + startid + rtginfo);
697         my_offset += 6;
698         remainder_count -= 6;
699     } while (remainder_count > 6);
700     my_offset += remainder_count - 2;
701     /* fold 32 bit sum into 16 bits */
702     while (my_checksum>>16)
703         my_checksum = (my_checksum & 0xffff) + (my_checksum >> 16);
704     checksum = tvb_get_letohs(tvb, my_offset);
705     if (checksum != my_checksum) {
706         proto_tree_add_none_format(tree, hf_dec_rt_segment, tvb,
707             my_offset, 2,
708             "Checksum mismatch(computed 0x%x <> received 0x%x)",
709             my_checksum, checksum);
710     } else {
711         proto_tree_add_none_format(tree, hf_dec_rt_segment, tvb,
712             my_offset, 2,
713             "Checksum: match (computed 0x%x = received 0x%x)",
714             my_checksum, checksum);
715     }
716     my_offset += 2;
717     return (my_offset);
718 }
719
720 static int
721 do_hello_msg(
722     tvbuff_t *tvb,
723     packet_info *pinfo,
724     proto_tree *tree,
725     guint offset,
726     guint msg)
727 {
728     guint   my_offset = offset;
729     guint8  iinfo, priority;
730     guint16 version, eco_nr, user_eco, timer;
731     proto_item *ti;
732     proto_tree *iinfo_tree;
733     char *addr;
734
735     version = tvb_get_guint8(tvb, my_offset);
736     eco_nr = tvb_get_guint8(tvb, my_offset + 1);
737     user_eco = tvb_get_guint8(tvb, my_offset + 2);
738     proto_tree_add_none_format(tree, hf_dec_rt_version, tvb,
739         my_offset, 3, "Routing Layer Version: %d.%d.%d",
740         version, eco_nr, user_eco);
741     my_offset +=3;
742     ti = proto_tree_add_item(tree, hf_dec_rt_id, tvb,
743         my_offset, 6, ENC_NA);
744     addr = dnet_ntoa(ep_tvb_memdup(tvb, my_offset, 6));
745     if (addr != NULL) {
746         proto_item_append_text(ti, " (%s)", addr);
747     }
748     my_offset += 6;
749     iinfo = tvb_get_guint8(tvb, my_offset);
750     ti = proto_tree_add_uint(
751         tree, hf_dec_rt_iinfo, tvb, my_offset, 1, iinfo);
752     iinfo_tree = proto_item_add_subtree(ti, ett_dec_rt_info_flags);
753     proto_tree_add_uint(
754         iinfo_tree, hf_dec_rt_iinfo_node_type, tvb, my_offset, 1, iinfo);
755     proto_tree_add_boolean(iinfo_tree, hf_dec_rt_iinfo_vrf,
756         tvb, my_offset, 1, iinfo);
757     proto_tree_add_boolean(iinfo_tree, hf_dec_rt_iinfo_rej,
758         tvb, my_offset, 1, iinfo);
759     proto_tree_add_boolean(iinfo_tree, hf_dec_rt_iinfo_verf,
760         tvb, my_offset, 1, iinfo);
761     proto_tree_add_boolean(iinfo_tree, hf_dec_rt_iinfo_mta,
762         tvb, my_offset, 1, iinfo);
763     proto_tree_add_boolean(iinfo_tree, hf_dec_rt_iinfo_blkreq,
764         tvb, my_offset, 1, iinfo);
765     my_offset++;
766     proto_tree_add_item(tree, hf_dec_rt_blk_size, tvb,
767         my_offset, 2, ENC_LITTLE_ENDIAN);
768     my_offset += 2;
769     if (msg == 5) {
770         /* Ethernet router hello message
771            Has a 'priority' field in this position */
772         col_set_str(pinfo->cinfo, COL_INFO, "Routing control, Ethernet Router Hello  message");
773         priority = tvb_get_guint8(tvb, my_offset);
774         proto_tree_add_uint(
775             tree, hf_dec_rt_iprio, tvb, my_offset, 1, priority);
776         my_offset++;
777     }
778     /* Skip the 'area' field common to both hello messages */
779     my_offset += 1;
780     if (msg == 6) {
781         /* The endnode hello message has 'seed' and 'neighbor' fields */
782         col_set_str(pinfo->cinfo, COL_INFO, "Routing control, Endnode Hello message");
783         proto_tree_add_item(tree, hf_dec_rt_seed, tvb,
784                             my_offset, 8, ENC_NA);
785         my_offset += 8;
786         ti = proto_tree_add_item(tree, hf_dec_rt_neighbor, tvb,
787                 my_offset, 6, ENC_NA);
788         addr = dnet_ntoa(ep_tvb_memdup(tvb, my_offset, 6));
789         if (addr != NULL) {
790             proto_item_append_text(ti, " (%s)", addr);
791         }
792         my_offset += 6;
793     }
794     /*'Timer' and 'mpd' fields are common
795       'mpd' field is reserved */
796     timer = tvb_get_letohs(tvb, my_offset);
797     proto_tree_add_item(tree, hf_dec_rt_timer, tvb,
798         my_offset, 2, ENC_LITTLE_ENDIAN);
799     my_offset += 3;
800     if (msg == 5) {
801         /* The Ethernet router hello message contains
802            a list of router states
803            The Ethernet Endnode Hello Message contains
804            up to 128 bytes of test data at the end.
805            These data are left to be dissected as 'data'.
806          */
807         proto_item  *ti_locala, *ti_ether;
808         proto_tree *list_tree, *list_ether;
809         guint8 image_len;
810         guint8 item_len;
811
812         /* image field is preceded by count of remainder of field */
813         image_len = tvb_get_guint8(tvb, my_offset);
814         my_offset++;
815
816         ti_locala = proto_tree_add_item(tree, hf_dec_rt_elist, tvb,
817             my_offset, image_len, ENC_NA);
818         list_tree = proto_item_add_subtree(ti_locala, ett_dec_rt_list);
819
820         while (image_len > 0) {
821             ti_ether = proto_tree_add_item(list_tree, hf_dec_rt_ename, tvb,
822                 my_offset, 7, ENC_NA);
823             list_ether = proto_item_add_subtree(ti_ether, ett_dec_rt_rlist);
824             my_offset += 7;
825             image_len -= 7;
826
827             /* image field is preceded by count of remainder of field */
828             item_len = tvb_get_guint8(tvb, my_offset);
829             my_offset++;
830             image_len -= 1;
831             while (item_len > 0)
832             {
833                 guint8  pristate;
834                 proto_item  *ti_localb;
835                 proto_tree *pstate_tree;
836
837                 ti_localb = proto_tree_add_item(list_ether, hf_dec_rt_router_id,
838                     tvb, my_offset, 6, ENC_NA);
839                 addr = dnet_ntoa(ep_tvb_memdup(tvb, my_offset, 6));
840                 if (addr != NULL) {
841                     proto_item_append_text(ti_localb, " (%s)", addr);
842                 }
843                 my_offset += 6;
844                 pstate_tree = proto_item_add_subtree(ti_localb, ett_dec_rt_state);
845                 pristate = tvb_get_guint8(tvb, my_offset);
846                 proto_tree_add_string(pstate_tree, hf_dec_rt_router_state,
847                     tvb, my_offset, 1,
848                     ((pristate & 0x80) ? "known 2-way": "unknown"));
849                 proto_tree_add_uint(pstate_tree, hf_dec_rt_router_prio,
850                     tvb, my_offset, 1, pristate);
851                 my_offset++;
852                 item_len -= 7;
853                 image_len -= 7;
854             }
855         }
856     }
857     return (my_offset);
858 }
859
860 static int
861 handle_nsp_msg(
862     tvbuff_t *tvb,
863     packet_info *pinfo,
864     proto_tree *tree,
865     guint offset,
866     guint8 nsp_msg_type)
867 {
868     /* Offset in tvb now points at the first byte still to be handled */
869     guint      my_offset = offset;
870     gint       data_length;
871     guint16    ack_num, ack_dat, ack_oth, seg_num, seg_size, reason;
872     guint8     ls_flags, fc_val, services, info;
873     proto_item  *ti;
874     proto_tree *flow_control_tree;
875
876     /* 'tree' is now the subtree for the NSP message */
877     switch (nsp_msg_type) {
878         case DATA_SEGMENT_MSG:     /* "Data segment" */
879         case BOM_MSG:              /* "Beginning of segment message" */
880         case EOM_MSG:              /* "End of segment message" */
881         case BOM_EOM_MSG:          /* "BOM / EOM message" */
882             ack_num = tvb_get_letohs(tvb, my_offset);
883             if (ack_num & 0x8000) {
884                 proto_tree_add_none_format(tree, hf_dec_rt_acknum,
885                     tvb, my_offset, 2,
886                     "Last data segment %s acknowledged: %d",
887                     (ack_num & 0x1000) ? "negatively" : "positively",
888                     ack_num & 0xfff);
889                 my_offset += 2;
890                 /* There may still be an ackoth field */
891                 ack_oth = tvb_get_letohs(tvb, my_offset);
892                 if (ack_oth & 0x8000) {
893                     /* There is an ack_oth field */
894                     proto_tree_add_none_format(tree, hf_dec_rt_acknum,
895                         tvb, my_offset, 2,
896                         "Cross sub-channel %s of other data msg %d",
897                         ((ack_oth & 0x3000) == 0x2000) ? "ACK" : "NAK",
898                         ack_oth & 0xfff);
899                     my_offset += 2;
900                 }
901             }
902             /*
903              * The optional ACKNUM and ACKOTH  fields are not present
904              * There is still the segnum field
905              */
906             seg_num = tvb_get_letohs(tvb, my_offset);
907             if (nsp_msg_type == BOM_MSG) {
908                 dec_dna_total_bytes_this_segment = 0;
909                 col_append_fstr(pinfo->cinfo, COL_INFO,
910                     "msg nr. %d: start of segment",
911                     seg_num & 0xfff);
912             } else if (nsp_msg_type == DATA_SEGMENT_MSG) {
913                 col_append_fstr(pinfo->cinfo, COL_INFO,
914                     "msg nr. %d: continuation segment ",
915                     seg_num & 0xfff);
916             } else if (nsp_msg_type == EOM_MSG) {
917                 col_append_fstr(pinfo->cinfo, COL_INFO,
918                     "msg nr. %d: end of segment",
919                     seg_num & 0xfff);
920             } else if (nsp_msg_type == BOM_EOM_MSG) {
921                 dec_dna_total_bytes_this_segment = 0;
922                 col_append_fstr(pinfo->cinfo, COL_INFO,
923                     "msg nr. %d single segment",
924                     seg_num & 0xfff);
925             }
926             /* This is the last field, the rest are data */
927             proto_tree_add_item(tree, hf_dec_rt_segnum,
928                 tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
929             proto_tree_add_boolean(tree, hf_dec_rt_delay,
930                 tvb, my_offset, 2, seg_num);
931             my_offset += 2;
932             /* Compute the number of bytes in this data segment */
933             data_length =
934                 tvb_reported_length_remaining(tvb, my_offset);
935             dec_dna_previous_total = dec_dna_total_bytes_this_segment;
936             dec_dna_total_bytes_this_segment += data_length;
937             col_append_fstr(pinfo->cinfo, COL_INFO,
938                 ", bytes this segment: %d, total so far:%d",
939                 data_length, dec_dna_total_bytes_this_segment);
940             /* We are done, return my_offset */
941             break;
942         case INTERRUPT_MSG:        /* "Interrupt message" */
943             col_set_str(pinfo->cinfo, COL_INFO, "NSP interrupt message");
944             ack_num = tvb_get_letohs(tvb, my_offset);
945             if (ack_num & 0x8000) {
946                 proto_tree_add_none_format(tree, hf_dec_rt_acknum,
947                     tvb, my_offset, 2,
948                     "Last interrupt/link service msg %s acknowledged: %d",
949                     (ack_num & 0x1000) ? "negatively" : "positively",
950                     ack_num & 0xfff);
951                 my_offset += 2;
952                 /* There may still be an ack_dat field */
953             } else {
954                 /* There are no ack/nak fields */
955                 proto_tree_add_item(tree, hf_dec_rt_segnum,
956                     tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
957                 proto_tree_add_boolean(tree, hf_dec_rt_delay,
958                     tvb, my_offset, 2, ack_num);
959                 my_offset += 2;
960                 /* We are done, return my_offset */
961                 break;
962             }
963             ack_dat = tvb_get_letohs(tvb, my_offset);
964             if (ack_dat & 0x8000) {
965                 /* There is an ack_dat field */
966                 proto_tree_add_none_format(tree, hf_dec_rt_acknum,
967                     tvb, my_offset, 2,
968                     "Cross sub-channel %s of data segment msg: %d",
969                     ((ack_dat & 0x3000) == 0x2000) ? "ACK" : "NAK",
970                    ack_dat & 0xfff);
971                 my_offset += 2;
972             }
973             seg_num = tvb_get_letohs(tvb, my_offset);
974             /* This is the last field, the rest are data */
975             proto_tree_add_item(tree, hf_dec_rt_segnum,
976                 tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
977             proto_tree_add_boolean(tree, hf_dec_rt_delay,
978                 tvb, my_offset, 2, seg_num);
979             my_offset += 2;
980             /* We are done, return my_offset */
981             break;
982         case LINK_SERVICE_MSG:     /* "Link service message" */
983             col_set_str(pinfo->cinfo, COL_INFO, "NSP link control message");
984             ack_num = tvb_get_letohs(tvb, my_offset);
985             if (ack_num & 0x8000) {
986                 proto_tree_add_none_format(tree, hf_dec_rt_acknum,
987                     tvb, my_offset, 2,
988                     "Last interrupt/link service msg %s acknowledged: %d",
989                     (ack_num & 0x1000) ? "negatively" : "positively",
990                     ack_num & 0xfff);
991                 my_offset += 2;
992                 /* There may still be an ack_dat field */
993             } else {
994                 /* There are no ack/nak fields */
995                 proto_tree_add_item(tree, hf_dec_rt_segnum,
996                     tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
997                 proto_tree_add_boolean(tree, hf_dec_rt_delay,
998                     tvb, my_offset, 2, ack_num);
999                 my_offset += 2;
1000                 /* We are done, return my_offset */
1001                 break;
1002             }
1003             ack_dat = tvb_get_letohs(tvb, my_offset);
1004             if (ack_dat & 0x8000) {
1005                 /* There is an ack_dat field */
1006                 proto_tree_add_none_format(tree, hf_dec_rt_acknum,
1007                     tvb, my_offset, 2,
1008                     "Cross sub-channel %s of data segment msg: %d",
1009                     ((ack_dat & 0x3000) == 0x2000) ? "ACK" : "NAK",
1010                    ack_dat & 0xfff);
1011                 my_offset += 2;
1012             }
1013             seg_num = tvb_get_letohs(tvb, my_offset);
1014             proto_tree_add_item(tree, hf_dec_rt_segnum,
1015                 tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
1016             proto_tree_add_boolean(tree, hf_dec_rt_delay,
1017                 tvb, my_offset, 2, seg_num);
1018             my_offset += 2;
1019             /* Now follows the ls_flags field */
1020             ls_flags = tvb_get_guint8(tvb, my_offset);
1021             switch(ls_flags) {
1022                 case 0: /* no change */
1023                     col_append_str(pinfo->cinfo, COL_INFO,
1024                        "(no change)");
1025                 break;
1026                 case 1: /* stop sending data */
1027                     col_append_str(pinfo->cinfo, COL_INFO,
1028                        "(stop)");
1029                 break;
1030                 case 2: /* send data */
1031                     col_append_str(pinfo->cinfo, COL_INFO,
1032                        "(go)");
1033                 break;
1034                 default:
1035                 break;
1036             }
1037             fc_val = tvb_get_guint8(tvb, my_offset + 1);
1038             ti = proto_tree_add_uint(tree, hf_dec_flow_control, tvb,
1039                          my_offset, 1, ls_flags);
1040             flow_control_tree =
1041                 proto_item_add_subtree(ti, ett_dec_flow_control);
1042             proto_tree_add_none_format(flow_control_tree, hf_dec_rt_fc_val,
1043                 tvb, my_offset, 2,
1044                 "Request for additional %d %s msgs",
1045                 fc_val, ((ls_flags & 0x04) ? "interrupt" : "data"));
1046             my_offset += 2;
1047             break;
1048         case DATA_ACK_MSG:         /* "Data acknowledgement message" */
1049             ack_num = tvb_get_letohs(tvb, my_offset);
1050             proto_tree_add_none_format(tree, hf_dec_rt_acknum,
1051                 tvb, my_offset, 2,
1052                 "Last data segment %s acknowledged: %d",
1053                 (ack_num & 0x1000) ? "negatively" : "positively",
1054                 ack_num & 0xfff);
1055             my_offset += 2;
1056             /* There may be an optional ack_oth field */
1057             col_append_fstr(pinfo->cinfo, COL_INFO,
1058                 "NSP data %s message(%d)",
1059                     (ack_num & 0x1000) ? "NAK" : "ACK",
1060                     ack_num & 0xfff);
1061
1062             if (tvb_length_remaining(tvb, my_offset) > 0) {
1063                 ack_oth = tvb_get_letohs(tvb, my_offset);
1064                 if (ack_oth & 0x8000) {
1065                     /* There is an ack_oth field */
1066                     proto_tree_add_none_format(tree, hf_dec_rt_acknum,
1067                         tvb, my_offset, 2,
1068                         "Cross sub-channel %s of other data msg %d",
1069                         ((ack_oth & 0x3000) == 0x2000) ? "ACK" : "NAK",
1070                         ack_oth & 0xfff);
1071                     my_offset += 2;
1072                 }
1073             }
1074             /* We are done, return my_offset */
1075             break;
1076         case OTHER_DATA_ACK_MSG:   /* "Other data acknowledgement message" */
1077             col_set_str(pinfo->cinfo, COL_INFO, "NSP other data ACK message");
1078             ack_num = tvb_get_letohs(tvb, my_offset);
1079             proto_tree_add_none_format(tree, hf_dec_rt_acknum,
1080                 tvb, my_offset, 2,
1081                 "Last interrupt/link service msg %s acknowledged: %d",
1082                 (ack_num & 0x1000) ? "negatively" : "positively",
1083                 ack_num & 0xfff);
1084             my_offset += 2;
1085             /* There may be an optional ack_dat field */
1086             if (tvb_length_remaining(tvb, my_offset) > 0) {
1087                 ack_dat = tvb_get_letohs(tvb, my_offset);
1088                 if (ack_dat & 0x8000) {
1089                     /* There is an ack_dat field */
1090                     proto_tree_add_none_format(tree, hf_dec_rt_acknum,
1091                         tvb, my_offset, 2,
1092                         "Cross sub-channel %s of data msg %d",
1093                         ((ack_dat & 0x3000) == 0x2000) ? "ACK" : "NAK",
1094                         ack_dat & 0xfff);
1095                     my_offset += 2;
1096                 }
1097             }
1098             /* We are done, return my_offset */
1099             break;
1100         case CONN_CONFIRM_MSG:     /* "Connect confirm" */
1101         case CONN_INITIATE_MSG:    /* "Connect initiate" */
1102             col_set_str(pinfo->cinfo, COL_INFO, "NSP connect confirm/initiate message");
1103             services = tvb_get_guint8(tvb, my_offset);
1104             proto_tree_add_uint(tree, hf_dec_rt_services, tvb,
1105                          my_offset, 1, services);
1106             my_offset++;
1107             info = tvb_get_guint8(tvb, my_offset);
1108             proto_tree_add_uint(tree, hf_dec_rt_info, tvb,
1109                          my_offset, 1, info);
1110             my_offset++;
1111             seg_size = tvb_get_letohs(tvb, my_offset);
1112             proto_tree_add_item(tree, hf_dec_rt_seg_size, tvb,
1113                          my_offset, 2, ENC_LITTLE_ENDIAN);
1114             my_offset += 2;
1115             my_offset =
1116                 handle_connect_contents(
1117                     tvb, tree, my_offset);
1118             break;
1119         case DISCONN_INITIATE_MSG: /* "Disconnect initiate" */
1120         case DISCONN_CONFIRM_MSG:  /* "Disconnect confirm" */
1121             col_set_str(pinfo->cinfo, COL_INFO, "NSP disconnect initiate/confirm message");
1122             reason = tvb_get_letohs(tvb, my_offset);
1123             proto_tree_add_item(tree, hf_dec_disc_reason, tvb,
1124                  my_offset, 2, ENC_LITTLE_ENDIAN);
1125             my_offset += 2;
1126             if (nsp_msg_type == DISCONN_INITIATE_MSG) {
1127                 my_offset =
1128                     handle_disc_init_contents( my_offset);
1129             }
1130             break;
1131         default:
1132             break;
1133     }
1134     return (my_offset);
1135 }
1136
1137 static int
1138 handle_connect_contents(
1139     tvbuff_t *tvb,
1140     proto_tree *tree,
1141     guint offset)
1142 {
1143     guint my_offset = offset;
1144     proto_item   *ti;
1145     proto_tree   *contents_tree;
1146     guint8       dst_format, src_format, obj_type, image_len, menu_ver;
1147     guint16      grp_code, usr_code;
1148
1149     ti = proto_tree_add_item(tree, hf_dec_conn_contents,
1150         tvb, my_offset, -1, ENC_NA);
1151     contents_tree = proto_item_add_subtree(ti, ett_dec_sess_contents);
1152     /* The destination end user */
1153     dst_format = tvb_get_guint8(tvb, my_offset);
1154     my_offset++;
1155     obj_type = tvb_get_guint8(tvb, my_offset);
1156     proto_tree_add_uint(contents_tree, hf_dec_sess_obj_type,
1157         tvb, my_offset, 1, obj_type);
1158     my_offset++;
1159     if (dst_format == 2) {
1160         grp_code = tvb_get_letohs(tvb, my_offset);
1161         proto_tree_add_item(contents_tree, hf_dec_sess_grp_code,
1162             tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
1163         my_offset += 2;
1164         usr_code = tvb_get_letohs(tvb, my_offset);
1165         proto_tree_add_item(contents_tree, hf_dec_sess_usr_code,
1166             tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
1167         my_offset += 2;
1168     }
1169     if (dst_format != 0) {
1170         /* The name field for formats 1 and 2 */
1171         image_len = tvb_get_guint8(tvb, my_offset);
1172         my_offset++;
1173         proto_tree_add_item(contents_tree, hf_dec_sess_dst_name,
1174             tvb, my_offset, image_len, ENC_ASCII|ENC_NA);
1175         my_offset += image_len;
1176     }
1177     /* The source end user */
1178     src_format = tvb_get_guint8(tvb, my_offset);
1179     my_offset++;
1180     obj_type = tvb_get_guint8(tvb, my_offset);
1181     proto_tree_add_uint(contents_tree, hf_dec_sess_obj_type,
1182         tvb, my_offset, 1, obj_type);
1183     my_offset++;
1184     if (src_format == 2) {
1185         grp_code = tvb_get_letohs(tvb, my_offset);
1186         proto_tree_add_item(contents_tree, hf_dec_sess_grp_code,
1187             tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
1188         my_offset += 2;
1189         usr_code = tvb_get_letohs(tvb, my_offset);
1190         proto_tree_add_item(contents_tree, hf_dec_sess_usr_code,
1191             tvb, my_offset, 2, ENC_LITTLE_ENDIAN);
1192         my_offset += 2;
1193     }
1194     if (dst_format != 0) {
1195         /* The name field for formats 1 and 2 */
1196         image_len = tvb_get_guint8(tvb, my_offset);
1197         my_offset++;
1198         proto_tree_add_item(contents_tree, hf_dec_sess_src_name,
1199             tvb, my_offset, image_len, ENC_ASCII|ENC_NA);
1200         my_offset += image_len;
1201     }
1202     /* Now the MENUVER field */
1203     menu_ver = tvb_get_guint8(tvb, my_offset);
1204     switch (menu_ver) {
1205         case 1:
1206         case 3:
1207             proto_tree_add_string(contents_tree, hf_dec_sess_menu_ver,
1208                 tvb, my_offset, 1,
1209                 "Version 1.0: RQSTRID, PASSWRD and ACCOUNT fields included");
1210             my_offset++;
1211             image_len = tvb_get_guint8(tvb, my_offset);
1212             my_offset++;
1213             proto_tree_add_item(contents_tree, hf_dec_sess_rqstr_id,
1214                 tvb, my_offset, image_len, ENC_ASCII|ENC_NA);
1215             my_offset += image_len;
1216             image_len = tvb_get_guint8(tvb, my_offset);
1217             my_offset++;
1218             proto_tree_add_item(contents_tree, hf_dec_sess_rqstr_id,
1219                 tvb, my_offset, image_len, ENC_ASCII|ENC_NA);
1220             my_offset += image_len;
1221             image_len = tvb_get_guint8(tvb, my_offset);
1222             my_offset++;
1223             proto_tree_add_item(contents_tree, hf_dec_sess_rqstr_id,
1224                 tvb, my_offset, image_len, ENC_ASCII|ENC_NA);
1225             my_offset += image_len;
1226
1227
1228             break;
1229         case 2:
1230             /* A USRDATA field is handled by dissect_data */
1231             proto_tree_add_string(contents_tree, hf_dec_sess_menu_ver,
1232                 tvb, my_offset, 1,
1233                 "Version 1.0: USRDATA field included");
1234             break;
1235         default:
1236             proto_tree_add_string(contents_tree, hf_dec_sess_menu_ver,
1237                 tvb, my_offset, 1,
1238                 "Session control version 1.0");
1239             break;
1240     }
1241     return (my_offset);
1242 }
1243
1244 static int
1245 handle_disc_init_contents(
1246     guint offset)
1247 {
1248     guint my_offset = offset;
1249
1250     return (my_offset);
1251 }
1252
1253
1254 void
1255 proto_register_dec_rt(void)
1256 {
1257
1258     static hf_register_info hf[] = {
1259         /* Mesage header items */
1260         { &hf_dec_routing_flags,
1261           { "Routing flags",            "dec_dna.flags",
1262             FT_UINT8,    BASE_HEX,    NULL,    0x0,
1263             "DNA routing flag", HFILL }},
1264         { &hf_dec_rt_ctrl_msg,
1265           { "Control packet",            "dec_dna.flags.control",
1266             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    RT_FLAGS_CTRL_MSG,
1267             NULL, HFILL }},
1268         { &hf_dec_rt_long_msg,
1269           { "Long data packet format",     "dec_dna.flags.msglen",
1270             FT_UINT8,    BASE_HEX,    NULL, 0x06,
1271             "Long message indicator", HFILL }},
1272         { &hf_dec_rt_short_msg,
1273           { "Short data packet format",     "dec_dna.flags.msglen",
1274             FT_UINT8,    BASE_HEX,    NULL, 0x06,
1275             "Short message indicator", HFILL }},
1276         { &hf_dec_rt_rqr,
1277           { "Return to Sender Request",    "dec_dna.flags.RQR",
1278             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    RT_FLAGS_RQR,
1279             "Return to Sender", HFILL }},
1280         { &hf_dec_rt_rts,
1281           { "Packet on return trip",    "dec_dna.flags.RTS",
1282             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    RT_FLAGS_RTS,
1283             NULL, HFILL }},
1284         { &hf_dec_rt_inter_eth,
1285           { "Intra-ethernet packet",    "dec_dna.flags.intra_eth",
1286             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    RT_FLAGS_INTRA_ETHER,
1287             NULL, HFILL }},
1288         { &hf_dec_rt_discard,
1289           { "Discarded packet",            "dec_dna.flags.discard",
1290             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    RT_FLAGS_DISCARD,
1291             NULL, HFILL }},
1292         { &hf_dec_rt_dst_addr,
1293           { "Destination Address",        "dec_dna.dst.address",
1294             FT_ETHER,    BASE_NONE,    NULL,    0x0,
1295             NULL, HFILL }},
1296         { &hf_dec_rt_src_addr,
1297           { "Source Address",            "dec_dna.src.addr",
1298             FT_ETHER,    BASE_NONE,    NULL,    0x0,
1299             NULL, HFILL }},
1300         { &hf_dec_rt_nl2,
1301           { "Next level 2 router",        "dec_dna.nl2",
1302             FT_UINT8,    BASE_HEX,    NULL,   0x0,
1303             "reserved", HFILL }},
1304         { &hf_dec_rt_service_class,
1305           { "Service class",            "dec_dna.svc_cls",
1306             FT_UINT8,    BASE_HEX,    NULL,   0x0,
1307             "reserved", HFILL }},
1308         { &hf_dec_rt_protocol_type,
1309           { "Protocol type",            "dec_dna.proto_type",
1310             FT_UINT8,    BASE_HEX,    NULL,   0x0,
1311             "reserved", HFILL }},
1312         { &hf_dec_rt_visit_count,
1313           { "Visit count",            "dec_dna.visit_cnt",
1314             FT_UINT8,    BASE_HEX,    NULL,   0x0,
1315             NULL, HFILL }},
1316         { &hf_dec_flow_control,
1317           { "Flow control",            "dec_dna.nsp.flow_control",
1318             FT_UINT8,    BASE_HEX,    VALS(rt_flow_control_vals),   0x3,
1319             "Flow control(stop, go)", HFILL }},
1320         { &hf_dec_rt_services,
1321           { "Requested services",   "dec_dna.nsp.services",
1322             FT_UINT8,    BASE_HEX,    VALS(rt_services_vals),   0x0c,
1323             "Services requested", HFILL }},
1324         { &hf_dec_rt_info,
1325           { "Version info",            "dec_dna.nsp.info",
1326             FT_UINT8,    BASE_HEX,    VALS(rt_info_version_vals),   0x03,
1327             NULL, HFILL }},
1328         { &hf_dec_rt_dst_node,
1329           { "Destination node",            "dec_dna.dst_node",
1330             FT_UINT16,    BASE_HEX,    NULL,   0x0,
1331             NULL, HFILL }},
1332         { &hf_dec_rt_seg_size,
1333           { "Maximum data segment size", "dec_dna.nsp.segsize",
1334             FT_UINT16,    BASE_DEC,    NULL,   0x0,
1335             "Max. segment size", HFILL }},
1336         { &hf_dec_rt_src_node,
1337           { "Source node",            "dec_dna.src_node",
1338             FT_UINT16,    BASE_HEX,    NULL,   0x0,
1339             NULL, HFILL }},
1340         { &hf_dec_rt_segnum,
1341           { "Message number",        "dec_dna.nsp.segnum",
1342             FT_UINT16,    BASE_DEC,    NULL,   0xfff,
1343             "Segment number", HFILL }},
1344         { &hf_dec_rt_delay,
1345           { "Delayed ACK allowed",  "dec_dna.nsp.delay",
1346             FT_BOOLEAN,    16,        TFS(&tfs_yes_no),    0x1000,
1347             "Delayed ACK allowed?", HFILL }},
1348         { &hf_dec_rt_visited_nodes,
1349           { "Nodes visited ty this package", "dec_dna.vst_node",
1350             FT_UINT8,    BASE_DEC,    NULL,   0x0,
1351             "Nodes visited", HFILL }},
1352         /* Control messsage items */
1353         { &hf_dec_ctl_msgs,
1354           { "Routing control message",        "dec_dna.rt.msg_type",
1355             FT_UINT8,    BASE_HEX,    VALS(rt_msg_type_vals),    0xe,
1356             "Routing control", HFILL }},
1357         { &hf_dec_ctl_msg_hdr,
1358           { "Routing control message",    "dec_dna.rt.msg_type",
1359             FT_UINT8,    BASE_HEX,    VALS(rt_msg_type_vals),    0xe,
1360             "Routing control", HFILL }},
1361         { &hf_dec_nsp_msgs,
1362           { "DNA NSP message",        "dec_dna.nsp.msg_type",
1363             FT_UINT8,    BASE_HEX,    VALS(nsp_msg_type_vals),    0x0,
1364             "NSP message", HFILL }},
1365         { &hf_dec_rt_acknum,
1366           { "Ack/Nak",                "dec_dna.ctl.acknum",
1367             FT_NONE,    BASE_NONE,    NULL,    0x0,
1368             "ack/nak number", HFILL }},
1369         { &hf_dec_rt_fc_val,
1370           { "Flow control",            "dec_dna.nsp.fc_val",
1371             FT_NONE,    BASE_NONE,    NULL,    0x0,
1372             NULL, HFILL }},
1373         { &hf_dec_rt_tiinfo,
1374           { "Routing information",    "dec_dna.ctl.tiinfo",
1375             FT_UINT8,    BASE_HEX,    VALS(rt_tiinfo_vals), 0x0,
1376             NULL, HFILL }},
1377         { &hf_dec_rt_blk_size,
1378           { "Block size",            "dec_dna.ctl.blk_size",
1379             FT_UINT16,    BASE_DEC,    NULL,    0x0,
1380             NULL, HFILL }},
1381         { &hf_dec_disc_reason,
1382           { "Reason for disconnect","dec_dna.nsp.disc_reason",
1383             FT_UINT16,    BASE_HEX,    VALS(rt_disc_reason_vals),    0x0,
1384             "Disconnect reason", HFILL }},
1385         { &hf_dec_rt_version,
1386           { "Version",                "dec_dna.ctl.version",
1387             FT_NONE,    BASE_NONE,    NULL,    0x0,
1388             "Control protocol version", HFILL }},
1389         { &hf_dec_rt_timer,
1390           { "Hello timer(seconds)",  "dec_dna.ctl.timer",
1391             FT_UINT16,    BASE_DEC,    NULL,   0x0,
1392             "Hello timer in seconds", HFILL }},
1393         { &hf_dec_rt_reserved,
1394           { "Reserved", "dec_dna.ctl.reserved",
1395             FT_BYTES, BASE_NONE, NULL, 0x0,
1396             NULL, HFILL }},
1397         { &hf_dec_rt_fcnval,
1398           { "Verification message function value", "dec_dna.ctl.fcnval",
1399             FT_BYTES, BASE_NONE, NULL, 0x0,
1400             "Routing Verification function", HFILL }},
1401         { &hf_dec_rt_test_data,
1402           { "Test message data", "dec_dna.ctl.test_data",
1403             FT_BYTES, BASE_NONE, NULL, 0x0,
1404             "Routing Test message data", HFILL }},
1405         { &hf_dec_rt_segment,
1406           { "Segment",                "dec_dna.ctl.segment",
1407             FT_NONE,    BASE_NONE,    NULL,    0x0,
1408             "Routing Segment", HFILL }},
1409         { &hf_dec_rt_id,
1410           { "Transmitting system ID",            "dec_dna.ctl.id",
1411             FT_ETHER,    BASE_NONE,    NULL,    0x0,
1412             NULL, HFILL }},
1413         { &hf_dec_rt_iinfo,
1414           { "Routing information",        "dec_dna.ctl.tiinfo",
1415             FT_UINT8,    BASE_HEX,    NULL, 0x0,
1416             NULL, HFILL }},
1417         { &hf_dec_rt_iinfo_node_type,
1418           { "Node type",            "dec_dna.ctl.iinfo.node_type",
1419             FT_UINT8,    BASE_HEX,    VALS(rt_iinfo_node_type_vals),    0x03,
1420             NULL, HFILL }},
1421         { &hf_dec_rt_iinfo_vrf,
1422           { "Verification required",            "dec_dna.ctl.iinfo.vrf",
1423             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    0x4,
1424             "Verification required?", HFILL }},
1425         { &hf_dec_rt_iinfo_rej,
1426           { "Rejected",            "dec_dna.ctl.iinfo.rej",
1427             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    0x8,
1428             "Rejected message", HFILL }},
1429         { &hf_dec_rt_iinfo_verf,
1430           { "Verification failed",            "dec_dna.ctl.iinfo.verf",
1431             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    0x10,
1432             "Verification failed?", HFILL }},
1433         { &hf_dec_rt_iinfo_mta,
1434           { "Accepts multicast traffic",            "dec_dna.ctl.iinfo.mta",
1435             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    0x20,
1436             "Accepts multicast traffic?", HFILL }},
1437         { &hf_dec_rt_iinfo_blkreq,
1438           { "Blocking requested",            "dec_dna.ctl.iinfo.blkreq",
1439             FT_BOOLEAN,    8,        TFS(&tfs_yes_no),    0x40,
1440             "Blocking requested?", HFILL }},
1441         { &hf_dec_rt_iprio,
1442           { "Routing priority",        "dec_dna.ctl.prio",
1443             FT_UINT8,    BASE_HEX,    NULL, 0x0,
1444             NULL, HFILL }},
1445         { &hf_dec_rt_neighbor,
1446           { "Neighbor",                "dec_dna.ctl_neighbor",
1447             FT_ETHER,    BASE_NONE,    NULL,    0x0,
1448             "Neighbour ID", HFILL }},
1449         { &hf_dec_rt_seed,
1450           { "Verification seed",    "dec_dna.ctl.seed",
1451             FT_BYTES,    BASE_NONE,    NULL, 0x0,
1452             NULL, HFILL }},
1453         { &hf_dec_rt_elist,
1454           { "List of router states",    "dec_dna.ctl.elist",
1455             FT_NONE,    BASE_NONE,    NULL, 0x0,
1456             "Router states", HFILL }},
1457         { &hf_dec_rt_ename,
1458           { "Ethernet name",      "dec_dna.ctl.ename",
1459             FT_BYTES,    BASE_NONE,    NULL,    0x0,
1460             NULL, HFILL }},
1461         { &hf_dec_rt_router_id,
1462           { "Router ID",                "dec_dna.ctl.router_id",
1463             FT_ETHER,    BASE_NONE,    NULL,    0x0,
1464             NULL, HFILL }},
1465         { &hf_dec_rt_router_state,
1466           { "Router state",    "dec_dna.ctl.router_state",
1467             FT_STRING,    BASE_NONE,    NULL, 0x0,
1468             NULL, HFILL }},
1469         { &hf_dec_conn_contents,
1470           { "Session connect data",    "dec_dna.sess.conn",
1471             FT_NONE,    BASE_NONE,    NULL, 0x0,
1472             NULL, HFILL }},
1473         { &hf_dec_rt_router_prio,
1474           { "Router priority",    "dec_dna.ctl.router_prio",
1475             FT_UINT8,    BASE_HEX,    NULL, 0x7f,
1476             NULL, HFILL }},
1477         { &hf_dec_sess_grp_code,
1478           { "Session Group code",    "dec_dna.sess.grp_code",
1479             FT_UINT16,    BASE_HEX,    NULL, 0x0,
1480             NULL, HFILL }},
1481         { &hf_dec_sess_usr_code,
1482           { "Session User code",    "dec_dna.sess.usr_code",
1483             FT_UINT16,    BASE_HEX,    NULL, 0x0,
1484             NULL, HFILL }},
1485         { &hf_dec_sess_dst_name,
1486           { "Session Destination end user",    "dec_dna.sess.dst_name",
1487             FT_STRING,    BASE_NONE,    NULL, 0x0,
1488             NULL, HFILL }},
1489         { &hf_dec_sess_src_name,
1490           { "Session Source end user",    "dec_dna.sess.src_name",
1491             FT_STRING,    BASE_NONE,    NULL, 0x0,
1492             NULL, HFILL }},
1493         { &hf_dec_sess_obj_type,
1494           { "Session Object type",    "dec_dna.sess.obj_type",
1495             FT_UINT8,    BASE_HEX,    NULL, 0x0,
1496             NULL, HFILL }},
1497         { &hf_dec_sess_menu_ver,
1498           { "Session Menu version",    "dec_dna.sess.menu_ver",
1499             FT_STRING,    BASE_NONE,    NULL, 0x0,
1500             NULL, HFILL }},
1501         { &hf_dec_sess_rqstr_id,
1502           { "Session Requestor ID",    "dec_dna.sess.rqstr_id",
1503             FT_STRING,    BASE_NONE,    NULL, 0x0,
1504             NULL, HFILL }},
1505
1506
1507     };
1508     static gint *ett[] = {
1509         &ett_dec_rt,
1510         &ett_dec_routing_flags,
1511         &ett_dec_msg_flags,
1512         &ett_dec_rt_ctl_msg,
1513         &ett_dec_rt_nsp_msg,
1514         &ett_dec_rt_info_flags,
1515         &ett_dec_rt_list,
1516         &ett_dec_rt_rlist,
1517         &ett_dec_rt_state,
1518         &ett_dec_flow_control,
1519         &ett_dec_sess_contents,
1520     };
1521
1522     proto_dec_rt = proto_register_protocol("DEC DNA Routing Protocol",
1523                                            "DEC_DNA", "dec_dna");
1524     proto_register_field_array(proto_dec_rt, hf, array_length(hf));
1525     proto_register_subtree_array(ett, array_length(ett));
1526 }
1527
1528 void
1529 proto_reg_handoff_dec_rt(void)
1530 {
1531     dissector_handle_t dec_rt_handle;
1532
1533     dec_rt_handle = create_dissector_handle(dissect_dec_rt,
1534                                             proto_dec_rt);
1535     dissector_add_uint("ethertype", ETHERTYPE_DNA_RT, dec_rt_handle);
1536     dissector_add_uint("chdlctype", ETHERTYPE_DNA_RT, dec_rt_handle);
1537     dissector_add_uint("ppp.protocol", PPP_DEC4, dec_rt_handle);
1538 /*  dissector_add_uint("ppp.protocol", PPP_DECNETCP, dec_rt_handle);*/
1539 }