2 * Routines for IGMP packet disassembly
5 * <See AUTHORS for emails>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 IGMP is defined in the following RFCs
29 RFC988 Version 0 Obsolete
31 RFC1112 Version 1 (same as RFC1054 as far as we are concerned)
35 Size in bytes for each packet
36 type RFC988 RFC1054 RFC2236 RFC3376 DVMRP MRDISC MSNIP IGAP RGMP
64 * Differs in second byte of protocol. Always 0 in V1
67 Multicast traceroute was taken from
68 draft-ietf-idmr-traceroute-ipm-07.txt
70 Size in bytes for each packet
71 type draft-ietf-idmr-traceroute-ipm-07.ps
73 0x1f 24 + n*32 (n == 0 for Query)
75 x DVMRP Protocol see packet-dvmrp.c
77 DVMRP is defined in the following RFCs
79 draft-ietf-idmr-dvmrp-v3-10.txt Version 3
81 V1 and V3 can be distinguished by looking at bytes 6 and 7 in the
83 If header[6]==0xff and header[7]==0x03 we have version 3.
85 a MRDISC Protocol see packet-mrdisc.c
87 MRDISC : IGMP Multicast Router DISCovery
88 draft-ietf-idmr-igmp-mrdisc-06.txt
89 TTL == 1 and IP.DST==224.0.0.2 for all packets
91 b MSNIP Protocol see packet-msnip.c
93 MSNIP : Multicast Source Notification of Interest Protocol
94 draft-ietf-idmr-msnip-00.txt
95 0x23, 0x24 are sent with ip.dst==224.0.0.22
96 0x25 is sent as unicast.
98 c IGAP Protocol see packet-igap.c
100 IGAP : Internet Group membership Authentication Protocol
101 draft-hayashi-igap-03.txt
103 d RGMP Protocol see packet-rgmp.c
105 RGMP : Router-port Group Management Protocol
107 TTL == 1 and IP.DST==224.0.0.25 for all packets
118 #include <epan/packet.h>
119 #include <epan/ipproto.h>
120 #include <epan/in_cksum.h>
121 #include "packet-igmp.h"
122 #include "packet-dvmrp.h"
123 #include "packet-pim.h"
124 #include "packet-mrdisc.h"
125 #include "packet-msnip.h"
126 #include "packet-igap.h"
127 #include "packet-rgmp.h"
129 static int proto_igmp = -1;
130 static int hf_type = -1;
131 static int hf_version = -1;
132 static int hf_group_type = -1;
133 static int hf_reply_code = -1;
134 static int hf_reply_pending = -1;
135 static int hf_checksum = -1;
136 static int hf_checksum_bad = -1;
137 static int hf_identifier = -1;
138 static int hf_access_key = -1;
139 static int hf_max_resp = -1;
140 static int hf_max_resp_exp = -1;
141 static int hf_max_resp_mant = -1;
142 static int hf_suppress = -1;
143 static int hf_qrv = -1;
144 static int hf_qqic = -1;
145 static int hf_num_src = -1;
146 static int hf_saddr = -1;
147 static int hf_num_grp_recs = -1;
148 static int hf_record_type = -1;
149 static int hf_aux_data_len = -1;
150 static int hf_maddr = -1;
151 static int hf_aux_data = -1;
152 static int hf_mtrace_max_hops = -1;
153 static int hf_mtrace_saddr = -1;
154 static int hf_mtrace_raddr = -1;
155 static int hf_mtrace_rspaddr = -1;
156 static int hf_mtrace_resp_ttl = -1;
157 static int hf_mtrace_q_id = -1;
158 static int hf_mtrace_q_arrival = -1;
159 static int hf_mtrace_q_inaddr = -1;
160 static int hf_mtrace_q_outaddr = -1;
161 static int hf_mtrace_q_prevrtr = -1;
162 static int hf_mtrace_q_inpkt = -1;
163 static int hf_mtrace_q_outpkt = -1;
164 static int hf_mtrace_q_total = -1;
165 static int hf_mtrace_q_rtg_proto = -1;
166 static int hf_mtrace_q_fwd_ttl = -1;
167 static int hf_mtrace_q_mbz = -1;
168 static int hf_mtrace_q_s = -1;
169 static int hf_mtrace_q_src_mask = -1;
170 static int hf_mtrace_q_fwd_code = -1;
172 static int ett_igmp = -1;
173 static int ett_group_record = -1;
174 static int ett_sqrv_bits = -1;
175 static int ett_max_resp = -1;
176 static int ett_mtrace_block = -1;
178 #define MC_ALL_ROUTERS 0xe0000002
179 #define MC_ALL_IGMPV3_ROUTERS 0xe0000016
180 #define MC_RGMP 0xe0000019
183 #define IGMP_V0_CREATE_GROUP_REQUEST 0x01
184 #define IGMP_V0_CREATE_GROUP_REPLY 0x02
185 #define IGMP_V0_JOIN_GROUP_REQUEST 0x03
186 #define IGMP_V0_JOIN_GROUP_REPLY 0x04
187 #define IGMP_V0_LEAVE_GROUP_REQUEST 0x05
188 #define IGMP_V0_LEAVE_GROUP_REPLY 0x06
189 #define IGMP_V0_CONFIRM_GROUP_REQUEST 0x07
190 #define IGMP_V0_CONFIRM_GROUP_REPLY 0x08
191 #define IGMP_V1_HOST_MEMBERSHIP_QUERY 0x11
192 #define IGMP_V1_HOST_MEMBERSHIP_REPORT 0x12
193 #define IGMP_DVMRP 0x13
194 #define IGMP_V1_PIM_ROUTING_MESSAGE 0x14
195 #define IGMP_V2_MEMBERSHIP_REPORT 0x16
196 #define IGMP_V2_LEAVE_GROUP 0x17
197 #define IGMP_TRACEROUTE_RESPONSE 0x1e
198 #define IGMP_TRACEROUTE_QUERY_REQ 0x1f
199 #define IGMP_V3_MEMBERSHIP_REPORT 0x22
200 #define IGMP_TYPE_0x23 0x23
201 #define IGMP_TYPE_0x24 0x24
202 #define IGMP_TYPE_0x25 0x25
203 #define IGMP_TYPE_0x26 0x26
205 #define IGMP_TRACEROUTE_HDR_LEN 24
206 #define IGMP_TRACEROUTE_RSP_LEN 32
208 static const value_string commands[] = {
209 {IGMP_V0_CREATE_GROUP_REQUEST, "Create Group Request" },
210 {IGMP_V0_CREATE_GROUP_REPLY, "Create Group Reply" },
211 {IGMP_V0_JOIN_GROUP_REQUEST, "Join Group Request" },
212 {IGMP_V0_JOIN_GROUP_REPLY, "Join Group Reply" },
213 {IGMP_V0_LEAVE_GROUP_REQUEST, "Leave Group Request" },
214 {IGMP_V0_LEAVE_GROUP_REPLY, "Leave Group Reply" },
215 {IGMP_V0_CONFIRM_GROUP_REQUEST, "Confirm Group Request" },
216 {IGMP_V0_CONFIRM_GROUP_REPLY, "Confirm Group Reply" },
217 {IGMP_V1_HOST_MEMBERSHIP_QUERY, "Membership Query" },
218 {IGMP_V1_HOST_MEMBERSHIP_REPORT,"Membership Report" },
219 {IGMP_DVMRP, "DVMRP Protocol" },
220 {IGMP_V1_PIM_ROUTING_MESSAGE, "PIM Routing Message" },
221 {IGMP_V2_MEMBERSHIP_REPORT, "Membership Report" },
222 {IGMP_V2_LEAVE_GROUP, "Leave Group" },
223 {IGMP_TRACEROUTE_RESPONSE, "Traceroute Response" },
224 {IGMP_TRACEROUTE_QUERY_REQ, "Traceroute Query or Request" },
225 {IGMP_V3_MEMBERSHIP_REPORT, "Membership Report" },
229 #define IGMP_V3_S 0x08
230 #define IGMP_V3_QRV_MASK 0x07
232 #define IGMP_MAX_RESP_EXP 0x70
233 #define IGMP_MAX_RESP_MANT 0x0f
235 #define IGMP_V0_GROUP_PUBLIC 0x00
236 #define IGMP_V0_GROUP_PRIVATE 0x01
238 static const value_string vs_group_type[] = {
239 {IGMP_V0_GROUP_PUBLIC, "Public Group" },
240 {IGMP_V0_GROUP_PRIVATE, "Private Group" },
244 #define IGMP_V0_REPLY_GRANTED 0x00
245 #define IGMP_V0_REPLY_NO_RESOURCES 0x01
246 #define IGMP_V0_REPLY_INVALID_CODE 0x02
247 #define IGMP_V0_REPLY_INVALID_GROUP 0x03
248 #define IGMP_V0_REPLY_INVALID_KEY 0x04
250 static const value_string vs_reply_code[] = {
251 {IGMP_V0_REPLY_GRANTED, "Request Granted" },
252 {IGMP_V0_REPLY_NO_RESOURCES, "Request Denied, No Resources" },
253 {IGMP_V0_REPLY_INVALID_CODE, "Request Denied, Invalid Code" },
254 {IGMP_V0_REPLY_INVALID_GROUP, "Request Denied, Invalid Group" },
255 {IGMP_V0_REPLY_INVALID_KEY, "Request Denied, Invalid Key" },
259 static const true_false_string tfs_s = {
260 "SUPPRESS router side processing",
261 "Do not suppress router side processing"
264 #define IGMP_V3_MODE_IS_INCLUDE 1
265 #define IGMP_V3_MODE_IS_EXCLUDE 2
266 #define IGMP_V3_CHANGE_TO_INCLUDE_MODE 3
267 #define IGMP_V3_CHANGE_TO_EXCLUDE_MODE 4
268 #define IGMP_V3_ALLOW_NEW_SOURCES 5
269 #define IGMP_V3_BLOCK_OLD_SOURCES 6
271 static const value_string vs_record_type[] = {
272 {IGMP_V3_MODE_IS_INCLUDE, "Mode Is Include" },
273 {IGMP_V3_MODE_IS_EXCLUDE, "Mode Is Exclude" },
274 {IGMP_V3_CHANGE_TO_INCLUDE_MODE,"Change To Include Mode" },
275 {IGMP_V3_CHANGE_TO_EXCLUDE_MODE,"Change To Exclude Mode" },
276 {IGMP_V3_ALLOW_NEW_SOURCES, "Allow New Sources" },
277 {IGMP_V3_BLOCK_OLD_SOURCES, "Block Old Sources" },
281 static const value_string mtrace_rtg_vals[] = {
286 {5, "PIM using special routing table" },
287 {6, "PIM using a static route" },
288 {7, "DVMRP using a static route" },
289 {8, "PIM using MBGP (aka BGP4+) route" },
290 {9, "CBT using special routing table" },
291 {10, "CBT using a static route" },
292 {11, "PIM using state created by Assert processing" },
296 static const value_string mtrace_fwd_code_vals[] = {
299 {0x02, "PRUNE_SENT" },
300 {0x03, "PRUNE_RCVD" },
303 {0x06, "WRONG_LAST_HOP" },
304 {0x07, "NOT_FORWARDING" },
305 {0x08, "REACHED_RP" },
307 {0x0A, "NO_MULTICAST" },
308 {0x0B, "INFO_HIDDEN" },
310 {0x82, "OLD_ROUTER" },
311 {0x83, "ADMIN_PROHIB" },
315 #define PRINT_IGMP_VERSION(version) \
318 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "IGMPv%d",version); \
319 col_add_fstr(pinfo->cinfo, COL_INFO, \
320 "%s",val_to_str(type, commands, "Unknown Type:0x%02x")); \
321 /* version of IGMP protocol */ \
322 ti = proto_tree_add_uint(tree, hf_version, tvb, 0, 0, version); \
323 PROTO_ITEM_SET_GENERATED(ti); \
324 /* type of command */ \
325 proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);\
329 void igmp_checksum(proto_tree *tree, tvbuff_t *tvb, int hf_index,
330 int hf_index_bad, packet_info *pinfo, guint len)
332 guint16 cksum, hdrcksum;
334 proto_item *hidden_item;
338 * Checksum the entire IGMP packet.
340 len = tvb_reported_length(tvb);
343 hdrcksum = tvb_get_ntohs(tvb, 2);
344 if (!pinfo->fragmented && tvb_length(tvb) >= len) {
346 * The packet isn't part of a fragmented datagram and isn't
347 * truncated, so we can checksum it.
349 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, len);
350 cksum_vec[0].len = len;
352 cksum = in_cksum(&cksum_vec[0],1);
355 proto_tree_add_uint_format(tree, hf_index, tvb, 2, 2, hdrcksum,
356 "Header checksum: 0x%04x [correct]", hdrcksum);
358 hidden_item = proto_tree_add_boolean(tree, hf_index_bad,
360 PROTO_ITEM_SET_HIDDEN(hidden_item);
361 proto_tree_add_uint_format(tree, hf_index, tvb, 2, 2, hdrcksum,
362 "Header checksum: 0x%04x [incorrect, should be 0x%04x]",
363 hdrcksum, in_cksum_shouldbe(hdrcksum,cksum));
366 proto_tree_add_uint(tree, hf_index, tvb, 2, 2, hdrcksum);
372 /* Unknown IGMP message type */
374 dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
378 col_add_str(pinfo->cinfo, COL_INFO,
379 val_to_str(type, commands, "Unknown Type:0x%02x"));
381 /* type of command */
382 proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);
385 /* Just call the rest of it "data" */
386 len = tvb_length_remaining(tvb, offset);
387 proto_tree_add_text(tree, tvb, offset, len, "Data");
395 /*************************************************************
396 * IGMP Protocol dissectors
397 *************************************************************/
399 dissect_v3_max_resp(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
406 bits = tvb_get_guint8(tvb, offset);
408 tsecs = ((bits&IGMP_MAX_RESP_MANT)|0x10);
409 tsecs = tsecs << ( ((bits&IGMP_MAX_RESP_EXP)>>4) + 3);
414 item = proto_tree_add_uint_format(parent_tree, hf_max_resp, tvb,
415 offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)",tsecs*0.1,bits);
418 tree = proto_item_add_subtree(item, ett_max_resp);
420 proto_tree_add_uint(tree, hf_max_resp_exp, tvb, offset, 1,
422 proto_tree_add_uint(tree, hf_max_resp_mant, tvb, offset, 1,
432 dissect_v3_sqrv_bits(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
438 bits = tvb_get_guint8(tvb, offset);
440 item = proto_tree_add_text(parent_tree, tvb, offset, 1,
441 "QRV=%d S=%s", bits&IGMP_V3_QRV_MASK,
442 (bits&IGMP_V3_S)?tfs_s.true_string:tfs_s.false_string);
443 tree = proto_item_add_subtree(item, ett_sqrv_bits);
446 proto_tree_add_boolean(tree, hf_suppress, tvb, offset, 1, bits);
448 proto_tree_add_uint(tree, hf_qrv, tvb, offset, 1, bits);
455 dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
459 int old_offset = offset;
466 ip = tvb_get_ipv4(tvb, offset+4);
467 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
468 "Group Record : %s %s",
469 ip_to_str((guint8*)&ip),
470 val_to_str(tvb_get_guint8(tvb, offset), vs_record_type,"")
472 tree = proto_item_add_subtree(item, ett_group_record);
475 record_type = tvb_get_guint8(tvb, offset);
476 proto_tree_add_item(tree, hf_record_type, tvb, offset, 1, ENC_BIG_ENDIAN);
480 adl = tvb_get_guint8(tvb, offset);
481 proto_tree_add_uint(tree, hf_aux_data_len, tvb, offset, 1, adl);
484 /*number of sources*/
485 num = tvb_get_ntohs(tvb, offset);
486 proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
489 /* multicast address */
490 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
491 maddr = tvb_get_ipv4(tvb, offset);
495 switch(record_type) {
496 case IGMP_V3_MODE_IS_INCLUDE:
497 case IGMP_V3_CHANGE_TO_INCLUDE_MODE:
498 col_append_fstr(pinfo->cinfo, COL_INFO, " / Leave group %s",
499 ip_to_str((guint8*)&maddr));
501 case IGMP_V3_MODE_IS_EXCLUDE:
502 case IGMP_V3_CHANGE_TO_EXCLUDE_MODE:
503 col_append_fstr(pinfo->cinfo, COL_INFO,
504 " / Join group %s for any sources", ip_to_str((guint8*)&maddr));
506 case IGMP_V3_ALLOW_NEW_SOURCES:
507 col_append_fstr(pinfo->cinfo, COL_INFO,
508 " / Group %s, ALLOW_NEW_SOURCES but no source specified (?)",
509 ip_to_str((guint8*)&maddr));
511 case IGMP_V3_BLOCK_OLD_SOURCES:
512 col_append_fstr(pinfo->cinfo, COL_INFO,
513 " / Group %s, BLOCK_OLD_SOURCES but no source specified (?)",
514 ip_to_str((guint8*)&maddr));
517 col_append_fstr(pinfo->cinfo, COL_INFO,
518 " / Group %s, unknown record type (?)",
519 ip_to_str((guint8*)&maddr));
523 switch(record_type) {
524 case IGMP_V3_MODE_IS_INCLUDE:
525 case IGMP_V3_CHANGE_TO_INCLUDE_MODE:
526 col_append_fstr(pinfo->cinfo, COL_INFO,
527 " / Join group %s for source%s {",
528 ip_to_str((guint8*)&maddr), (num>1) ? "s in" : "");
530 case IGMP_V3_MODE_IS_EXCLUDE:
531 case IGMP_V3_CHANGE_TO_EXCLUDE_MODE:
532 col_append_fstr(pinfo->cinfo, COL_INFO,
533 " / Join group %s, for source%s {",
534 ip_to_str((guint8*)&maddr), (num>1) ? "s not in" : " not");
536 case IGMP_V3_ALLOW_NEW_SOURCES:
537 col_append_fstr(pinfo->cinfo, COL_INFO,
538 " / Group %s, new source%s {",
539 ip_to_str((guint8*)&maddr), (num>1) ? "s" : "");
541 case IGMP_V3_BLOCK_OLD_SOURCES:
542 col_append_fstr(pinfo->cinfo, COL_INFO,
543 " / Group %s, block source%s {",
544 ip_to_str((guint8*)&maddr), (num>1) ? "s" : "");
547 col_append_fstr(pinfo->cinfo, COL_INFO,
548 " / Group %s, unknown record type (?), sources {",
549 ip_to_str((guint8*)&maddr));
554 /* source addresses */
556 if (check_col(pinfo->cinfo, COL_INFO)) {
557 col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s",
558 tvb_ip_to_str(tvb, offset), (num?", ":"}"));
560 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, ENC_BIG_ENDIAN);
566 proto_tree_add_item(tree, hf_aux_data, tvb, offset, adl*4, ENC_NA);
570 proto_item_set_len(item, offset-old_offset);
574 /* dissectors for version 3, rfc3376 */
576 dissect_igmp_v3_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
580 PRINT_IGMP_VERSION(3);
582 /* skip reserved field*/
586 igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
589 /* skip reserved field */
592 /* number of group records */
593 num = tvb_get_ntohs(tvb, offset);
595 col_append_fstr(pinfo->cinfo, COL_INFO, " - General query");
597 proto_tree_add_uint(tree, hf_num_grp_recs, tvb, offset, 2, num);
601 offset = dissect_v3_group_record(tvb, pinfo, tree, offset);
607 dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
612 PRINT_IGMP_VERSION(3);
614 num = tvb_get_ntohs(tvb, offset+9);
616 offset = dissect_v3_max_resp(tvb, tree, offset);
619 igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
623 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
625 maddr = tvb_get_ipv4(tvb, offset);
627 col_append_fstr(pinfo->cinfo, COL_INFO, ", general");
629 col_append_fstr(pinfo->cinfo, COL_INFO, ", specific for group %s",
630 ip_to_str((guint8*)&maddr));
634 /* bitmask for S and QRV */
635 offset = dissect_v3_sqrv_bits(tvb, tree, offset);
638 proto_tree_add_item(tree, hf_qqic, tvb, offset, 1, ENC_BIG_ENDIAN);
641 /*number of sources*/
642 proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
644 col_append_fstr(pinfo->cinfo, COL_INFO, ", source%s {", (num>1)?"s":"");
649 if (check_col(pinfo->cinfo, COL_INFO))
650 col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", tvb_ip_to_str(tvb, offset), (num?", ":"}"));
651 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, ENC_BIG_ENDIAN);
658 /* dissector for version 2 query and report, rfc2236 */
660 dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
665 PRINT_IGMP_VERSION(2);
668 tsecs = tvb_get_guint8(tvb, offset);
669 proto_tree_add_uint_format(tree, hf_max_resp, tvb,
670 offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)", tsecs*0.1,tsecs);
674 igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
678 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
680 maddr = tvb_get_ipv4(tvb, offset);
682 col_append_fstr(pinfo->cinfo, COL_INFO, ", general");
684 if (type == IGMP_V2_LEAVE_GROUP) {
685 col_append_fstr(pinfo->cinfo, COL_INFO,
686 " %s", ip_to_str((guint8*)&maddr));
687 } else if (type == IGMP_V1_HOST_MEMBERSHIP_QUERY) {
688 col_append_fstr(pinfo->cinfo, COL_INFO,
689 ", specific for group %s", ip_to_str((guint8*)&maddr));
690 } else { /* IGMP_V2_MEMBERSHIP_REPORT is the only case left */
691 col_append_fstr(pinfo->cinfo, COL_INFO,
692 " group %s", ip_to_str((guint8*)&maddr));
700 /* dissector for version 1 query and report, rfc1054 */
702 dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
704 PRINT_IGMP_VERSION(1);
706 /* skip unused byte */
710 igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
714 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
720 /* dissector for version 0, rfc988 */
722 dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
726 PRINT_IGMP_VERSION(0);
729 code = tvb_get_guint8(tvb, offset);
730 if (type==IGMP_V0_CREATE_GROUP_REQUEST) {
731 proto_tree_add_uint(tree, hf_group_type, tvb, offset, 1, code);
732 } else if (!(type&0x01)) {
734 proto_tree_add_uint(tree, hf_reply_code, tvb, offset, 1, code);
736 proto_tree_add_uint(tree, hf_reply_pending, tvb, offset, 1, code);
742 igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 20);
746 proto_tree_add_item(tree, hf_identifier, tvb, offset, 4, ENC_BIG_ENDIAN);
750 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
754 proto_tree_add_item(tree, hf_access_key, tvb, offset, 8, ENC_NA);
760 /* dissector for multicast traceroute, rfc???? */
762 dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
764 const char *typestr, *blocks = NULL;
767 /* All multicast traceroute packets (Query, Request and
768 * Response) have the same fixed header. Request and Response
769 * have one or more response data blocks following this fixed
770 * header. Since Query and Request share the same IGMP type,
771 * the method to differentiate between them is to check the
772 * IGMP packet length. Queries are only
773 * IGMP_TRACEROUTE_HDR_LEN bytes long.
775 if (type == IGMP_TRACEROUTE_RESPONSE) {
776 int i = (tvb_reported_length_remaining(tvb, offset) - IGMP_TRACEROUTE_HDR_LEN) / IGMP_TRACEROUTE_RSP_LEN;
777 g_snprintf(buf, sizeof buf, ", %d block%s", i, plurality(i, "", "s"));
778 typestr = "Traceroute Response";
780 } else if (tvb_reported_length_remaining(tvb, offset) == IGMP_TRACEROUTE_HDR_LEN)
781 typestr = "Traceroute Query";
783 typestr = "Traceroute Request";
785 col_set_str(pinfo->cinfo, COL_INFO, typestr);
787 col_append_str(pinfo->cinfo, COL_INFO, blocks);
789 proto_tree_add_uint_format(tree, hf_type, tvb, offset, 1, type,
790 "Type: %s (0x%02x)", typestr, type);
793 /* maximum number of hops that the requester wants to trace */
794 proto_tree_add_item(tree, hf_mtrace_max_hops, tvb, offset, 1, ENC_BIG_ENDIAN);
798 igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
801 /* group address to be traced */
802 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
805 /* address of multicast source for the path being traced */
806 proto_tree_add_item(tree, hf_mtrace_saddr, tvb, offset, 4, ENC_BIG_ENDIAN);
809 /* address of multicast receiver for the path being traced */
810 proto_tree_add_item(tree, hf_mtrace_raddr, tvb, offset, 4, ENC_BIG_ENDIAN);
813 /* address where the completed traceroute response packet gets sent */
814 proto_tree_add_item(tree, hf_mtrace_rspaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
817 /* for multicasted responses, TTL at which to multicast the response */
818 proto_tree_add_item(tree, hf_mtrace_resp_ttl, tvb, offset, 1, ENC_BIG_ENDIAN);
821 /* unique identifier for this traceroute request (for e.g. duplicate/delay detection) */
822 proto_tree_add_item(tree, hf_mtrace_q_id, tvb, offset, 3, ENC_BIG_ENDIAN);
825 /* If this was Query, we only had the fixed header */
826 if (tvb_reported_length_remaining(tvb, offset) == 0)
829 /* Loop through the response data blocks */
830 while (tvb_reported_length_remaining(tvb, offset) >= IGMP_TRACEROUTE_RSP_LEN) {
832 proto_tree *block_tree;
834 bi = proto_tree_add_text(tree, tvb, offset, IGMP_TRACEROUTE_RSP_LEN,
835 "Response data block: %s -> %s, Proto: %s, Forwarding Code: %s",
836 tvb_ip_to_str(tvb, offset + 4),
837 tvb_ip_to_str(tvb, offset + 8),
838 val_to_str(tvb_get_guint8(tvb, offset + 28), mtrace_rtg_vals, "Unknown"),
839 val_to_str(tvb_get_guint8(tvb, offset + 31), mtrace_fwd_code_vals, "Unknown"));
840 block_tree = proto_item_add_subtree(bi, ett_mtrace_block);
842 /* Query Arrival Time */
843 proto_tree_add_item(block_tree, hf_mtrace_q_arrival, tvb, offset, 4, ENC_BIG_ENDIAN);
846 /* Incoming Interface Address */
847 proto_tree_add_item(block_tree, hf_mtrace_q_inaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
850 /* Outgoing Interface Address */
851 proto_tree_add_item(block_tree, hf_mtrace_q_outaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
854 /* Previous-Hop Router Address */
855 proto_tree_add_item(block_tree, hf_mtrace_q_prevrtr, tvb, offset, 4, ENC_BIG_ENDIAN);
858 /* Input packet count on incoming interface */
859 proto_tree_add_item(block_tree, hf_mtrace_q_inpkt, tvb, offset, 4, ENC_BIG_ENDIAN);
862 /* Output packet count on outgoing interface */
863 proto_tree_add_item(block_tree, hf_mtrace_q_outpkt, tvb, offset, 4, ENC_BIG_ENDIAN);
866 /* Total number of packets for this source-group pair */
867 proto_tree_add_item(block_tree, hf_mtrace_q_total, tvb, offset, 4, ENC_BIG_ENDIAN);
870 /* Routing protocol in use between this and previous-hop router */
871 proto_tree_add_item(block_tree, hf_mtrace_q_rtg_proto, tvb, offset, 1, ENC_BIG_ENDIAN);
874 /* TTL that a packet is required to be forwarded */
875 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_ttl, tvb, offset, 1, ENC_BIG_ENDIAN);
878 /* Must be zeroed and ignored bit, S bit and src network mask length */
879 proto_tree_add_item(block_tree, hf_mtrace_q_mbz, tvb, offset, 1, ENC_BIG_ENDIAN);
880 proto_tree_add_item(block_tree, hf_mtrace_q_s, tvb, offset, 1, ENC_BIG_ENDIAN);
881 proto_tree_add_item(block_tree, hf_mtrace_q_src_mask, tvb, offset, 1, ENC_BIG_ENDIAN);
884 /* Forwarding information/error code */
885 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_code, tvb, offset, 1, ENC_BIG_ENDIAN);
893 dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
901 item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, ENC_NA);
902 tree = proto_item_add_subtree(item, ett_igmp);
904 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP");
905 col_clear(pinfo->cinfo, COL_INFO);
907 type = tvb_get_guint8(tvb, offset);
911 offset = dissect_igmp_v0(tvb, pinfo, tree, type, offset);
915 case IGMP_V1_HOST_MEMBERSHIP_QUERY: /* 0x11 v1/v2/v3 */
916 if ( (pinfo->iplen-pinfo->iphdrlen)>=12 ) {
918 offset = dissect_igmp_v3_query(tvb, pinfo, tree, type, offset);
920 /* v1 and v2 differs in second byte of header */
921 if (tvb_get_guint8(tvb, offset+1)) {
922 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
924 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
929 case IGMP_V1_HOST_MEMBERSHIP_REPORT: /* 0x12 v1 only */
930 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
934 offset = dissect_dvmrp(tvb, pinfo, parent_tree, offset);
937 case IGMP_V1_PIM_ROUTING_MESSAGE:
938 offset = dissect_pimv1(tvb, pinfo, parent_tree, offset);
941 case IGMP_V2_MEMBERSHIP_REPORT:
942 case IGMP_V2_LEAVE_GROUP:
943 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
946 case IGMP_TRACEROUTE_RESPONSE:
947 case IGMP_TRACEROUTE_QUERY_REQ:
948 offset = dissect_igmp_mtrace(tvb, pinfo, tree, type, offset);
951 case IGMP_V3_MEMBERSHIP_REPORT:
952 offset = dissect_igmp_v3_report(tvb, pinfo, tree, type, offset);
956 dst = g_htonl(MC_ALL_IGMPV3_ROUTERS);
957 if (!memcmp(pinfo->dst.data, &dst, 4)) {
958 offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
963 dst = g_htonl(MC_ALL_ROUTERS);
964 if (!memcmp(pinfo->dst.data, &dst, 4)) {
965 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
967 dst = g_htonl(MC_ALL_IGMPV3_ROUTERS);
968 if (!memcmp(pinfo->dst.data, &dst, 4)) {
969 offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
974 if ( (pinfo->iplen-pinfo->iphdrlen)>=8 ) {
975 /* if len of igmp packet>=8 we assume it is MSNIP */
976 offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
978 /* ok its not MSNIP, check if it might be MRDISC */
979 dst = g_htonl(MC_ALL_ROUTERS);
980 if (!memcmp(pinfo->dst.data, &dst, 4)) {
981 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
987 dst = g_htonl(MC_ALL_ROUTERS);
988 if (!memcmp(pinfo->dst.data, &dst, 4)) {
989 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
994 case IGMP_IGAP_QUERY:
995 case IGMP_IGAP_LEAVE:
996 offset = dissect_igap(tvb, pinfo, parent_tree, offset);
999 case IGMP_RGMP_HELLO:
1001 case IGMP_RGMP_JOIN:
1002 case IGMP_RGMP_LEAVE:
1003 dst = g_htonl(MC_RGMP);
1004 if (!memcmp(pinfo->dst.data, &dst, 4)) {
1005 offset = dissect_rgmp(tvb, pinfo, parent_tree, offset);
1010 offset = dissect_igmp_unknown(tvb, pinfo, tree, type, offset);
1014 proto_item_set_len(item, offset);
1018 proto_register_igmp(void)
1020 static hf_register_info hf[] = {
1022 { "Type", "igmp.type", FT_UINT8, BASE_HEX,
1023 VALS(commands), 0, "IGMP Packet Type", HFILL }},
1026 { "IGMP Version", "igmp.version", FT_UINT8, BASE_DEC,
1027 NULL, 0, NULL, HFILL }},
1030 { "Type Of Group", "igmp.group_type", FT_UINT8, BASE_DEC,
1031 VALS(vs_group_type), 0, "IGMP V0 Type Of Group", HFILL }},
1034 { "Reply", "igmp.reply", FT_UINT8, BASE_DEC,
1035 VALS(vs_reply_code), 0, "IGMP V0 Reply", HFILL }},
1037 { &hf_reply_pending,
1038 { "Reply Pending", "igmp.reply.pending", FT_UINT8, BASE_DEC,
1039 NULL, 0, "IGMP V0 Reply Pending, Retry in this many seconds", HFILL }},
1042 { "Checksum", "igmp.checksum", FT_UINT16, BASE_HEX,
1043 NULL, 0, "IGMP Checksum", HFILL }},
1046 { "Bad Checksum", "igmp.checksum_bad", FT_BOOLEAN, BASE_NONE,
1047 NULL, 0x0, "Bad IGMP Checksum", HFILL }},
1050 { "Identifier", "igmp.identifier", FT_UINT32, BASE_DEC,
1051 NULL, 0, "IGMP V0 Identifier", HFILL }},
1054 { "Access Key", "igmp.access_key", FT_BYTES, BASE_NONE,
1055 NULL, 0, "IGMP V0 Access Key", HFILL }},
1058 { "Max Resp Time", "igmp.max_resp", FT_UINT8, BASE_DEC,
1059 NULL, 0, "Max Response Time", HFILL }},
1062 { "S", "igmp.s", FT_BOOLEAN, 8,
1063 TFS(&tfs_s), IGMP_V3_S, "Suppress Router Side Processing", HFILL }},
1066 { "QRV", "igmp.qrv", FT_UINT8, BASE_DEC,
1067 NULL, IGMP_V3_QRV_MASK, "Querier's Robustness Value", HFILL }},
1070 { "QQIC", "igmp.qqic", FT_UINT8, BASE_DEC,
1071 NULL, 0, "Querier's Query Interval Code", HFILL }},
1074 { "Num Src", "igmp.num_src", FT_UINT16, BASE_DEC,
1075 NULL, 0, "Number Of Sources", HFILL }},
1078 { "Source Address", "igmp.saddr", FT_IPv4, BASE_NONE,
1079 NULL, 0, NULL, HFILL }},
1082 { "Num Group Records", "igmp.num_grp_recs", FT_UINT16, BASE_DEC,
1083 NULL, 0, "Number Of Group Records", HFILL }},
1086 { "Record Type", "igmp.record_type", FT_UINT8, BASE_DEC,
1087 VALS(vs_record_type), 0, NULL, HFILL }},
1090 { "Aux Data Len", "igmp.aux_data_len", FT_UINT8, BASE_DEC,
1091 NULL, 0, "Aux Data Len, In units of 32bit words", HFILL }},
1094 { "Multicast Address", "igmp.maddr", FT_IPv4, BASE_NONE,
1095 NULL, 0, NULL, HFILL }},
1098 { "Aux Data", "igmp.aux_data", FT_BYTES, BASE_NONE,
1099 NULL, 0, "IGMP V3 Auxiliary Data", HFILL }},
1102 { "Exponent", "igmp.max_resp.exp", FT_UINT8, BASE_HEX,
1103 NULL, IGMP_MAX_RESP_EXP, "Maximum Response Time, Exponent", HFILL }},
1105 { &hf_max_resp_mant,
1106 { "Mantissa", "igmp.max_resp.mant", FT_UINT8, BASE_HEX,
1107 NULL, IGMP_MAX_RESP_MANT, "Maximum Response Time, Mantissa", HFILL }},
1109 { &hf_mtrace_max_hops,
1110 { "# hops", "igmp.mtrace.max_hops", FT_UINT8, BASE_DEC,
1111 NULL, 0, "Maximum Number of Hops to Trace", HFILL }},
1114 { "Source Address", "igmp.mtrace.saddr", FT_IPv4, BASE_NONE,
1115 NULL, 0, "Multicast Source for the Path Being Traced", HFILL }},
1118 { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4, BASE_NONE,
1119 NULL, 0, "Multicast Receiver for the Path Being Traced", HFILL }},
1121 { &hf_mtrace_rspaddr,
1122 { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4, BASE_NONE,
1123 NULL, 0, "Destination of Completed Traceroute Response", HFILL }},
1125 { &hf_mtrace_resp_ttl,
1126 { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8, BASE_DEC,
1127 NULL, 0, "TTL for Multicasted Responses", HFILL }},
1130 { "Query ID", "igmp.mtrace.q_id", FT_UINT24, BASE_DEC,
1131 NULL, 0, "Identifier for this Traceroute Request", HFILL }},
1133 { &hf_mtrace_q_arrival,
1134 { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32, BASE_DEC,
1135 NULL, 0, "Query Arrival Time", HFILL }},
1137 { &hf_mtrace_q_inaddr,
1138 { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4, BASE_NONE,
1139 NULL, 0, "Incoming Interface Address", HFILL }},
1141 { &hf_mtrace_q_outaddr,
1142 { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4, BASE_NONE,
1143 NULL, 0, "Outgoing Interface Address", HFILL }},
1145 { &hf_mtrace_q_prevrtr,
1146 { "Previous rtr addr", "igmp.mtrace.q_prevrtr", FT_IPv4, BASE_NONE,
1147 NULL, 0, "Previous-Hop Router Address", HFILL }},
1149 { &hf_mtrace_q_inpkt,
1150 { "In pkts", "igmp.mtrace.q_inpkt", FT_UINT32, BASE_DEC,
1151 NULL, 0, "Input packet count on incoming interface", HFILL }},
1153 { &hf_mtrace_q_outpkt,
1154 { "Out pkts", "igmp.mtrace.q_outpkt", FT_UINT32, BASE_DEC,
1155 NULL, 0, "Output packet count on outgoing interface", HFILL }},
1157 { &hf_mtrace_q_total,
1158 { "S,G pkt count", "igmp.mtrace.q_total", FT_UINT32, BASE_DEC,
1159 NULL, 0, "Total number of packets for this source-group pair", HFILL }},
1161 { &hf_mtrace_q_rtg_proto,
1162 { "Rtg Protocol", "igmp.mtrace.q_rtg_proto", FT_UINT8, BASE_DEC,
1163 VALS(mtrace_rtg_vals), 0, "Routing protocol between this and previous hop rtr", HFILL }},
1165 { &hf_mtrace_q_fwd_ttl,
1166 { "FwdTTL", "igmp.mtrace.q_fwd_ttl", FT_UINT8, BASE_DEC,
1167 NULL, 0, "TTL required for forwarding", HFILL }},
1170 { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8, BASE_HEX,
1171 NULL, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL }},
1174 { "S", "igmp.mtrace.q_s", FT_UINT8, BASE_HEX,
1175 NULL, 0x40, "Set if S,G packet count is for source network", HFILL }},
1177 { &hf_mtrace_q_src_mask,
1178 { "Src Mask", "igmp.mtrace.q_src_mask", FT_UINT8, BASE_HEX,
1179 NULL, 0x3F, "Source mask length. 63 when forwarding on group state", HFILL }},
1181 { &hf_mtrace_q_fwd_code,
1182 { "Forwarding Code", "igmp.mtrace.q_fwd_code", FT_UINT8, BASE_HEX,
1183 VALS(mtrace_fwd_code_vals), 0, "Forwarding information/error code", HFILL }},
1186 static gint *ett[] = {
1194 proto_igmp = proto_register_protocol("Internet Group Management Protocol",
1196 proto_register_field_array(proto_igmp, hf, array_length(hf));
1197 proto_register_subtree_array(ett, array_length(ett));
1201 proto_reg_handoff_igmp(void)
1203 dissector_handle_t igmp_handle;
1205 igmp_handle = create_dissector_handle(dissect_igmp, proto_igmp);
1206 dissector_add_uint("ip.proto", IP_PROTO_IGMP, igmp_handle);
1210 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1215 * indent-tabs-mode: t
1218 * vi: set shiftwidth=4 tabstop=8 noexpandtab:
1219 * :indentSize=4:tabSize=8:noTabs=false: