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