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