1 /* packet-igmp.c 2001 Ronnie Sahlberg <rsahlber@bigpond.net.au>
2 * Routines for IGMP packet disassembly
4 * $Id: packet-igmp.c,v 1.12 2001/07/12 07:05:33 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 IGMP is defined in the following RFCs
26 RFC988 Version 0 Obsolete
28 RFC1112 Version 1 (same as RFC1054 as far as we are concerned)
30 draft-ietf-idmr-igmp-v3-07 Version 3
32 Size in bytes for each packet
33 type RFC988 RFC1054 RFC2236 RFC???? DVMRP MRDISC MSNIP
55 * Differs in second byte of protocol. Always 0 in V1
58 Multicast traceroute was taken from
59 draft-ietf-idmr-traceroute-ipm-07.txt
61 Size in bytes for each packet
62 type draft-ietf-idmr-traceroute-ipm-07.ps
64 0x1f 24 + n*32 (n == 0 for Query)
66 x DVMRP Protocol see packet-dvmrp.c
68 DVMRP is defined in the following RFCs
70 draft-ietf-idmr-dvmrp-v3-10.txt Version 3
72 V1 and V3 can be distinguished by looking at bytes 6 and 7 in the
74 If header[6]==0xff and header[7]==0x03 we have version 3.
76 a MRDISC Protocol see packet-mrdisc.c
78 MRDISC : IGMP Multicast Router DISCovery
79 draft-ietf-idmr-igmp-mrdisc-06.txt
80 TTL == 1 and IP.DST==224.0.0.2 for all packets
82 b MSNIP Protocol see packet-msnip.c
84 MSNIP : Multicast Source Notification of Interest Protocol
85 draft-ietf-idmr-msnip-00.txt
86 0x23, 0x24 are sent with ip.dst==224.0.0.22
87 0x25 is sent as unicast.
95 #ifdef HAVE_SYS_TYPES_H
96 # include <sys/types.h>
103 #ifdef NEED_SNPRINTF_H
104 # include "snprintf.h"
109 #include "in_cksum.h"
110 #include "packet-dvmrp.h"
111 #include "packet-pim.h"
112 #include "packet-mrdisc.h"
113 #include "packet-msnip.h"
115 static int proto_igmp = -1;
116 static int hf_type = -1;
117 static int hf_version = -1;
118 static int hf_group_type = -1;
119 static int hf_reply_code = -1;
120 static int hf_reply_pending = -1;
121 static int hf_checksum = -1;
122 static int hf_checksum_bad = -1;
123 static int hf_identifier = -1;
124 static int hf_access_key = -1;
125 static int hf_max_resp = -1;
126 static int hf_max_resp_exp = -1;
127 static int hf_max_resp_mant = -1;
128 static int hf_supress = -1;
129 static int hf_qrv = -1;
130 static int hf_qqic = -1;
131 static int hf_num_src = -1;
132 static int hf_saddr = -1;
133 static int hf_num_grp_recs = -1;
134 static int hf_record_type = -1;
135 static int hf_aux_data_len = -1;
136 static int hf_maddr = -1;
137 static int hf_aux_data = -1;
138 static int hf_mtrace_max_hops = -1;
139 static int hf_mtrace_saddr = -1;
140 static int hf_mtrace_raddr = -1;
141 static int hf_mtrace_rspaddr = -1;
142 static int hf_mtrace_resp_ttl = -1;
143 static int hf_mtrace_q_id = -1;
144 static int hf_mtrace_q_arrival = -1;
145 static int hf_mtrace_q_inaddr = -1;
146 static int hf_mtrace_q_outaddr = -1;
147 static int hf_mtrace_q_prevrtr = -1;
148 static int hf_mtrace_q_inpkt = -1;
149 static int hf_mtrace_q_outpkt = -1;
150 static int hf_mtrace_q_total = -1;
151 static int hf_mtrace_q_rtg_proto = -1;
152 static int hf_mtrace_q_fwd_ttl = -1;
153 static int hf_mtrace_q_mbz = -1;
154 static int hf_mtrace_q_s = -1;
155 static int hf_mtrace_q_src_mask = -1;
156 static int hf_mtrace_q_fwd_code = -1;
158 static int ett_igmp = -1;
159 static int ett_group_record = -1;
160 static int ett_sqrv_bits = -1;
161 static int ett_max_resp = -1;
162 static int ett_mtrace_block = -1;
164 #define MC_ALL_ROUTERS 0xe0000002
165 #define MC_ALL_IGMPV3_ROUTERS 0xe0000016
168 #define IGMP_V0_CREATE_GROUP_REQUEST 0x01
169 #define IGMP_V0_CREATE_GROUP_REPLY 0x02
170 #define IGMP_V0_JOIN_GROUP_REQUEST 0x03
171 #define IGMP_V0_JOIN_GROUP_REPLY 0x04
172 #define IGMP_V0_LEAVE_GROUP_REQUEST 0x05
173 #define IGMP_V0_LEAVE_GROUP_REPLY 0x06
174 #define IGMP_V0_CONFIRM_GROUP_REQUEST 0x07
175 #define IGMP_V0_CONFIRM_GROUP_REPLY 0x08
176 #define IGMP_V1_HOST_MEMBERSHIP_QUERY 0x11
177 #define IGMP_V1_HOST_MEMBERSHIP_REPORT 0x12
178 #define IGMP_DVMRP 0x13
179 #define IGMP_V1_PIM_ROUTING_MESSAGE 0x14
180 #define IGMP_V2_MEMBERSHIP_REPORT 0x16
181 #define IGMP_V2_LEAVE_GROUP 0x17
182 #define IGMP_TRACEROUTE_RESPONSE 0x1e
183 #define IGMP_TRACEROUTE_QUERY_REQ 0x1f
184 #define IGMP_V3_MEMBERSHIP_REPORT 0x22
185 #define IGMP_TYPE_0x23 0x23
186 #define IGMP_TYPE_0x24 0x24
187 #define IGMP_TYPE_0x25 0x25
188 #define IGMP_TYPE_0x26 0x26
190 #define IGMP_TRACEROUTE_HDR_LEN 24
191 #define IGMP_TRACEROUTE_RSP_LEN 32
193 static const value_string commands[] = {
194 {IGMP_V0_CREATE_GROUP_REQUEST, "Create Group Request" },
195 {IGMP_V0_CREATE_GROUP_REPLY, "Create Group Reply" },
196 {IGMP_V0_JOIN_GROUP_REQUEST, "Join Group Request" },
197 {IGMP_V0_JOIN_GROUP_REPLY, "Join Group Reply" },
198 {IGMP_V0_LEAVE_GROUP_REQUEST, "Leave Group Request" },
199 {IGMP_V0_LEAVE_GROUP_REPLY, "Leave Group Reply" },
200 {IGMP_V0_CONFIRM_GROUP_REQUEST, "Confirm Group Request" },
201 {IGMP_V0_CONFIRM_GROUP_REPLY, "Confirm Group Reply" },
202 {IGMP_V1_HOST_MEMBERSHIP_QUERY, "Membership Query" },
203 {IGMP_V1_HOST_MEMBERSHIP_REPORT,"Membership Report" },
204 {IGMP_DVMRP, "DVMRP Protocol" },
205 {IGMP_V1_PIM_ROUTING_MESSAGE, "PIM Routing Message" },
206 {IGMP_V2_MEMBERSHIP_REPORT, "Membership Report" },
207 {IGMP_V2_LEAVE_GROUP, "Leave Group" },
208 {IGMP_TRACEROUTE_RESPONSE, "Traceroute Response" },
209 {IGMP_TRACEROUTE_QUERY_REQ, "Traceroute Query or Request" },
210 {IGMP_V3_MEMBERSHIP_REPORT, "Membership Report" },
214 #define IGMP_V3_S 0x08
215 #define IGMP_V3_QRV_MASK 0x07
217 #define IGMP_MAX_RESP_EXP 0x70
218 #define IGMP_MAX_RESP_MANT 0x0f
220 #define IGMP_V0_GROUP_PUBLIC 0x00
221 #define IGMP_V0_GROUP_PRIVATE 0x01
223 static const value_string vs_group_type[] = {
224 {IGMP_V0_GROUP_PUBLIC, "Public Group" },
225 {IGMP_V0_GROUP_PRIVATE, "Private Group" },
229 #define IGMP_V0_REPLY_GRANTED 0x00
230 #define IGMP_V0_REPLY_NO_RESOURCES 0x01
231 #define IGMP_V0_REPLY_INVALID_CODE 0x02
232 #define IGMP_V0_REPLY_INVALID_GROUP 0x03
233 #define IGMP_V0_REPLY_INVALID_KEY 0x04
235 static const value_string vs_reply_code[] = {
236 {IGMP_V0_REPLY_GRANTED, "Request Granted" },
237 {IGMP_V0_REPLY_NO_RESOURCES, "Request Denied, No Resources" },
238 {IGMP_V0_REPLY_INVALID_CODE, "Request Denied, Invalid Code" },
239 {IGMP_V0_REPLY_INVALID_GROUP, "Request Denied, Invalid Group" },
240 {IGMP_V0_REPLY_INVALID_KEY, "Request Denied, Invalid Key" },
244 static const true_false_string tfs_s = {
245 "SUPRESS router side processing",
246 "Do not supress router side processing"
249 #define IGMP_V3_MODE_IS_INCLUDE 1
250 #define IGMP_V3_MODE_IS_EXCLUDE 2
251 #define IGMP_V3_CHANGE_TO_INCLUDE_MODE 3
252 #define IGMP_V3_CHANGE_TO_EXCLUDE_MODE 4
253 #define IGMP_V3_ALLOW_NEW_SOURCES 5
254 #define IGMP_V3_BLOCK_OLD_SOURCES 6
256 static const value_string vs_record_type[] = {
257 {IGMP_V3_MODE_IS_INCLUDE, "Mode Is Include" },
258 {IGMP_V3_MODE_IS_EXCLUDE, "Mode Is Exclude" },
259 {IGMP_V3_CHANGE_TO_INCLUDE_MODE,"Change To Include Mode" },
260 {IGMP_V3_CHANGE_TO_EXCLUDE_MODE,"Change To Exclude Mode" },
261 {IGMP_V3_ALLOW_NEW_SOURCES, "Allow New Sources" },
262 {IGMP_V3_BLOCK_OLD_SOURCES, "Block Old Sources" },
266 static const value_string mtrace_rtg_vals[] = {
271 {5, "PIM using special routing table" },
272 {6, "PIM using a static route" },
273 {7, "DVMRP using a static route" },
274 {8, "PIM using MBGP (aka BGP4+) route" },
275 {9, "CBT using special routing table" },
276 {10, "CBT using a static route" },
277 {11, "PIM using state created by Assert processing" },
281 static const value_string mtrace_fwd_code_vals[] = {
284 {0x02, "PRUNE_SENT" },
285 {0x03, "PRUNE_RCVD" },
288 {0x06, "WRONG_LAST_HOP" },
289 {0x07, "NOT_FORWARDING" },
290 {0x08, "REACHED_RP" },
292 {0x0A, "NO_MULTICAST" },
293 {0x0B, "INFO_HIDDEN" },
295 {0x82, "OLD_ROUTER" },
296 {0x83, "ADMIN_PROHIB" },
300 #define PRINT_IGMP_VERSION(version) \
301 if (check_col(pinfo->fd, COL_INFO)) { \
302 col_add_fstr(pinfo->fd, COL_INFO, \
303 "V%d %s",version,val_to_str(type, commands, \
304 "Unknown Type:0x%02x")); \
306 /* version of IGMP protocol */ \
307 proto_tree_add_uint(tree, hf_version, tvb, 0, 0, version); \
308 /* type of command */ \
309 proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type); \
312 static void igmp_checksum(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
315 guint16 cksum, hdrcksum;
320 * Checksum the entire IGMP packet.
322 len = tvb_reported_length(tvb);
325 hdrcksum = tvb_get_ntohs(tvb, 2);
326 if (!pinfo->fragmented && tvb_length(tvb) >= len) {
328 * The packet isn't part of a fragmented datagram and isn't
329 * truncated, so we can checksum it.
331 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, len);
332 cksum_vec[0].len = len;
334 cksum = in_cksum(&cksum_vec[0],1);
337 proto_tree_add_uint_format(tree, hf_checksum,
339 "Header checksum: 0x%04x (correct)", hdrcksum);
341 proto_tree_add_item_hidden(tree, hf_checksum_bad,
343 proto_tree_add_uint_format(tree, hf_checksum,
345 "Header checksum: 0x%04x (incorrect, should be 0x%04x)", hdrcksum,in_cksum_shouldbe(hdrcksum,cksum));
348 proto_tree_add_uint(tree, hf_checksum, tvb, 2, 2, hdrcksum);
354 /* Unknown IGMP message type */
356 dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
360 if (check_col(pinfo->fd, COL_INFO)) {
361 col_add_str(pinfo->fd, COL_INFO,
362 val_to_str(type, commands, "Unknown Type:0x%02x"));
365 /* type of command */
366 proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);
369 /* Just call the rest of it "data" */
370 len = tvb_length_remaining(tvb, offset);
371 proto_tree_add_text(tree, tvb, offset, len, "Data");
379 /*************************************************************
380 * IGMP Protocol dissectors
381 *************************************************************/
383 dissect_v3_max_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
390 bits = tvb_get_guint8(tvb, offset);
392 tsecs = ((bits&IGMP_MAX_RESP_MANT)|0x10);
393 tsecs = tsecs << ( ((bits&IGMP_MAX_RESP_EXP)>>4) + 3);
398 item = proto_tree_add_uint_format(parent_tree, hf_max_resp, tvb,
399 offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)",tsecs*0.1,bits);
402 tree = proto_item_add_subtree(item, ett_max_resp);
404 proto_tree_add_uint(tree, hf_max_resp_exp, tvb, offset, 1,
406 proto_tree_add_uint(tree, hf_max_resp_mant, tvb, offset, 1,
416 dissect_v3_sqrv_bits(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
422 bits = tvb_get_guint8(tvb, offset);
424 item = proto_tree_add_text(parent_tree, tvb, offset, 1,
425 "QRV=%d S=%s", bits&IGMP_V3_QRV_MASK,
426 (bits&IGMP_V3_S)?tfs_s.true_string:tfs_s.false_string);
427 tree = proto_item_add_subtree(item, ett_sqrv_bits);
430 proto_tree_add_boolean(tree, hf_supress, tvb, offset, 1, bits);
432 proto_tree_add_uint(tree, hf_qrv, tvb, offset, 1, bits);
439 dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
443 int old_offset = offset;
448 tvb_memcpy(tvb, (guint8 *)&ip, offset+4, 4);
449 item = proto_tree_add_text(parent_tree, tvb, offset, 0,
450 "Group Record : %s %s",
451 ip_to_str((gchar*)&ip),
452 val_to_str(tvb_get_guint8(tvb, offset), vs_record_type,"")
454 tree = proto_item_add_subtree(item, ett_group_record);
457 proto_tree_add_item(tree, hf_record_type, tvb, offset, 1, FALSE);
461 adl = tvb_get_guint8(tvb, offset);
462 proto_tree_add_uint(tree, hf_aux_data_len, tvb, offset, 1, adl);
465 /*number of sources*/
466 num = tvb_get_ntohs(tvb, offset);
467 proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
470 /* multicast address */
471 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
474 /* source addresses */
476 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, FALSE);
482 proto_tree_add_item(tree, hf_aux_data, tvb, offset, adl*4,
487 proto_item_set_len(item, offset-old_offset);
491 /* dissectors for version 3, rfc???? */
493 dissect_igmp_v3_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
497 PRINT_IGMP_VERSION(3);
499 /* skip reserved field*/
503 igmp_checksum(tree, tvb, pinfo, 0);
506 /* skip reserved field */
509 /* number of group records */
510 num = tvb_get_ntohs(tvb, offset);
511 proto_tree_add_uint(tree, hf_num_grp_recs, tvb, offset, 2, num);
515 offset = dissect_v3_group_record(tvb,pinfo,tree,offset);
522 dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
526 PRINT_IGMP_VERSION(3);
528 num = tvb_get_ntohs(tvb, offset+9);
530 offset = dissect_v3_max_resp(tvb, pinfo, tree, offset);
533 igmp_checksum(tree, tvb, pinfo, 0);
537 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
540 /* bitmask for S and QRV */
541 offset = dissect_v3_sqrv_bits(tvb, pinfo, tree, offset);
544 proto_tree_add_item(tree, hf_qqic, tvb, offset, 1, FALSE);
547 /*number of sources*/
548 proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
552 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, FALSE);
559 /* dissector for version 2, rfc2236 */
561 dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
565 PRINT_IGMP_VERSION(2);
568 tsecs = tvb_get_guint8(tvb, offset);
569 proto_tree_add_uint_format(tree, hf_max_resp, tvb,
570 offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)", tsecs*0.1,tsecs);
574 igmp_checksum(tree, tvb, pinfo, 8);
578 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
584 /* dissector for version 1, rfc1054 */
586 dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
588 PRINT_IGMP_VERSION(1);
590 /* skip unused byte */
594 igmp_checksum(tree, tvb, pinfo, 8);
598 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
604 /* dissector for version 0, rfc988 */
606 dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
610 PRINT_IGMP_VERSION(0);
613 code = tvb_get_guint8(tvb, offset);
614 if (type==IGMP_V0_CREATE_GROUP_REQUEST) {
615 proto_tree_add_uint(tree, hf_group_type, tvb, offset, 1, code);
616 } else if (!(type&0x01)) {
618 proto_tree_add_uint(tree, hf_reply_code, tvb, offset, 1, code);
620 proto_tree_add_uint(tree, hf_reply_pending, tvb, offset, 1, code);
626 igmp_checksum(tree, tvb, pinfo, 20);
630 proto_tree_add_item(tree, hf_identifier, tvb, offset, 4, FALSE);
634 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
638 proto_tree_add_item(tree, hf_access_key, tvb, offset, 8, FALSE);
644 /* dissector for multicast traceroute, rfc???? */
646 dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
648 char *typestr, *blocks = NULL;
651 /* All multicast traceroute packets (Query, Request and
652 * Response) have the same fixed header. Request and Response
653 * have one or more response data blocks following this fixed
654 * header. Since Query and Request share the same IGMP type,
655 * the method to differentiate between them is to check the
656 * IGMP packet length. Queries are only
657 * IGMP_TRACEROUTE_HDR_LEN bytes long.
659 if (type == IGMP_TRACEROUTE_RESPONSE) {
660 int i = (tvb_reported_length_remaining(tvb, offset) - IGMP_TRACEROUTE_HDR_LEN) / IGMP_TRACEROUTE_RSP_LEN;
661 snprintf(buf, sizeof buf, ", %d block%s", i, plurality(i, "", "s"));
662 typestr = "Traceroute Response";
664 } else if (tvb_reported_length_remaining(tvb, offset) == IGMP_TRACEROUTE_HDR_LEN)
665 typestr = "Traceroute Query";
667 typestr = "Traceroute Request";
669 if (check_col(pinfo->fd, COL_INFO)) {
670 col_set_str(pinfo->fd, COL_INFO, typestr);
671 if (blocks) col_append_str(pinfo->fd, COL_INFO, blocks);
674 proto_tree_add_uint_format(tree, hf_type, tvb, offset, 1, type,
675 "Type: %s (0x%02x)", typestr, type);
678 /* maximum number of hops that the requester wants to trace */
679 proto_tree_add_item(tree, hf_mtrace_max_hops, tvb, offset, 1, FALSE);
683 igmp_checksum(tree, tvb, pinfo, 0);
686 /* group address to be traced */
687 proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
690 /* address of multicast source for the path being traced */
691 proto_tree_add_item(tree, hf_mtrace_saddr, tvb, offset, 4, FALSE);
694 /* address of multicast receiver for the path being traced */
695 proto_tree_add_item(tree, hf_mtrace_raddr, tvb, offset, 4, FALSE);
698 /* address where the completed traceroute response packet gets sent */
699 proto_tree_add_item(tree, hf_mtrace_rspaddr, tvb, offset, 4, FALSE);
702 /* for multicasted responses, TTL at which to multicast the response */
703 proto_tree_add_item(tree, hf_mtrace_resp_ttl, tvb, offset, 1, FALSE);
706 /* unique identifier for this traceroute request (for e.g. duplicate/delay detection) */
707 proto_tree_add_item(tree, hf_mtrace_q_id, tvb, offset, 3, FALSE);
710 /* If this was Query, we only had the fixed header */
711 if (tvb_reported_length_remaining(tvb, offset) == 0)
714 /* Loop through the response data blocks */
715 while (tvb_reported_length_remaining(tvb, offset) >= IGMP_TRACEROUTE_RSP_LEN) {
717 proto_tree *block_tree;
719 bi = proto_tree_add_text(tree, tvb, offset, IGMP_TRACEROUTE_RSP_LEN,
720 "Response data block: %s -> %s, Proto: %s, Forwarding Code: %s",
721 ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)),
722 ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)),
723 val_to_str(tvb_get_guint8(tvb, offset + 28), mtrace_rtg_vals, "Unknown"),
724 val_to_str(tvb_get_guint8(tvb, offset + 31), mtrace_fwd_code_vals, "Unknown"));
725 block_tree = proto_item_add_subtree(bi, ett_mtrace_block);
727 /* Query Arrival Time */
728 proto_tree_add_item(block_tree, hf_mtrace_q_arrival, tvb, offset, 4, FALSE);
731 /* Incoming Interface Address */
732 proto_tree_add_item(block_tree, hf_mtrace_q_inaddr, tvb, offset, 4, FALSE);
735 /* Outgoing Interface Address */
736 proto_tree_add_item(block_tree, hf_mtrace_q_outaddr, tvb, offset, 4, FALSE);
739 /* Previous-Hop Router Address */
740 proto_tree_add_item(block_tree, hf_mtrace_q_prevrtr, tvb, offset, 4, FALSE);
743 /* Input packet count on incoming interface */
744 proto_tree_add_item(block_tree, hf_mtrace_q_inpkt, tvb, offset, 4, FALSE);
747 /* Output packet count on outgoing interface */
748 proto_tree_add_item(block_tree, hf_mtrace_q_outpkt, tvb, offset, 4, FALSE);
751 /* Total number of packets for this source-group pair */
752 proto_tree_add_item(block_tree, hf_mtrace_q_total, tvb, offset, 4, FALSE);
755 /* Routing protocol in use between this and previous-hop router */
756 proto_tree_add_item(block_tree, hf_mtrace_q_rtg_proto, tvb, offset, 1, FALSE);
759 /* TTL that a packet is required to be forwarded */
760 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_ttl, tvb, offset, 1, FALSE);
763 /* Must be zeroed and ignored bit, S bit and src network mask length */
764 proto_tree_add_item(block_tree, hf_mtrace_q_mbz, tvb, offset, 1, FALSE);
765 proto_tree_add_item(block_tree, hf_mtrace_q_s, tvb, offset, 1, FALSE);
766 proto_tree_add_item(block_tree, hf_mtrace_q_src_mask, tvb, offset, 1, FALSE);
769 /* Forwarding information/error code */
770 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_code, tvb, offset, 1, FALSE);
779 dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
787 item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, 0, FALSE);
788 tree = proto_item_add_subtree(item, ett_igmp);
791 if (check_col(pinfo->fd, COL_PROTOCOL)) {
792 col_set_str(pinfo->fd, COL_PROTOCOL, "IGMP");
794 if (check_col(pinfo->fd, COL_INFO)) {
795 col_clear(pinfo->fd, COL_INFO);
799 type = tvb_get_guint8(tvb, offset);
804 offset = dissect_igmp_v0(tvb, pinfo, tree, type, offset);
810 case IGMP_V1_HOST_MEMBERSHIP_QUERY: /* 0x11 v1/v2/v3 */
811 if ( (pinfo->iplen-pinfo->iphdrlen*4)>=12 ) {
813 offset = dissect_igmp_v3_query(tvb, pinfo, tree, type, offset);
815 /* v1 and v2 differs in second byte of header */
816 if (tvb_get_guint8(tvb, offset)) {
817 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
819 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
824 case IGMP_V1_HOST_MEMBERSHIP_REPORT: /* 0x12 v1/v2 */
825 /* v1 and v2 differs in second byte of header */
826 if (tvb_get_guint8(tvb, offset)) {
827 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
829 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
834 offset = dissect_dvmrp(tvb, pinfo, parent_tree, offset);
837 case IGMP_V1_PIM_ROUTING_MESSAGE:
838 offset = dissect_pimv1(tvb, pinfo, parent_tree, offset);
841 case IGMP_V2_MEMBERSHIP_REPORT:
842 case IGMP_V2_LEAVE_GROUP:
843 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
846 case IGMP_TRACEROUTE_RESPONSE:
847 case IGMP_TRACEROUTE_QUERY_REQ:
848 offset = dissect_igmp_mtrace(tvb, pinfo, tree, type, offset);
851 case IGMP_V3_MEMBERSHIP_REPORT:
852 offset = dissect_igmp_v3_response(tvb, pinfo, tree, type, offset);
856 dst = htonl(MC_ALL_IGMPV3_ROUTERS);
857 if (!memcmp(pinfo->dst.data, &dst, 4)) {
858 offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
863 dst = htonl(MC_ALL_ROUTERS);
864 if (!memcmp(pinfo->dst.data, &dst, 4)) {
865 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
867 dst = htonl(MC_ALL_IGMPV3_ROUTERS);
868 if (!memcmp(pinfo->dst.data, &dst, 4)) {
869 offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
874 if ( (pinfo->iplen-pinfo->iphdrlen*4)>=8 ) {
875 /* if len of igmp packet>=8 we assume it is MSNIP */
876 offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
878 /* ok its not MSNIP, check if it might be MRDISC */
879 dst = htonl(MC_ALL_ROUTERS);
880 if (!memcmp(pinfo->dst.data, &dst, 4)) {
881 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
887 dst = htonl(MC_ALL_ROUTERS);
888 if (!memcmp(pinfo->dst.data, &dst, 4)) {
889 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
894 offset = dissect_igmp_unknown(tvb, pinfo, tree, type, offset);
899 proto_item_set_len(item, offset);
903 proto_register_igmp(void)
905 static hf_register_info hf[] = {
907 { "Type", "igmp.type", FT_UINT8, BASE_HEX,
908 VALS(commands), 0, "IGMP Packet Type", HFILL }},
911 { "IGMP Version", "igmp.version", FT_UINT8, BASE_DEC,
912 NULL, 0, "IGMP Version", HFILL }},
915 { "Type Of Group", "igmp.group_type", FT_UINT8, BASE_DEC,
916 VALS(vs_group_type), 0, "IGMP V0 Type Of Group", HFILL }},
919 { "Reply", "igmp.reply", FT_UINT8, BASE_DEC,
920 VALS(vs_reply_code), 0, "IGMP V0 Reply", HFILL }},
923 { "Reply Pending", "igmp.reply.pending", FT_UINT8, BASE_DEC,
924 NULL, 0, "IGMP V0 Reply Pending, Retry in this many seconds", HFILL }},
927 { "Checksum", "igmp.checksum", FT_UINT16, BASE_HEX,
928 NULL, 0, "IGMP Checksum", HFILL }},
931 { "Bad Checksum", "igmp.checksum_bad", FT_BOOLEAN, BASE_NONE,
932 NULL, 0, "Bad IGMP Checksum", HFILL }},
935 { "Identifier", "igmp.identifier", FT_UINT32, BASE_DEC,
936 NULL, 0, "IGMP V0 Identifier", HFILL }},
939 { "Access Key", "igmp.access_key", FT_BYTES, BASE_HEX,
940 NULL, 0, "IGMP V0 Access Key", HFILL }},
943 { "Max Resp Time", "igmp.max_resp", FT_UINT8, BASE_DEC,
944 NULL, 0, "Max Response Time", HFILL }},
947 { "S", "igmp.s", FT_BOOLEAN, 8,
948 TFS(&tfs_s), IGMP_V3_S, "Supress Router Side Processing", HFILL }},
951 { "QRV", "igmp.qrv", FT_UINT8, BASE_DEC,
952 NULL, IGMP_V3_QRV_MASK, "Querier's Robustness Value", HFILL }},
955 { "QQIC", "igmp.qqic", FT_UINT8, BASE_DEC,
956 NULL, 0, "Querier's Query Interval Code", HFILL }},
959 { "Num Src", "igmp.num_src", FT_UINT16, BASE_DEC,
960 NULL, 0, "Number Of Sources", HFILL }},
963 { "Source Address", "igmp.saddr", FT_IPv4, BASE_NONE,
964 NULL, 0, "Source Address", HFILL }},
967 { "Num Group Records", "igmp.num_grp_recs", FT_UINT16, BASE_DEC,
968 NULL, 0, "Number Of Group Records", HFILL }},
971 { "Record Type", "igmp.record_type", FT_UINT8, BASE_DEC,
972 VALS(vs_record_type), 0, "Record Type", HFILL }},
975 { "Aux Data Len", "igmp.aux_data_len", FT_UINT8, BASE_DEC,
976 NULL, 0, "Aux Data Len, In units of 32bit words", HFILL }},
979 { "Multicast Address", "igmp.maddr", FT_IPv4, BASE_NONE,
980 NULL, 0, "Multicast Address", HFILL }},
983 { "Aux Data", "igmp.aux_data", FT_BYTES, BASE_HEX,
984 NULL, 0, "IGMP V3 Auxiliary Data", HFILL }},
987 { "Exponent", "igmp.max_resp.exp", FT_UINT8, BASE_HEX,
988 NULL, IGMP_MAX_RESP_EXP, "Maxmimum Response Time, Exponent", HFILL }},
991 { "Mantissa", "igmp.max_resp.mant", FT_UINT8, BASE_HEX,
992 NULL, IGMP_MAX_RESP_MANT, "Maxmimum Response Time, Mantissa", HFILL }},
994 { &hf_mtrace_max_hops,
995 { "# hops", "igmp.mtrace.max_hops", FT_UINT8, BASE_DEC,
996 NULL, 0, "Maxmimum Number of Hops to Trace", HFILL }},
999 { "Source Address", "igmp.mtrace.saddr", FT_IPv4, BASE_NONE,
1000 NULL, 0, "Multicast Source for the Path Being Traced", HFILL }},
1003 { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4, BASE_NONE,
1004 NULL, 0, "Multicast Receiver for the Path Being Traced", HFILL }},
1006 { &hf_mtrace_rspaddr,
1007 { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4, BASE_NONE,
1008 NULL, 0, "Destination of Completed Traceroute Response", HFILL }},
1010 { &hf_mtrace_resp_ttl,
1011 { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8, BASE_DEC,
1012 NULL, 0, "TTL for Multicasted Responses", HFILL }},
1015 { "Query ID", "igmp.mtrace.q_id", FT_UINT24, BASE_DEC,
1016 NULL, 0, "Identifier for this Traceroute Request", HFILL }},
1018 { &hf_mtrace_q_arrival,
1019 { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32, BASE_DEC,
1020 NULL, 0, "Query Arrival Time", HFILL }},
1022 { &hf_mtrace_q_inaddr,
1023 { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4, BASE_NONE,
1024 NULL, 0, "Incoming Interface Address", HFILL }},
1026 { &hf_mtrace_q_outaddr,
1027 { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4, BASE_NONE,
1028 NULL, 0, "Outgoing Interface Address", HFILL }},
1030 { &hf_mtrace_q_prevrtr,
1031 { "Previous rtr addr", "igmp.mtrace.q_prevrtr", FT_IPv4, BASE_NONE,
1032 NULL, 0, "Previous-Hop Router Address", HFILL }},
1034 { &hf_mtrace_q_inpkt,
1035 { "In pkts", "igmp.mtrace.q_inpkt", FT_UINT32, BASE_DEC,
1036 NULL, 0, "Input packet count on incoming interface", HFILL }},
1038 { &hf_mtrace_q_outpkt,
1039 { "Out pkts", "igmp.mtrace.q_outpkt", FT_UINT32, BASE_DEC,
1040 NULL, 0, "Output packet count on outgoing interface", HFILL }},
1042 { &hf_mtrace_q_total,
1043 { "S,G pkt count", "igmp.mtrace.q_total", FT_UINT32, BASE_DEC,
1044 NULL, 0, "Total number of packets for this source-group pair", HFILL }},
1046 { &hf_mtrace_q_rtg_proto,
1047 { "Rtg Protocol", "igmp.mtrace.q_rtg_proto", FT_UINT8, BASE_DEC,
1048 VALS(&mtrace_rtg_vals), 0, "Routing protocol between this and previous hop rtr", HFILL }},
1050 { &hf_mtrace_q_fwd_ttl,
1051 { "FwdTTL", "igmp.mtrace.q_fwd_ttl", FT_UINT8, BASE_DEC,
1052 NULL, 0, "TTL required for forwarding", HFILL }},
1055 { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8, BASE_HEX,
1056 NULL, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL }},
1059 { "S", "igmp.mtrace.q_s", FT_UINT8, BASE_HEX,
1060 NULL, 0x40, "Set if S,G packet count is for source network", HFILL }},
1062 { &hf_mtrace_q_src_mask,
1063 { "Src Mask", "igmp.mtrace.q_src_mask", FT_UINT8, BASE_HEX,
1064 NULL, 0x3F, "Source mask length. 63 when forwarding on group state", HFILL }},
1066 { &hf_mtrace_q_fwd_code,
1067 { "Forwarding Code", "igmp.mtrace.q_fwd_code", FT_UINT8, BASE_HEX,
1068 VALS(&mtrace_fwd_code_vals), 0, "Forwarding information/error code", HFILL }},
1071 static gint *ett[] = {
1079 proto_igmp = proto_register_protocol("Internet Group Management Protocol",
1081 proto_register_field_array(proto_igmp, hf, array_length(hf));
1082 proto_register_subtree_array(ett, array_length(ett));
1086 proto_reg_handoff_igmp(void)
1088 dissector_add("ip.proto", IP_PROTO_IGMP, dissect_igmp, proto_igmp);