Revert "Fixup: tvb_* -> tvb_captured"
[metze/wireshark/wip.git] / epan / dissectors / packet-dvmrp.c
1 /* packet-dvmrp.c   2001 Ronnie Sahlberg <See AUTHORS for email>
2  * Routines for IGMP/DVMRP packet disassembly
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 /*
23
24
25                         DVMRP   DVMRP
26         code            v1      v3
27
28         0x01            *       *
29         0x02            *       *
30         0x03            x
31         0x04            x
32         0x07                    x
33         0x08                    x
34         0x09                    x
35
36
37         * V3 has len>=8 and byte[6]==0xff and byte[7]==0x03
38
39
40         DVMRP is defined in the following RFCs
41         RFC1075 Version 1
42         draft-ietf-idmr-dvmrp-v3-10.txt Version 3
43
44         V1 and V3 can be distinguished by looking at bytes 6 and 7 in the
45         IGMP/DVMRP header.
46         If header[6]==0xff and header[7]==0x03 we have version 3.
47
48
49         RFC1075 has typos in 3.12.2 and 3.12.4, see if you can spot them.
50 */
51
52 #include "config.h"
53
54 #include <glib.h>
55
56 #include <epan/packet.h>
57 #include <epan/ipproto.h>
58 #include <epan/prefs.h>
59 #include "packet-igmp.h"
60 #include "packet-dvmrp.h"
61
62 void proto_register_dvmrp(void);
63
64 static int proto_dvmrp = -1;
65 static int hf_version = -1;
66 static int hf_type = -1;
67 static int hf_code_v1 = -1;
68 static int hf_checksum = -1;
69 static int hf_checksum_bad = -1;
70 static int hf_commands = -1;
71 static int hf_command = -1;
72 static int hf_count = -1;
73 static int hf_afi = -1;
74 static int hf_netmask = -1;
75 static int hf_metric = -1;
76 static int hf_dest_unr = -1;
77 static int hf_split_horiz = -1;
78 static int hf_infinity = -1;
79 static int hf_daddr = -1;
80 static int hf_maddr = -1;
81 static int hf_hold = -1;
82 static int hf_code_v3 = -1;
83 static int hf_capabilities = -1;
84 static int hf_cap_leaf = -1;
85 static int hf_cap_prune = -1;
86 static int hf_cap_genid = -1;
87 static int hf_cap_mtrace = -1;
88 static int hf_cap_snmp = -1;
89 static int hf_cap_netmask = -1;
90 static int hf_min_ver = -1;
91 static int hf_maj_ver = -1;
92 static int hf_genid = -1;
93 static int hf_route = -1;
94 static int hf_saddr = -1;
95 static int hf_life = -1;
96 static int hf_local = -1;
97 static int hf_threshold = -1;
98 static int hf_flags = -1;
99 static int hf_flag_tunnel = -1;
100 static int hf_flag_srcroute = -1;
101 static int hf_flag_down = -1;
102 static int hf_flag_disabled = -1;
103 static int hf_flag_querier = -1;
104 static int hf_flag_leaf = -1;
105 static int hf_ncount = -1;
106 static int hf_neighbor = -1;
107
108 static int ett_dvmrp = -1;
109 static int ett_commands = -1;
110 static int ett_capabilities = -1;
111 static int ett_flags = -1;
112 static int ett_route = -1;
113
114 static int strict_v3 = FALSE;
115
116 #define DVMRP_TYPE                              0x13
117 static const value_string dvmrp_type[] = {
118         {DVMRP_TYPE,    "DVMRP" },
119         {0,             NULL}
120 };
121
122 #define DVMRP_V1_RESPONSE                       1
123 #define DVMRP_V1_REQUEST                        2
124 #define DVMRP_V1_NON_MEMBERSHIP_REPORT          3
125 #define DVMRP_V1_NON_MEMBERSHIP_CANCELLATION    4
126 static const value_string code_v1[] = {
127         {DVMRP_V1_RESPONSE,                     "Response"                      },
128         {DVMRP_V1_REQUEST,                      "Request"                       },
129         {DVMRP_V1_NON_MEMBERSHIP_REPORT,        "Non-membership report"         },
130         {DVMRP_V1_NON_MEMBERSHIP_CANCELLATION,  "Non-membership cancellation"   },
131         {0,                                     NULL}
132 };
133
134 #define DVMRP_V3_PROBE                          0x1
135 #define DVMRP_V3_REPORT                         0x2
136 #define DVMRP_V3_ASK_NEIGHBORS                  0x3
137 #define DVMRP_V3_NEIGHBORS                      0x4
138 #define DVMRP_V3_ASK_NEIGHBORS_2                0x5
139 #define DVMRP_V3_NEIGHBORS_2                    0x6
140 #define DVMRP_V3_PRUNE                          0x7
141 #define DVMRP_V3_GRAFT                          0x8
142 #define DVMRP_V3_GRAFT_ACK                      0x9
143 static const value_string code_v3[] = {
144         {DVMRP_V3_PROBE,                "Probe"},
145         {DVMRP_V3_REPORT,               "Report"},
146         {DVMRP_V3_ASK_NEIGHBORS,        "Ask Neighbors"},
147         {DVMRP_V3_NEIGHBORS,            "Neighbors"},
148         {DVMRP_V3_ASK_NEIGHBORS_2,      "Ask Neighbors 2"},
149         {DVMRP_V3_NEIGHBORS_2,          "Neighbors 2"},
150         {DVMRP_V3_PRUNE,                "Prune"},
151         {DVMRP_V3_GRAFT,                "Graft"},
152         {DVMRP_V3_GRAFT_ACK,            "Graft ACK"},
153         {0,                             NULL}
154 };
155
156 #define DVMRP_V3_CAP_LEAF       0x01
157 #define DVMRP_V3_CAP_PRUNE      0x02
158 #define DVMRP_V3_CAP_GENID      0x04
159 #define DVMRP_V3_CAP_MTRACE     0x08
160 #define DVMRP_V3_CAP_SNMP       0x10
161 #define DVMRP_V3_CAP_NETMASK    0x20
162
163 #define DVMRP_V3_FLAG_TUNNEL    0x01
164 #define DVMRP_V3_FLAG_SRCROUTE  0x02
165 #define DVMRP_V3_FLAG_DOWN      0x10
166 #define DVMRP_V3_FLAG_DISABLED  0x20
167 #define DVMRP_V3_FLAG_QUERIER   0x40
168 #define DVMRP_V3_FLAG_LEAF      0x80
169
170
171 #define V1_COMMAND_NULL         0
172 #define V1_COMMAND_AFI          2
173 #define V1_COMMAND_SUBNETMASK   3
174 #define V1_COMMAND_METRIC       4
175 #define V1_COMMAND_FLAGS0       5
176 #define V1_COMMAND_INFINITY     6
177 #define V1_COMMAND_DA           7
178 #define V1_COMMAND_RDA          8
179 #define V1_COMMAND_NMR          9
180 #define V1_COMMAND_NMR_CANCEL   10
181 static const value_string command[] = {
182         {V1_COMMAND_NULL,       "NULL"  },
183         {V1_COMMAND_AFI,        "Address Family Indicator"},
184         {V1_COMMAND_SUBNETMASK, "Subnetmask"},
185         {V1_COMMAND_METRIC,     "Metric"},
186         {V1_COMMAND_FLAGS0,     "Flags0"},
187         {V1_COMMAND_INFINITY,   "Infinity"},
188         {V1_COMMAND_DA,         "Destination Address"},
189         {V1_COMMAND_RDA,        "Requested Destination Address"},
190         {V1_COMMAND_NMR,        "Non-Membership Report"},
191         {V1_COMMAND_NMR_CANCEL, "Non-Membership Report Cancel"},
192         {0,                     NULL}
193 };
194
195 #define V1_AFI_IP               2
196 static const value_string afi[] = {
197         {V1_AFI_IP,     "IP v4 Family"},
198         {0,             NULL}
199 };
200
201 static const true_false_string tfs_dest_unreach = {
202         "Destination Unreachable",
203         "NOT Destination Unreachable"
204 };
205
206 static const true_false_string tfs_split_horiz = {
207         "Split Horizon concealed route",
208         "NOT Split Horizon concealed route"
209 };
210
211 static const true_false_string tfs_cap_leaf = {
212         "Leaf",
213         "NOT Leaf"
214 };
215 static const true_false_string tfs_cap_prune = {
216         "Prune capable",
217         "NOT Prune capable"
218 };
219 static const true_false_string tfs_cap_genid = {
220         "Genid capable",
221         "NOT Genid capable"
222 };
223 static const true_false_string tfs_cap_mtrace = {
224         "Multicast Traceroute capable",
225         "NOT Multicast Traceroute capable"
226 };
227 static const true_false_string tfs_cap_snmp = {
228         "SNMP capable",
229         "NOT SNMP capable"
230 };
231 static const true_false_string tfs_cap_netmask = {
232         "Netmask capable",
233         "NOT Netmask capable"
234 };
235
236 static int
237 dissect_v3_report(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
238 {
239         guint8 m0,m1,m2,m3;
240         guint8 s0,s1,s2,s3;
241         guint8 metric;
242         guint32 ip;
243
244         while (tvb_reported_length_remaining(tvb, offset) > 0) {
245                 proto_tree *tree;
246                 proto_item *item;
247                 int old_offset_a = offset;
248
249                 item = proto_tree_add_item(parent_tree, hf_route,
250                                 tvb, offset, -1, ENC_NA);
251                 tree = proto_item_add_subtree(item, ett_route);
252
253                 m0 = 0xff;
254                 /* read the mask */
255                 m1 = tvb_get_guint8(tvb, offset);
256                 m2 = tvb_get_guint8(tvb, offset+1);
257                 m3 = tvb_get_guint8(tvb, offset+2);
258
259                 ip = m3;
260                 ip = (ip<<8)|m2;
261                 ip = (ip<<8)|m1;
262                 ip = (ip<<8)|m0;
263                 proto_tree_add_ipv4(tree, hf_netmask, tvb, offset, 3, ip);
264
265                 offset += 3;
266
267                 /* read every srcnet, metric  pairs */
268                 do {
269                         int old_offset_b = offset;
270                         m0 = 0xff;
271
272                         s1 = 0;
273                         s2 = 0;
274                         s3 = 0;
275
276                         s0 = tvb_get_guint8(tvb, offset);
277                         offset += 1;
278                         if (m1) {
279                                 s1 = tvb_get_guint8(tvb, offset);
280                                 offset += 1;
281                         }
282                         if (m2) {
283                                 s2 = tvb_get_guint8(tvb, offset);
284                                 offset += 1;
285                         }
286                         if (m3) {
287                                 s3 = tvb_get_guint8(tvb, offset);
288                                 offset += 1;
289                         }
290
291                         /* handle special case for default route V3/3.4.3 */
292                         if ((!m1)&&(!m2)&&(!m3)&&(!s0)) {
293                                 m0 = 0;
294                         }
295
296                         ip = s3;
297                         ip = (ip<<8)|s2;
298                         ip = (ip<<8)|s1;
299                         ip = (ip<<8)|s0;
300                         proto_tree_add_ipv4_format(tree, hf_saddr, tvb,
301                                 old_offset_b, offset-old_offset_b, ip,
302                                 "%s %d.%d.%d.%d (netmask %d.%d.%d.%d)",
303                                 m0?"Source Network":"Default Route",
304                                 s0,s1,s2,s3,m0,m1,m2,m3);
305
306                         metric = tvb_get_guint8(tvb, offset);
307                         proto_tree_add_uint(tree, hf_metric, tvb,
308                                 offset, 1, metric&0x7f);
309                         offset += 1;
310
311
312                 } while (!(metric&0x80));
313
314                 proto_item_set_len(item, offset-old_offset_a);
315         }
316
317         return offset;
318 }
319
320 static int
321 dissect_dvmrp_v3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
322 {
323         guint8 code,count;
324
325         /* version */
326         proto_tree_add_uint(parent_tree, hf_version, tvb, 0, 0, 3);
327
328         /* type of command */
329         proto_tree_add_uint(parent_tree, hf_type, tvb, offset, 1, 0x13);
330         offset += 1;
331
332         /* code */
333         code = tvb_get_guint8(tvb, offset);
334         proto_tree_add_uint(parent_tree, hf_code_v3, tvb, offset, 1, code);
335         offset += 1;
336         col_add_fstr(pinfo->cinfo, COL_INFO,
337                         "V%d %s",3 ,val_to_str(code, code_v3,
338                                 "Unknown Type:0x%02x"));
339
340         /* checksum */
341         igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
342         offset += 2;
343
344         /* skip unused byte */
345         offset += 1;
346
347         /* PROBE and NEIGHBORS 2 packets have capabilities flags, unused
348            for other packets */
349         if (code==DVMRP_V3_PROBE || code==DVMRP_V3_NEIGHBORS_2) {
350                 proto_tree *tree;
351                 proto_item *item;
352
353                 item = proto_tree_add_item(parent_tree, hf_capabilities,
354                                 tvb, offset, 1, ENC_NA);
355                 tree = proto_item_add_subtree(item, ett_capabilities);
356
357                 count = tvb_get_guint8(tvb, offset);
358                 proto_tree_add_boolean(tree, hf_cap_netmask, tvb, offset, 1, count);
359                 proto_tree_add_boolean(tree, hf_cap_snmp, tvb, offset, 1, count);
360                 proto_tree_add_boolean(tree, hf_cap_mtrace, tvb, offset, 1, count);
361                 proto_tree_add_boolean(tree, hf_cap_genid, tvb, offset, 1, count);
362                 proto_tree_add_boolean(tree, hf_cap_prune, tvb, offset, 1, count);
363                 proto_tree_add_boolean(tree, hf_cap_leaf, tvb, offset, 1, count);
364         }
365         offset += 1;
366
367         /* minor version */
368         proto_tree_add_item(parent_tree, hf_min_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
369         offset += 1;
370
371         /* major version */
372         proto_tree_add_item(parent_tree, hf_maj_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
373         offset += 1;
374
375         switch (code) {
376         case DVMRP_V3_PROBE:
377                 /* generation id */
378                 proto_tree_add_item(parent_tree, hf_genid, tvb,
379                         offset, 4, ENC_BIG_ENDIAN);
380                 offset += 4;
381                 while (tvb_reported_length_remaining(tvb, offset)>=4) {
382                         proto_tree_add_item(parent_tree, hf_neighbor,
383                                 tvb, offset, 4, ENC_BIG_ENDIAN);
384                         offset += 4;
385                 }
386                 break;
387         case DVMRP_V3_REPORT:
388                 offset = dissect_v3_report(tvb, parent_tree, offset);
389                 break;
390         case DVMRP_V3_PRUNE:
391                 /* source address */
392                 proto_tree_add_item(parent_tree, hf_saddr,
393                         tvb, offset, 4, ENC_BIG_ENDIAN);
394                 offset += 4;
395                 /* group address */
396                 proto_tree_add_item(parent_tree, hf_maddr,
397                         tvb, offset, 4, ENC_BIG_ENDIAN);
398                 offset += 4;
399                 /* prune lifetime */
400                 proto_tree_add_item(parent_tree, hf_life,
401                         tvb, offset, 4, ENC_BIG_ENDIAN);
402                 offset += 4;
403                 /* source netmask */
404                 if (tvb_reported_length_remaining(tvb, offset)>=4) {
405                         proto_tree_add_item(parent_tree, hf_netmask,
406                                 tvb, offset, 4, ENC_BIG_ENDIAN);
407                         offset += 4;
408                 }
409                 break;
410         case DVMRP_V3_GRAFT:
411                 /* source address */
412                 proto_tree_add_item(parent_tree, hf_saddr,
413                         tvb, offset, 4, ENC_BIG_ENDIAN);
414                 offset += 4;
415                 /* group address */
416                 proto_tree_add_item(parent_tree, hf_maddr,
417                         tvb, offset, 4, ENC_BIG_ENDIAN);
418                 offset += 4;
419                 /* source netmask */
420                 if (tvb_reported_length_remaining(tvb, offset)>=4) {
421                         proto_tree_add_item(parent_tree, hf_netmask,
422                                 tvb, offset, 4, ENC_BIG_ENDIAN);
423                         offset += 4;
424                 }
425                 break;
426         case DVMRP_V3_GRAFT_ACK:
427                 /* source address */
428                 proto_tree_add_item(parent_tree, hf_saddr,
429                         tvb, offset, 4, ENC_BIG_ENDIAN);
430                 offset += 4;
431                 /* group address */
432                 proto_tree_add_item(parent_tree, hf_maddr,
433                         tvb, offset, 4, ENC_BIG_ENDIAN);
434                 offset += 4;
435                 /* source netmask */
436                 if (tvb_reported_length_remaining(tvb, offset)>=4) {
437                         proto_tree_add_item(parent_tree, hf_netmask,
438                                 tvb, offset, 4, ENC_BIG_ENDIAN);
439                         offset += 4;
440                 }
441                 break;
442         case DVMRP_V3_ASK_NEIGHBORS:
443         case DVMRP_V3_NEIGHBORS:
444                 /* XXX - obsolete, and the draft doesn't describe them */
445                 break;
446         case DVMRP_V3_ASK_NEIGHBORS_2:
447                 /* No data */
448                 break;
449         case DVMRP_V3_NEIGHBORS_2:
450                 while (tvb_reported_length_remaining(tvb, offset)>=12) {
451                         guint8 neighbor_count;
452
453                         /* local address */
454                         proto_tree_add_item(parent_tree, hf_local,
455                                 tvb, offset, 4, ENC_BIG_ENDIAN);
456                         offset += 4;
457                         /* Metric */
458                         proto_tree_add_item(parent_tree, hf_metric,
459                                 tvb, offset, 1, ENC_BIG_ENDIAN);
460                         offset += 1;
461                         /* Threshold */
462                         proto_tree_add_item(parent_tree, hf_threshold,
463                                 tvb, offset, 1, ENC_BIG_ENDIAN);
464                         offset += 1;
465                         /* Flags */
466                         {
467                                 proto_tree *tree;
468                                 proto_item *item;
469
470                                 item = proto_tree_add_item(parent_tree, hf_flags,
471                                         tvb, offset, 1, ENC_NA);
472                                 tree = proto_item_add_subtree(item, ett_flags);
473
474                                 proto_tree_add_item(tree, hf_flag_tunnel, tvb,
475                                         offset, 1, ENC_BIG_ENDIAN);
476                                 proto_tree_add_item(tree, hf_flag_srcroute, tvb,
477                                         offset, 1, ENC_BIG_ENDIAN);
478                                 proto_tree_add_item(tree, hf_flag_down, tvb,
479                                         offset, 1, ENC_BIG_ENDIAN);
480                                 proto_tree_add_item(tree, hf_flag_disabled, tvb,
481                                         offset, 1, ENC_BIG_ENDIAN);
482                                 proto_tree_add_item(tree, hf_flag_querier, tvb,
483                                         offset, 1, ENC_BIG_ENDIAN);
484                                 proto_tree_add_item(tree, hf_flag_leaf, tvb,
485                                         offset, 1, ENC_BIG_ENDIAN);
486                         }
487                         offset += 1;
488                         /* Neighbor count */
489                         neighbor_count = tvb_get_guint8(tvb, offset);
490                         proto_tree_add_item(parent_tree, hf_ncount,
491                                 tvb, offset, 1, ENC_BIG_ENDIAN);
492                         offset += 1;
493
494                         while ((tvb_reported_length_remaining(tvb, offset)>=4)
495                                 && (neighbor_count>0)) {
496                                 proto_tree_add_item(parent_tree, hf_neighbor,
497                                         tvb, offset, 4, ENC_BIG_ENDIAN);
498                                 offset += 4;
499                                 neighbor_count--;
500                         }
501                 }
502                 break;
503         }
504
505         return offset;
506 }
507
508
509 static int
510 dissect_dvmrp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
511 {
512         guint8 code;
513         guint8 af=2; /* default */
514
515         /* version */
516         proto_tree_add_uint(parent_tree, hf_version, tvb, 0, 0, 1);
517
518         /* type of command */
519         proto_tree_add_uint(parent_tree, hf_type, tvb, offset, 1, 0x13);
520         offset += 1;
521
522         /* code */
523         code = tvb_get_guint8(tvb, offset);
524         proto_tree_add_uint(parent_tree, hf_code_v1, tvb, offset, 1, code);
525         offset += 1;
526         col_add_fstr(pinfo->cinfo, COL_INFO,
527                         "V%d %s",1 ,val_to_str(code, code_v1,
528                                 "Unknown Type:0x%02x"));
529
530         /* checksum */
531         igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
532         offset += 2;
533
534         /* decode all the v1 commands */
535         while (tvb_reported_length_remaining(tvb, offset) > 0) {
536                 proto_tree *tree;
537                 proto_item *item;
538                 guint8 cmd,count;
539                 int old_offset = offset;
540
541                 item = proto_tree_add_item(parent_tree, hf_commands,
542                                 tvb, offset, -1, ENC_NA);
543                 tree = proto_item_add_subtree(item, ett_commands);
544
545                 cmd = tvb_get_guint8(tvb, offset);
546                 proto_tree_add_uint(tree, hf_command, tvb,
547                         offset, 1, cmd);
548                 offset += 1;
549
550                 switch (cmd){
551                 case V1_COMMAND_NULL:
552                         offset += 1; /* skip ignored/pad byte*/
553                         if (item) {
554                                 proto_item_set_text(item, "Command: NULL");
555                         }
556                         break;
557                 case V1_COMMAND_AFI:
558                         af = tvb_get_guint8(tvb, offset);
559                         proto_tree_add_uint(tree, hf_afi, tvb,
560                                 offset, 1, af);
561                         offset += 1;
562                         if (item) {
563                                 proto_item_set_text(item, "%s: %s",
564                                         val_to_str(cmd, command, "Unknown Command:0x%02x"),
565                                         val_to_str(af, afi, "Unknown Family:0x%02x")
566                                 );
567                         }
568                         break;
569                 case V1_COMMAND_SUBNETMASK:
570                         count = tvb_get_guint8(tvb, offset);
571                         proto_tree_add_uint(tree, hf_count, tvb,
572                                 offset, 1, count);
573                         offset += 1;
574                         if (count) { /* must be 0 or 1 */
575                                 proto_tree_add_item(tree, hf_netmask,
576                                         tvb, offset, 4, ENC_BIG_ENDIAN);
577                                 if (item) {
578                                         proto_item_set_text(item, "%s: %d.%d.%d.%d",
579                                                 val_to_str(cmd, command, "Unknown Command:0x%02x"),
580                                                 tvb_get_guint8(tvb, offset),
581                                                 tvb_get_guint8(tvb, offset+1),
582                                                 tvb_get_guint8(tvb, offset+2),
583                                                 tvb_get_guint8(tvb, offset+3));
584                                 }
585                                 offset += 4;
586                         } else {
587                                 if (item) {
588                                         proto_item_set_text(item, "%s: <no mask supplied>",
589                                                 val_to_str(cmd, command, "Unknown Command:0x%02x"));
590                                 }
591                         }
592                         break;
593                 case V1_COMMAND_METRIC:
594                         proto_tree_add_item(tree, hf_metric, tvb,
595                                 offset, 1, ENC_BIG_ENDIAN);
596                         if (item) {
597                                 proto_item_set_text(item, "%s: %d",
598                                         val_to_str(cmd, command, "Unknown Command:0x%02x"),
599                                         tvb_get_guint8(tvb, offset));
600                         }
601                         offset += 1;
602                         break;
603                 case V1_COMMAND_FLAGS0:
604                         count = tvb_get_guint8(tvb, offset);
605                         proto_tree_add_boolean(tree, hf_dest_unr, tvb, offset, 1, count);
606                         proto_tree_add_boolean(tree, hf_split_horiz, tvb, offset, 1, count);
607                         if (item) {
608                                 proto_item_set_text(item, "%s: 0x%02x",
609                                         val_to_str(cmd, command, "Unknown Command:0x%02x"), count);
610                         }
611                         offset += 1;
612                         break;
613                 case V1_COMMAND_INFINITY:
614                         proto_tree_add_item(tree, hf_infinity, tvb,
615                                 offset, 1, ENC_BIG_ENDIAN);
616                         if (item) {
617                                 proto_item_set_text(item, "%s: %d",
618                                         val_to_str(cmd, command, "Unknown Command:0x%02x"), tvb_get_guint8(tvb, offset));
619                         }
620                         offset += 1;
621                         break;
622                 case V1_COMMAND_DA:
623                 case V1_COMMAND_RDA: /* same as DA */
624                         count = tvb_get_guint8(tvb, offset);
625                         proto_tree_add_uint(tree, hf_count, tvb,
626                                 offset, 1, count);
627                         offset += 1;
628                         while (count--) {
629                                 proto_tree_add_item(tree, hf_daddr,
630                                         tvb, offset, 4, ENC_BIG_ENDIAN);
631                                 offset += 4;
632                         }
633                         if (item) {
634                                 proto_item_set_text(item, "%s",
635                                         val_to_str(cmd, command, "Unknown Command:0x%02x"));
636                         }
637                         break;
638                 case V1_COMMAND_NMR:
639                         count = tvb_get_guint8(tvb, offset);
640                         proto_tree_add_uint(tree, hf_count, tvb,
641                                 offset, 1, count);
642                         offset += 1;
643                         while (count--) {
644                                 proto_tree_add_item(tree, hf_maddr,
645                                         tvb, offset, 4, ENC_BIG_ENDIAN);
646                                 offset += 4;
647                                 proto_tree_add_item(tree, hf_hold, tvb,
648                                         offset, 4, ENC_BIG_ENDIAN);
649                                 offset += 4;
650                         }
651                         if (item) {
652                                 proto_item_set_text(item, "%s",
653                                         val_to_str(cmd, command, "Unknown Command:0x%02x"));
654                         }
655                         break;
656                 case V1_COMMAND_NMR_CANCEL:
657                         count = tvb_get_guint8(tvb, offset);
658                         proto_tree_add_uint(tree, hf_count, tvb,
659                                 offset, 1, count);
660                         offset += 1;
661                         while (count--) {
662                                 proto_tree_add_item(tree, hf_maddr,
663                                         tvb, offset, 4, ENC_BIG_ENDIAN);
664                                 offset += 4;
665                         }
666                         if (item) {
667                                 proto_item_set_text(item, "%s",
668                                         val_to_str(cmd, command, "Unknown Command:0x%02x"));
669                         }
670                         break;
671                 }
672
673                 proto_item_set_len(item, offset-old_offset);
674         }
675
676         return offset;
677 }
678
679 /* This function is only called from the IGMP dissector */
680 int
681 dissect_dvmrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
682 {
683         proto_tree *tree;
684         proto_item *item;
685
686         if (!proto_is_protocol_enabled(find_protocol_by_id(proto_dvmrp))) {
687                 /* we are not enabled, skip entire packet to be nice
688                    to the igmp layer. (so clicking on IGMP will display the data)
689                  */
690                 return offset+tvb_length_remaining(tvb, offset);
691         }
692
693         item = proto_tree_add_item(parent_tree, proto_dvmrp, tvb, offset, -1, ENC_NA);
694         tree = proto_item_add_subtree(item, ett_dvmrp);
695
696
697         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DVMRP");
698         col_clear(pinfo->cinfo, COL_INFO);
699
700
701         if ((tvb_length_remaining(tvb, offset)>=8)
702          && (((tvb_get_guint8(tvb, 6)==0xff)
703          && (tvb_get_guint8(tvb, 7)==0x03))
704          || !strict_v3)) {
705                 offset = dissect_dvmrp_v3(tvb, pinfo, tree, offset);
706         } else {
707                 offset = dissect_dvmrp_v1(tvb, pinfo, tree, offset);
708         }
709
710         proto_item_set_len(item, offset);
711         return offset;
712 }
713
714 void
715 proto_register_dvmrp(void)
716 {
717         static hf_register_info hf[] = {
718                 { &hf_version,
719                         { "DVMRP Version", "dvmrp.version", FT_UINT8, BASE_DEC,
720                           NULL, 0, NULL, HFILL }},
721
722                 { &hf_type,
723                         { "Type", "dvmrp.type", FT_UINT8, BASE_HEX,
724                           VALS(dvmrp_type), 0, "DVMRP Packet Type", HFILL }},
725
726                 { &hf_code_v1,
727                         { "Code", "dvmrp.v1.code", FT_UINT8, BASE_HEX,
728                           VALS(code_v1), 0, "DVMRP Packet Code", HFILL }},
729
730                 { &hf_checksum,
731                         { "Checksum", "dvmrp.checksum", FT_UINT16, BASE_HEX,
732                           NULL, 0, "DVMRP Checksum", HFILL }},
733
734                 { &hf_checksum_bad,
735                         { "Bad Checksum", "dvmrp.checksum_bad", FT_BOOLEAN, BASE_NONE,
736                           NULL, 0x0, "Bad DVMRP Checksum", HFILL }},
737
738                 { &hf_commands,
739                         { "Commands", "dvmrp.commands", FT_NONE, BASE_NONE,
740                           NULL, 0, "DVMRP V1 Commands", HFILL }},
741
742                 { &hf_command,
743                         { "Command", "dvmrp.command", FT_UINT8, BASE_HEX,
744                           VALS(command), 0, "DVMRP V1 Command", HFILL }},
745
746                 { &hf_afi,
747                         { "Address Family", "dvmrp.afi", FT_UINT8, BASE_HEX,
748                           VALS(afi), 0, "DVMRP Address Family Indicator", HFILL }},
749
750                 { &hf_count,
751                         { "Count", "dvmrp.count", FT_UINT8, BASE_HEX,
752                           NULL, 0, NULL, HFILL }},
753
754                 { &hf_netmask,
755                         { "Netmask", "dvmrp.netmask", FT_IPv4, BASE_NONE,
756                           NULL, 0, "DVMRP Netmask", HFILL }},
757
758                 { &hf_metric,
759                         { "Metric", "dvmrp.metric", FT_UINT8, BASE_DEC,
760                           NULL, 0, "DVMRP Metric", HFILL }},
761
762                 {&hf_dest_unr,
763                         { "Destination Unreachable", "dvmrp.dest_unreach", FT_BOOLEAN, 8,
764                         TFS(&tfs_dest_unreach), 0x01, NULL, HFILL }},
765
766                 {&hf_split_horiz,
767                         { "Split Horizon", "dvmrp.split_horiz", FT_BOOLEAN, 8,
768                         TFS(&tfs_split_horiz), 0x02, "Split Horizon concealed route", HFILL }},
769
770                 { &hf_infinity,
771                         { "Infinity", "dvmrp.infinity", FT_UINT8, BASE_DEC,
772                           NULL, 0, "DVMRP Infinity", HFILL }},
773
774                 { &hf_daddr,
775                         { "Dest Addr", "dvmrp.daddr", FT_IPv4, BASE_NONE,
776                           NULL, 0, "DVMRP Destination Address", HFILL }},
777
778                 { &hf_maddr,
779                         { "Multicast Addr", "dvmrp.maddr", FT_IPv4, BASE_NONE,
780                           NULL, 0, "DVMRP Multicast Address", HFILL }},
781
782                 { &hf_hold,
783                         { "Hold Time", "dvmrp.hold", FT_UINT32, BASE_DEC,
784                           NULL, 0, "DVMRP Hold Time in seconds", HFILL }},
785
786                 { &hf_code_v3,
787                         { "Code", "dvmrp.v3.code", FT_UINT8, BASE_HEX,
788                           VALS(code_v3), 0, "DVMRP Packet Code", HFILL }},
789
790                 { &hf_capabilities,
791                         { "Capabilities", "dvmrp.capabilities", FT_NONE, BASE_NONE,
792                           NULL, 0, "DVMRP V3 Capabilities", HFILL }},
793
794                 {&hf_cap_leaf,
795                         { "Leaf", "dvmrp.cap.leaf", FT_BOOLEAN, 8,
796                         TFS(&tfs_cap_leaf), DVMRP_V3_CAP_LEAF, NULL, HFILL }},
797
798                 {&hf_cap_prune,
799                         { "Prune", "dvmrp.cap.prune", FT_BOOLEAN, 8,
800                         TFS(&tfs_cap_prune), DVMRP_V3_CAP_PRUNE, "Prune capability", HFILL }},
801
802                 {&hf_cap_genid,
803                         { "Genid", "dvmrp.cap.genid", FT_BOOLEAN, 8,
804                         TFS(&tfs_cap_genid), DVMRP_V3_CAP_GENID, "Genid capability", HFILL }},
805
806                 {&hf_cap_mtrace,
807                         { "Mtrace", "dvmrp.cap.mtrace", FT_BOOLEAN, 8,
808                         TFS(&tfs_cap_mtrace), DVMRP_V3_CAP_MTRACE, "Mtrace capability", HFILL }},
809
810                 {&hf_cap_snmp,
811                         { "SNMP", "dvmrp.cap.snmp", FT_BOOLEAN, 8,
812                         TFS(&tfs_cap_snmp), DVMRP_V3_CAP_SNMP, "SNMP capability", HFILL }},
813
814                 {&hf_cap_netmask,
815                         { "Netmask", "dvmrp.cap.netmask", FT_BOOLEAN, 8,
816                         TFS(&tfs_cap_netmask), DVMRP_V3_CAP_NETMASK, "Netmask capability", HFILL }},
817
818                 { &hf_min_ver,
819                         { "Minor Version", "dvmrp.min_ver", FT_UINT8, BASE_HEX,
820                           NULL, 0, "DVMRP Minor Version", HFILL }},
821
822                 { &hf_maj_ver,
823                         { "Major Version", "dvmrp.maj_ver", FT_UINT8, BASE_HEX,
824                           NULL, 0, "DVMRP Major Version", HFILL }},
825
826                 { &hf_genid,
827                         { "Generation ID", "dvmrp.genid", FT_UINT32, BASE_DEC,
828                           NULL, 0, "DVMRP Generation ID", HFILL }},
829
830                 { &hf_route,
831                         { "Route", "dvmrp.route", FT_NONE, BASE_NONE,
832                           NULL, 0, "DVMRP V3 Route Report", HFILL }},
833
834                 { &hf_saddr,
835                         { "Source Addr", "dvmrp.saddr", FT_IPv4, BASE_NONE,
836                           NULL, 0, "DVMRP Source Address", HFILL }},
837
838                 { &hf_life,
839                         { "Prune lifetime", "dvmrp.lifetime", FT_UINT32, BASE_DEC,
840                           NULL, 0, "DVMRP Prune Lifetime", HFILL }},
841
842                 { &hf_local,
843                         { "Local Addr", "dvmrp.local", FT_IPv4, BASE_NONE,
844                           NULL, 0, "DVMRP Local Address", HFILL }},
845
846                 { &hf_threshold,
847                         { "Threshold", "dvmrp.threshold", FT_UINT8, BASE_DEC,
848                         NULL, 0, "DVMRP Interface Threshold", HFILL }},
849
850                 { &hf_flags,
851                         { "Flags", "dvmrp.flags", FT_NONE, BASE_NONE,
852                         NULL, 0, "DVMRP Interface Flags", HFILL }},
853
854                 { &hf_flag_tunnel,
855                         { "Tunnel", "dvmrp.flag.tunnel", FT_BOOLEAN, 8,
856                         NULL, DVMRP_V3_FLAG_TUNNEL, "Neighbor reached via tunnel", HFILL }},
857
858                 { &hf_flag_srcroute,
859                         { "Source Route", "dvmrp.flag.srcroute", FT_BOOLEAN, 8,
860                         NULL, DVMRP_V3_FLAG_SRCROUTE, "Tunnel uses IP source routing", HFILL }},
861
862                 { &hf_flag_down,
863                         { "Down", "dvmrp.flag.down", FT_BOOLEAN, 8,
864                         NULL, DVMRP_V3_FLAG_DOWN, "Operational status down", HFILL }},
865
866                 { &hf_flag_disabled,
867                         { "Disabled", "dvmrp.flag.disabled", FT_BOOLEAN, 8,
868                         NULL, DVMRP_V3_FLAG_DISABLED, "Administrative status down", HFILL }},
869
870                 { &hf_flag_querier,
871                         { "Querier", "dvmrp.flag.querier", FT_BOOLEAN, 8,
872                         NULL, DVMRP_V3_FLAG_QUERIER, "Querier for interface", HFILL }},
873
874                 { &hf_flag_leaf,
875                         { "Leaf", "dvmrp.flag.leaf", FT_BOOLEAN, 8,
876                         NULL, DVMRP_V3_FLAG_LEAF, "No downstream neighbors on interface", HFILL }},
877
878                 { &hf_ncount,
879                         { "Neighbor Count", "dvmrp.ncount", FT_UINT8, BASE_DEC,
880                         NULL, 0, "DVMRP Neighbor Count", HFILL }},
881
882                 { &hf_neighbor,
883                         { "Neighbor Addr", "dvmrp.neighbor", FT_IPv4, BASE_NONE,
884                           NULL, 0, "DVMRP Neighbor Address", HFILL }}
885         };
886         static gint *ett[] = {
887                 &ett_dvmrp,
888                 &ett_commands,
889                 &ett_capabilities,
890                 &ett_flags,
891                 &ett_route
892         };
893         module_t *module_dvmrp;
894
895         proto_dvmrp = proto_register_protocol("Distance Vector Multicast Routing Protocol",
896             "DVMRP", "dvmrp");
897         proto_register_field_array(proto_dvmrp, hf, array_length(hf));
898         proto_register_subtree_array(ett, array_length(ett));
899
900         module_dvmrp = prefs_register_protocol(proto_dvmrp, NULL);
901
902         prefs_register_bool_preference(module_dvmrp, "strict_v3", "Allow strict DVMRP V3 only",
903                 "Allow only packets with Major=0x03//Minor=0xFF as DVMRP V3 packets",
904                 &strict_v3);
905 }