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
116 #include <epan/packet.h>
117 #include <epan/to_str.h>
118 #include <epan/ipproto.h>
119 #include <epan/in_cksum.h>
120 #include "packet-igmp.h"
121 #include "packet-dvmrp.h"
122 #include "packet-pim.h"
123 #include "packet-mrdisc.h"
124 #include "packet-msnip.h"
125 #include "packet-igap.h"
126 #include "packet-rgmp.h"
128 static int proto_igmp
= -1;
129 static int hf_type
= -1;
130 static int hf_version
= -1;
131 static int hf_group_type
= -1;
132 static int hf_reply_code
= -1;
133 static int hf_reply_pending
= -1;
134 static int hf_checksum
= -1;
135 static int hf_checksum_bad
= -1;
136 static int hf_identifier
= -1;
137 static int hf_access_key
= -1;
138 static int hf_max_resp
= -1;
139 static int hf_max_resp_exp
= -1;
140 static int hf_max_resp_mant
= -1;
141 static int hf_suppress
= -1;
142 static int hf_qrv
= -1;
143 static int hf_qqic
= -1;
144 static int hf_num_src
= -1;
145 static int hf_saddr
= -1;
146 static int hf_num_grp_recs
= -1;
147 static int hf_record_type
= -1;
148 static int hf_aux_data_len
= -1;
149 static int hf_maddr
= -1;
150 static int hf_aux_data
= -1;
151 static int hf_mtrace_max_hops
= -1;
152 static int hf_mtrace_saddr
= -1;
153 static int hf_mtrace_raddr
= -1;
154 static int hf_mtrace_rspaddr
= -1;
155 static int hf_mtrace_resp_ttl
= -1;
156 static int hf_mtrace_q_id
= -1;
157 static int hf_mtrace_q_arrival
= -1;
158 static int hf_mtrace_q_inaddr
= -1;
159 static int hf_mtrace_q_outaddr
= -1;
160 static int hf_mtrace_q_prevrtr
= -1;
161 static int hf_mtrace_q_inpkt
= -1;
162 static int hf_mtrace_q_outpkt
= -1;
163 static int hf_mtrace_q_total
= -1;
164 static int hf_mtrace_q_rtg_proto
= -1;
165 static int hf_mtrace_q_fwd_ttl
= -1;
166 static int hf_mtrace_q_mbz
= -1;
167 static int hf_mtrace_q_s
= -1;
168 static int hf_mtrace_q_src_mask
= -1;
169 static int hf_mtrace_q_fwd_code
= -1;
171 static int ett_igmp
= -1;
172 static int ett_group_record
= -1;
173 static int ett_sqrv_bits
= -1;
174 static int ett_max_resp
= -1;
175 static int ett_mtrace_block
= -1;
177 #define MC_ALL_ROUTERS 0xe0000002
178 #define MC_ALL_IGMPV3_ROUTERS 0xe0000016
179 #define MC_RGMP 0xe0000019
182 #define IGMP_V0_CREATE_GROUP_REQUEST 0x01
183 #define IGMP_V0_CREATE_GROUP_REPLY 0x02
184 #define IGMP_V0_JOIN_GROUP_REQUEST 0x03
185 #define IGMP_V0_JOIN_GROUP_REPLY 0x04
186 #define IGMP_V0_LEAVE_GROUP_REQUEST 0x05
187 #define IGMP_V0_LEAVE_GROUP_REPLY 0x06
188 #define IGMP_V0_CONFIRM_GROUP_REQUEST 0x07
189 #define IGMP_V0_CONFIRM_GROUP_REPLY 0x08
190 #define IGMP_V1_HOST_MEMBERSHIP_QUERY 0x11
191 #define IGMP_V1_HOST_MEMBERSHIP_REPORT 0x12
192 #define IGMP_DVMRP 0x13
193 #define IGMP_V1_PIM_ROUTING_MESSAGE 0x14
194 #define IGMP_V2_MEMBERSHIP_REPORT 0x16
195 #define IGMP_V2_LEAVE_GROUP 0x17
196 #define IGMP_TRACEROUTE_RESPONSE 0x1e
197 #define IGMP_TRACEROUTE_QUERY_REQ 0x1f
198 #define IGMP_V3_MEMBERSHIP_REPORT 0x22
199 #define IGMP_TYPE_0x23 0x23
200 #define IGMP_TYPE_0x24 0x24
201 #define IGMP_TYPE_0x25 0x25
202 #define IGMP_TYPE_0x26 0x26
204 #define IGMP_TRACEROUTE_HDR_LEN 24
205 #define IGMP_TRACEROUTE_RSP_LEN 32
207 static const value_string commands
[] = {
208 {IGMP_V0_CREATE_GROUP_REQUEST
, "Create Group Request" },
209 {IGMP_V0_CREATE_GROUP_REPLY
, "Create Group Reply" },
210 {IGMP_V0_JOIN_GROUP_REQUEST
, "Join Group Request" },
211 {IGMP_V0_JOIN_GROUP_REPLY
, "Join Group Reply" },
212 {IGMP_V0_LEAVE_GROUP_REQUEST
, "Leave Group Request" },
213 {IGMP_V0_LEAVE_GROUP_REPLY
, "Leave Group Reply" },
214 {IGMP_V0_CONFIRM_GROUP_REQUEST
, "Confirm Group Request" },
215 {IGMP_V0_CONFIRM_GROUP_REPLY
, "Confirm Group Reply" },
216 {IGMP_V1_HOST_MEMBERSHIP_QUERY
, "Membership Query" },
217 {IGMP_V1_HOST_MEMBERSHIP_REPORT
,"Membership Report" },
218 {IGMP_DVMRP
, "DVMRP Protocol" },
219 {IGMP_V1_PIM_ROUTING_MESSAGE
, "PIM Routing Message" },
220 {IGMP_V2_MEMBERSHIP_REPORT
, "Membership Report" },
221 {IGMP_V2_LEAVE_GROUP
, "Leave Group" },
222 {IGMP_TRACEROUTE_RESPONSE
, "Traceroute Response" },
223 {IGMP_TRACEROUTE_QUERY_REQ
, "Traceroute Query or Request" },
224 {IGMP_V3_MEMBERSHIP_REPORT
, "Membership Report" },
228 #define IGMP_V3_S 0x08
229 #define IGMP_V3_QRV_MASK 0x07
231 #define IGMP_MAX_RESP_EXP 0x70
232 #define IGMP_MAX_RESP_MANT 0x0f
234 #define IGMP_V0_GROUP_PUBLIC 0x00
235 #define IGMP_V0_GROUP_PRIVATE 0x01
237 static const value_string vs_group_type
[] = {
238 {IGMP_V0_GROUP_PUBLIC
, "Public Group" },
239 {IGMP_V0_GROUP_PRIVATE
, "Private Group" },
243 #define IGMP_V0_REPLY_GRANTED 0x00
244 #define IGMP_V0_REPLY_NO_RESOURCES 0x01
245 #define IGMP_V0_REPLY_INVALID_CODE 0x02
246 #define IGMP_V0_REPLY_INVALID_GROUP 0x03
247 #define IGMP_V0_REPLY_INVALID_KEY 0x04
249 static const value_string vs_reply_code
[] = {
250 {IGMP_V0_REPLY_GRANTED
, "Request Granted" },
251 {IGMP_V0_REPLY_NO_RESOURCES
, "Request Denied, No Resources" },
252 {IGMP_V0_REPLY_INVALID_CODE
, "Request Denied, Invalid Code" },
253 {IGMP_V0_REPLY_INVALID_GROUP
, "Request Denied, Invalid Group" },
254 {IGMP_V0_REPLY_INVALID_KEY
, "Request Denied, Invalid Key" },
258 static const true_false_string tfs_s
= {
259 "SUPPRESS router side processing",
260 "Do not suppress router side processing"
263 #define IGMP_V3_MODE_IS_INCLUDE 1
264 #define IGMP_V3_MODE_IS_EXCLUDE 2
265 #define IGMP_V3_CHANGE_TO_INCLUDE_MODE 3
266 #define IGMP_V3_CHANGE_TO_EXCLUDE_MODE 4
267 #define IGMP_V3_ALLOW_NEW_SOURCES 5
268 #define IGMP_V3_BLOCK_OLD_SOURCES 6
270 static const value_string vs_record_type
[] = {
271 {IGMP_V3_MODE_IS_INCLUDE
, "Mode Is Include" },
272 {IGMP_V3_MODE_IS_EXCLUDE
, "Mode Is Exclude" },
273 {IGMP_V3_CHANGE_TO_INCLUDE_MODE
,"Change To Include Mode" },
274 {IGMP_V3_CHANGE_TO_EXCLUDE_MODE
,"Change To Exclude Mode" },
275 {IGMP_V3_ALLOW_NEW_SOURCES
, "Allow New Sources" },
276 {IGMP_V3_BLOCK_OLD_SOURCES
, "Block Old Sources" },
280 static const value_string mtrace_rtg_vals
[] = {
285 {5, "PIM using special routing table" },
286 {6, "PIM using a static route" },
287 {7, "DVMRP using a static route" },
288 {8, "PIM using MBGP (aka BGP4+) route" },
289 {9, "CBT using special routing table" },
290 {10, "CBT using a static route" },
291 {11, "PIM using state created by Assert processing" },
295 static const value_string mtrace_fwd_code_vals
[] = {
298 {0x02, "PRUNE_SENT" },
299 {0x03, "PRUNE_RCVD" },
302 {0x06, "WRONG_LAST_HOP" },
303 {0x07, "NOT_FORWARDING" },
304 {0x08, "REACHED_RP" },
306 {0x0A, "NO_MULTICAST" },
307 {0x0B, "INFO_HIDDEN" },
309 {0x82, "OLD_ROUTER" },
310 {0x83, "ADMIN_PROHIB" },
314 #define PRINT_IGMP_VERSION(version) \
317 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "IGMPv%d",version); \
318 col_add_fstr(pinfo->cinfo, COL_INFO, \
319 "%s",val_to_str(type, commands, "Unknown Type:0x%02x")); \
320 /* version of IGMP protocol */ \
321 ti = proto_tree_add_uint(tree, hf_version, tvb, 0, 0, version); \
322 PROTO_ITEM_SET_GENERATED(ti); \
323 /* type of command */ \
324 proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);\
328 void igmp_checksum(proto_tree
*tree
, tvbuff_t
*tvb
, int hf_index
,
329 int hf_index_bad
, packet_info
*pinfo
, guint len
)
331 guint16 cksum
, hdrcksum
;
333 proto_item
*hidden_item
;
337 * Checksum the entire IGMP packet.
339 len
= tvb_reported_length(tvb
);
342 hdrcksum
= tvb_get_ntohs(tvb
, 2);
343 if (!pinfo
->fragmented
&& tvb_length(tvb
) >= len
) {
345 * The packet isn't part of a fragmented datagram and isn't
346 * truncated, so we can checksum it.
348 cksum_vec
[0].ptr
= tvb_get_ptr(tvb
, 0, len
);
349 cksum_vec
[0].len
= len
;
351 cksum
= in_cksum(&cksum_vec
[0],1);
354 proto_tree_add_uint_format(tree
, hf_index
, tvb
, 2, 2, hdrcksum
,
355 "Header checksum: 0x%04x [correct]", hdrcksum
);
357 hidden_item
= proto_tree_add_boolean(tree
, hf_index_bad
,
359 PROTO_ITEM_SET_HIDDEN(hidden_item
);
360 proto_tree_add_uint_format(tree
, hf_index
, tvb
, 2, 2, hdrcksum
,
361 "Header checksum: 0x%04x [incorrect, should be 0x%04x]",
362 hdrcksum
, in_cksum_shouldbe(hdrcksum
,cksum
));
365 proto_tree_add_uint(tree
, hf_index
, tvb
, 2, 2, hdrcksum
);
371 /* Unknown IGMP message type */
373 dissect_igmp_unknown(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int type
, int offset
)
377 col_add_str(pinfo
->cinfo
, COL_INFO
,
378 val_to_str(type
, commands
, "Unknown Type:0x%02x"));
380 /* type of command */
381 proto_tree_add_uint(tree
, hf_type
, tvb
, offset
, 1, type
);
384 /* Just call the rest of it "data" */
385 len
= tvb_length_remaining(tvb
, offset
);
386 proto_tree_add_text(tree
, tvb
, offset
, len
, "Data");
394 /*************************************************************
395 * IGMP Protocol dissectors
396 *************************************************************/
398 dissect_v3_max_resp(tvbuff_t
*tvb
, proto_tree
*parent_tree
, int offset
)
405 bits
= tvb_get_guint8(tvb
, offset
);
407 tsecs
= ((bits
&IGMP_MAX_RESP_MANT
)|0x10);
408 tsecs
= tsecs
<< ( ((bits
&IGMP_MAX_RESP_EXP
)>>4) + 3);
413 item
= proto_tree_add_uint_format_value(parent_tree
, hf_max_resp
, tvb
,
414 offset
, 1, tsecs
, "%.1f sec (0x%02x)",tsecs
*0.1,bits
);
417 tree
= proto_item_add_subtree(item
, ett_max_resp
);
419 proto_tree_add_uint(tree
, hf_max_resp_exp
, tvb
, offset
, 1,
421 proto_tree_add_uint(tree
, hf_max_resp_mant
, tvb
, offset
, 1,
431 dissect_v3_sqrv_bits(tvbuff_t
*tvb
, proto_tree
*parent_tree
, int offset
)
437 bits
= tvb_get_guint8(tvb
, offset
);
439 item
= proto_tree_add_text(parent_tree
, tvb
, offset
, 1,
440 "QRV=%d S=%s", bits
&IGMP_V3_QRV_MASK
,
441 (bits
&IGMP_V3_S
)?tfs_s
.true_string
:tfs_s
.false_string
);
442 tree
= proto_item_add_subtree(item
, ett_sqrv_bits
);
445 proto_tree_add_boolean(tree
, hf_suppress
, tvb
, offset
, 1, bits
);
447 proto_tree_add_uint(tree
, hf_qrv
, tvb
, offset
, 1, bits
);
454 dissect_v3_group_record(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, int offset
)
458 int old_offset
= offset
;
465 ip
= tvb_get_ipv4(tvb
, offset
+4);
466 item
= proto_tree_add_text(parent_tree
, tvb
, offset
, -1,
467 "Group Record : %s %s",
468 ip_to_str((guint8
*)&ip
),
469 val_to_str_const(tvb_get_guint8(tvb
, offset
), vs_record_type
,"")
471 tree
= proto_item_add_subtree(item
, ett_group_record
);
474 record_type
= tvb_get_guint8(tvb
, offset
);
475 proto_tree_add_item(tree
, hf_record_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
479 adl
= tvb_get_guint8(tvb
, offset
);
480 proto_tree_add_uint(tree
, hf_aux_data_len
, tvb
, offset
, 1, adl
);
483 /*number of sources*/
484 num
= tvb_get_ntohs(tvb
, offset
);
485 proto_tree_add_uint(tree
, hf_num_src
, tvb
, offset
, 2, num
);
488 /* multicast address */
489 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
490 maddr
= tvb_get_ipv4(tvb
, offset
);
494 switch(record_type
) {
495 case IGMP_V3_MODE_IS_INCLUDE
:
496 case IGMP_V3_CHANGE_TO_INCLUDE_MODE
:
497 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " / Leave group %s",
498 ip_to_str((guint8
*)&maddr
));
500 case IGMP_V3_MODE_IS_EXCLUDE
:
501 case IGMP_V3_CHANGE_TO_EXCLUDE_MODE
:
502 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
503 " / Join group %s for any sources", ip_to_str((guint8
*)&maddr
));
505 case IGMP_V3_ALLOW_NEW_SOURCES
:
506 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
507 " / Group %s, ALLOW_NEW_SOURCES but no source specified (?)",
508 ip_to_str((guint8
*)&maddr
));
510 case IGMP_V3_BLOCK_OLD_SOURCES
:
511 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
512 " / Group %s, BLOCK_OLD_SOURCES but no source specified (?)",
513 ip_to_str((guint8
*)&maddr
));
516 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
517 " / Group %s, unknown record type (?)",
518 ip_to_str((guint8
*)&maddr
));
522 switch(record_type
) {
523 case IGMP_V3_MODE_IS_INCLUDE
:
524 case IGMP_V3_CHANGE_TO_INCLUDE_MODE
:
525 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
526 " / Join group %s for source%s {",
527 ip_to_str((guint8
*)&maddr
), (num
>1) ? "s in" : "");
529 case IGMP_V3_MODE_IS_EXCLUDE
:
530 case IGMP_V3_CHANGE_TO_EXCLUDE_MODE
:
531 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
532 " / Join group %s, for source%s {",
533 ip_to_str((guint8
*)&maddr
), (num
>1) ? "s not in" : " not");
535 case IGMP_V3_ALLOW_NEW_SOURCES
:
536 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
537 " / Group %s, new source%s {",
538 ip_to_str((guint8
*)&maddr
), (num
>1) ? "s" : "");
540 case IGMP_V3_BLOCK_OLD_SOURCES
:
541 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
542 " / Group %s, block source%s {",
543 ip_to_str((guint8
*)&maddr
), (num
>1) ? "s" : "");
546 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
547 " / Group %s, unknown record type (?), sources {",
548 ip_to_str((guint8
*)&maddr
));
553 /* source addresses */
555 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s%s",
556 tvb_ip_to_str(tvb
, offset
), (num
?", ":"}"));
558 proto_tree_add_item(tree
, hf_saddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
564 proto_tree_add_item(tree
, hf_aux_data
, tvb
, offset
, adl
*4, ENC_NA
);
568 proto_item_set_len(item
, offset
-old_offset
);
572 /* dissectors for version 3, rfc3376 */
574 dissect_igmp_v3_report(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int type
, int offset
)
578 PRINT_IGMP_VERSION(3);
580 /* skip reserved field*/
584 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_bad
, pinfo
, 0);
587 /* skip reserved field */
590 /* number of group records */
591 num
= tvb_get_ntohs(tvb
, offset
);
593 col_append_str(pinfo
->cinfo
, COL_INFO
, " - General query");
595 proto_tree_add_uint(tree
, hf_num_grp_recs
, tvb
, offset
, 2, num
);
599 offset
= dissect_v3_group_record(tvb
, pinfo
, tree
, offset
);
605 dissect_igmp_v3_query(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int type
, int offset
)
610 PRINT_IGMP_VERSION(3);
612 num
= tvb_get_ntohs(tvb
, offset
+9);
614 offset
= dissect_v3_max_resp(tvb
, tree
, offset
);
617 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_bad
, pinfo
, 0);
621 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
623 maddr
= tvb_get_ipv4(tvb
, offset
);
625 col_append_str(pinfo
->cinfo
, COL_INFO
, ", general");
627 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", specific for group %s",
628 ip_to_str((guint8
*)&maddr
));
632 /* bitmask for S and QRV */
633 offset
= dissect_v3_sqrv_bits(tvb
, tree
, offset
);
636 proto_tree_add_item(tree
, hf_qqic
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
639 /*number of sources*/
640 proto_tree_add_uint(tree
, hf_num_src
, tvb
, offset
, 2, num
);
642 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", source%s {", (num
>1)?"s":"");
647 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s%s", tvb_ip_to_str(tvb
, offset
), (num
?", ":"}"));
648 proto_tree_add_item(tree
, hf_saddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
655 /* dissector for version 2 query and report, rfc2236 */
657 dissect_igmp_v2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int type
, int offset
)
662 PRINT_IGMP_VERSION(2);
665 tsecs
= tvb_get_guint8(tvb
, offset
);
666 proto_tree_add_uint_format_value(tree
, hf_max_resp
, tvb
,
667 offset
, 1, tsecs
, "%.1f sec (0x%02x)", tsecs
*0.1,tsecs
);
671 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_bad
, pinfo
, 8);
675 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
677 maddr
= tvb_get_ipv4(tvb
, offset
);
679 col_append_str(pinfo
->cinfo
, COL_INFO
, ", general");
681 if (type
== IGMP_V2_LEAVE_GROUP
) {
682 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
683 " %s", ip_to_str((guint8
*)&maddr
));
684 } else if (type
== IGMP_V1_HOST_MEMBERSHIP_QUERY
) {
685 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
686 ", specific for group %s", ip_to_str((guint8
*)&maddr
));
687 } else { /* IGMP_V2_MEMBERSHIP_REPORT is the only case left */
688 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
689 " group %s", ip_to_str((guint8
*)&maddr
));
697 /* dissector for version 1 query and report, rfc1054 */
699 dissect_igmp_v1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int type
, int offset
)
701 PRINT_IGMP_VERSION(1);
703 /* skip unused byte */
707 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_bad
, pinfo
, 8);
711 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
717 /* dissector for version 0, rfc988 */
719 dissect_igmp_v0(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int type
, int offset
)
723 PRINT_IGMP_VERSION(0);
726 code
= tvb_get_guint8(tvb
, offset
);
727 if (type
==IGMP_V0_CREATE_GROUP_REQUEST
) {
728 proto_tree_add_uint(tree
, hf_group_type
, tvb
, offset
, 1, code
);
729 } else if (!(type
&0x01)) {
731 proto_tree_add_uint(tree
, hf_reply_code
, tvb
, offset
, 1, code
);
733 proto_tree_add_uint(tree
, hf_reply_pending
, tvb
, offset
, 1, code
);
739 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_bad
, pinfo
, 20);
743 proto_tree_add_item(tree
, hf_identifier
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
747 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
751 proto_tree_add_item(tree
, hf_access_key
, tvb
, offset
, 8, ENC_NA
);
757 /* dissector for multicast traceroute, rfc???? */
759 dissect_igmp_mtrace(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int type
, int offset
)
761 const char *typestr
, *blocks
= NULL
;
764 /* All multicast traceroute packets (Query, Request and
765 * Response) have the same fixed header. Request and Response
766 * have one or more response data blocks following this fixed
767 * header. Since Query and Request share the same IGMP type,
768 * the method to differentiate between them is to check the
769 * IGMP packet length. Queries are only
770 * IGMP_TRACEROUTE_HDR_LEN bytes long.
772 if (type
== IGMP_TRACEROUTE_RESPONSE
) {
773 int i
= (tvb_reported_length_remaining(tvb
, offset
) - IGMP_TRACEROUTE_HDR_LEN
) / IGMP_TRACEROUTE_RSP_LEN
;
774 g_snprintf(buf
, sizeof buf
, ", %d block%s", i
, plurality(i
, "", "s"));
775 typestr
= "Traceroute Response";
777 } else if (tvb_reported_length_remaining(tvb
, offset
) == IGMP_TRACEROUTE_HDR_LEN
)
778 typestr
= "Traceroute Query";
780 typestr
= "Traceroute Request";
782 col_set_str(pinfo
->cinfo
, COL_INFO
, typestr
);
784 col_append_str(pinfo
->cinfo
, COL_INFO
, blocks
);
786 proto_tree_add_uint_format_value(tree
, hf_type
, tvb
, offset
, 1, type
,
787 "%s (0x%02x)", typestr
, type
);
790 /* maximum number of hops that the requester wants to trace */
791 proto_tree_add_item(tree
, hf_mtrace_max_hops
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
795 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_bad
, pinfo
, 0);
798 /* group address to be traced */
799 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
802 /* address of multicast source for the path being traced */
803 proto_tree_add_item(tree
, hf_mtrace_saddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
806 /* address of multicast receiver for the path being traced */
807 proto_tree_add_item(tree
, hf_mtrace_raddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
810 /* address where the completed traceroute response packet gets sent */
811 proto_tree_add_item(tree
, hf_mtrace_rspaddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
814 /* for multicasted responses, TTL at which to multicast the response */
815 proto_tree_add_item(tree
, hf_mtrace_resp_ttl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
818 /* unique identifier for this traceroute request (for e.g. duplicate/delay detection) */
819 proto_tree_add_item(tree
, hf_mtrace_q_id
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
822 /* If this was Query, we only had the fixed header */
823 if (tvb_reported_length_remaining(tvb
, offset
) == 0)
826 /* Loop through the response data blocks */
827 while (tvb_reported_length_remaining(tvb
, offset
) >= IGMP_TRACEROUTE_RSP_LEN
) {
829 proto_tree
*block_tree
;
831 bi
= proto_tree_add_text(tree
, tvb
, offset
, IGMP_TRACEROUTE_RSP_LEN
,
832 "Response data block: %s -> %s, Proto: %s, Forwarding Code: %s",
833 tvb_ip_to_str(tvb
, offset
+ 4),
834 tvb_ip_to_str(tvb
, offset
+ 8),
835 val_to_str_const(tvb_get_guint8(tvb
, offset
+ 28), mtrace_rtg_vals
, "Unknown"),
836 val_to_str_const(tvb_get_guint8(tvb
, offset
+ 31), mtrace_fwd_code_vals
, "Unknown"));
837 block_tree
= proto_item_add_subtree(bi
, ett_mtrace_block
);
839 /* Query Arrival Time */
840 proto_tree_add_item(block_tree
, hf_mtrace_q_arrival
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
843 /* Incoming Interface Address */
844 proto_tree_add_item(block_tree
, hf_mtrace_q_inaddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
847 /* Outgoing Interface Address */
848 proto_tree_add_item(block_tree
, hf_mtrace_q_outaddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
851 /* Previous-Hop Router Address */
852 proto_tree_add_item(block_tree
, hf_mtrace_q_prevrtr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
855 /* Input packet count on incoming interface */
856 proto_tree_add_item(block_tree
, hf_mtrace_q_inpkt
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
859 /* Output packet count on outgoing interface */
860 proto_tree_add_item(block_tree
, hf_mtrace_q_outpkt
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
863 /* Total number of packets for this source-group pair */
864 proto_tree_add_item(block_tree
, hf_mtrace_q_total
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
867 /* Routing protocol in use between this and previous-hop router */
868 proto_tree_add_item(block_tree
, hf_mtrace_q_rtg_proto
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
871 /* TTL that a packet is required to be forwarded */
872 proto_tree_add_item(block_tree
, hf_mtrace_q_fwd_ttl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
875 /* Must be zeroed and ignored bit, S bit and src network mask length */
876 proto_tree_add_item(block_tree
, hf_mtrace_q_mbz
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
877 proto_tree_add_item(block_tree
, hf_mtrace_q_s
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
878 proto_tree_add_item(block_tree
, hf_mtrace_q_src_mask
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
881 /* Forwarding information/error code */
882 proto_tree_add_item(block_tree
, hf_mtrace_q_fwd_code
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
890 dissect_igmp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
)
898 item
= proto_tree_add_item(parent_tree
, proto_igmp
, tvb
, offset
, -1, ENC_NA
);
899 tree
= proto_item_add_subtree(item
, ett_igmp
);
901 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IGMP");
902 col_clear(pinfo
->cinfo
, COL_INFO
);
904 type
= tvb_get_guint8(tvb
, offset
);
908 offset
= dissect_igmp_v0(tvb
, pinfo
, tree
, type
, offset
);
912 case IGMP_V1_HOST_MEMBERSHIP_QUERY
: /* 0x11 v1/v2/v3 */
913 if ( tvb_reported_length(tvb
)>=12 ) {
915 offset
= dissect_igmp_v3_query(tvb
, pinfo
, tree
, type
, offset
);
917 /* v1 and v2 differs in second byte of header */
918 if (tvb_get_guint8(tvb
, offset
+1)) {
919 offset
= dissect_igmp_v2(tvb
, pinfo
, tree
, type
, offset
);
921 offset
= dissect_igmp_v1(tvb
, pinfo
, tree
, type
, offset
);
926 case IGMP_V1_HOST_MEMBERSHIP_REPORT
: /* 0x12 v1 only */
927 offset
= dissect_igmp_v1(tvb
, pinfo
, tree
, type
, offset
);
931 offset
= dissect_dvmrp(tvb
, pinfo
, parent_tree
, offset
);
934 case IGMP_V1_PIM_ROUTING_MESSAGE
:
935 offset
= dissect_pimv1(tvb
, pinfo
, parent_tree
, offset
);
938 case IGMP_V2_MEMBERSHIP_REPORT
:
939 case IGMP_V2_LEAVE_GROUP
:
940 offset
= dissect_igmp_v2(tvb
, pinfo
, tree
, type
, offset
);
943 case IGMP_TRACEROUTE_RESPONSE
:
944 case IGMP_TRACEROUTE_QUERY_REQ
:
945 offset
= dissect_igmp_mtrace(tvb
, pinfo
, tree
, type
, offset
);
948 case IGMP_V3_MEMBERSHIP_REPORT
:
949 offset
= dissect_igmp_v3_report(tvb
, pinfo
, tree
, type
, offset
);
953 dst
= g_htonl(MC_ALL_IGMPV3_ROUTERS
);
954 if (!memcmp(pinfo
->dst
.data
, &dst
, 4)) {
955 offset
= dissect_msnip(tvb
, pinfo
, parent_tree
, offset
);
960 dst
= g_htonl(MC_ALL_ROUTERS
);
961 if (!memcmp(pinfo
->dst
.data
, &dst
, 4)) {
962 offset
= dissect_mrdisc(tvb
, pinfo
, parent_tree
, offset
);
964 dst
= g_htonl(MC_ALL_IGMPV3_ROUTERS
);
965 if (!memcmp(pinfo
->dst
.data
, &dst
, 4)) {
966 offset
= dissect_msnip(tvb
, pinfo
, parent_tree
, offset
);
971 if ( tvb_reported_length(tvb
)>=8 ) {
972 /* if len of igmp packet>=8 we assume it is MSNIP */
973 offset
= dissect_msnip(tvb
, pinfo
, parent_tree
, offset
);
975 /* ok its not MSNIP, check if it might be MRDISC */
976 dst
= g_htonl(MC_ALL_ROUTERS
);
977 if (!memcmp(pinfo
->dst
.data
, &dst
, 4)) {
978 offset
= dissect_mrdisc(tvb
, pinfo
, parent_tree
, offset
);
984 dst
= g_htonl(MC_ALL_ROUTERS
);
985 if (!memcmp(pinfo
->dst
.data
, &dst
, 4)) {
986 offset
= dissect_mrdisc(tvb
, pinfo
, parent_tree
, offset
);
991 case IGMP_IGAP_QUERY
:
992 case IGMP_IGAP_LEAVE
:
993 offset
= dissect_igap(tvb
, pinfo
, parent_tree
, offset
);
996 case IGMP_RGMP_HELLO
:
999 case IGMP_RGMP_LEAVE
:
1000 dst
= g_htonl(MC_RGMP
);
1001 if (!memcmp(pinfo
->dst
.data
, &dst
, 4)) {
1002 offset
= dissect_rgmp(tvb
, pinfo
, parent_tree
, offset
);
1007 offset
= dissect_igmp_unknown(tvb
, pinfo
, tree
, type
, offset
);
1011 proto_item_set_len(item
, offset
);
1015 proto_register_igmp(void)
1017 static hf_register_info hf
[] = {
1019 { "Type", "igmp.type", FT_UINT8
, BASE_HEX
,
1020 VALS(commands
), 0, "IGMP Packet Type", HFILL
}},
1023 { "IGMP Version", "igmp.version", FT_UINT8
, BASE_DEC
,
1024 NULL
, 0, NULL
, HFILL
}},
1027 { "Type Of Group", "igmp.group_type", FT_UINT8
, BASE_DEC
,
1028 VALS(vs_group_type
), 0, "IGMP V0 Type Of Group", HFILL
}},
1031 { "Reply", "igmp.reply", FT_UINT8
, BASE_DEC
,
1032 VALS(vs_reply_code
), 0, "IGMP V0 Reply", HFILL
}},
1034 { &hf_reply_pending
,
1035 { "Reply Pending", "igmp.reply.pending", FT_UINT8
, BASE_DEC
,
1036 NULL
, 0, "IGMP V0 Reply Pending, Retry in this many seconds", HFILL
}},
1039 { "Checksum", "igmp.checksum", FT_UINT16
, BASE_HEX
,
1040 NULL
, 0, "IGMP Checksum", HFILL
}},
1043 { "Bad Checksum", "igmp.checksum_bad", FT_BOOLEAN
, BASE_NONE
,
1044 NULL
, 0x0, "Bad IGMP Checksum", HFILL
}},
1047 { "Identifier", "igmp.identifier", FT_UINT32
, BASE_DEC
,
1048 NULL
, 0, "IGMP V0 Identifier", HFILL
}},
1051 { "Access Key", "igmp.access_key", FT_BYTES
, BASE_NONE
,
1052 NULL
, 0, "IGMP V0 Access Key", HFILL
}},
1055 { "Max Resp Time", "igmp.max_resp", FT_UINT8
, BASE_DEC
,
1056 NULL
, 0, "Max Response Time", HFILL
}},
1059 { "S", "igmp.s", FT_BOOLEAN
, 8,
1060 TFS(&tfs_s
), IGMP_V3_S
, "Suppress Router Side Processing", HFILL
}},
1063 { "QRV", "igmp.qrv", FT_UINT8
, BASE_DEC
,
1064 NULL
, IGMP_V3_QRV_MASK
, "Querier's Robustness Value", HFILL
}},
1067 { "QQIC", "igmp.qqic", FT_UINT8
, BASE_DEC
,
1068 NULL
, 0, "Querier's Query Interval Code", HFILL
}},
1071 { "Num Src", "igmp.num_src", FT_UINT16
, BASE_DEC
,
1072 NULL
, 0, "Number Of Sources", HFILL
}},
1075 { "Source Address", "igmp.saddr", FT_IPv4
, BASE_NONE
,
1076 NULL
, 0, NULL
, HFILL
}},
1079 { "Num Group Records", "igmp.num_grp_recs", FT_UINT16
, BASE_DEC
,
1080 NULL
, 0, "Number Of Group Records", HFILL
}},
1083 { "Record Type", "igmp.record_type", FT_UINT8
, BASE_DEC
,
1084 VALS(vs_record_type
), 0, NULL
, HFILL
}},
1087 { "Aux Data Len", "igmp.aux_data_len", FT_UINT8
, BASE_DEC
,
1088 NULL
, 0, "Aux Data Len, In units of 32bit words", HFILL
}},
1091 { "Multicast Address", "igmp.maddr", FT_IPv4
, BASE_NONE
,
1092 NULL
, 0, NULL
, HFILL
}},
1095 { "Aux Data", "igmp.aux_data", FT_BYTES
, BASE_NONE
,
1096 NULL
, 0, "IGMP V3 Auxiliary Data", HFILL
}},
1099 { "Exponent", "igmp.max_resp.exp", FT_UINT8
, BASE_HEX
,
1100 NULL
, IGMP_MAX_RESP_EXP
, "Maximum Response Time, Exponent", HFILL
}},
1102 { &hf_max_resp_mant
,
1103 { "Mantissa", "igmp.max_resp.mant", FT_UINT8
, BASE_HEX
,
1104 NULL
, IGMP_MAX_RESP_MANT
, "Maximum Response Time, Mantissa", HFILL
}},
1106 { &hf_mtrace_max_hops
,
1107 { "# hops", "igmp.mtrace.max_hops", FT_UINT8
, BASE_DEC
,
1108 NULL
, 0, "Maximum Number of Hops to Trace", HFILL
}},
1111 { "Source Address", "igmp.mtrace.saddr", FT_IPv4
, BASE_NONE
,
1112 NULL
, 0, "Multicast Source for the Path Being Traced", HFILL
}},
1115 { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4
, BASE_NONE
,
1116 NULL
, 0, "Multicast Receiver for the Path Being Traced", HFILL
}},
1118 { &hf_mtrace_rspaddr
,
1119 { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4
, BASE_NONE
,
1120 NULL
, 0, "Destination of Completed Traceroute Response", HFILL
}},
1122 { &hf_mtrace_resp_ttl
,
1123 { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8
, BASE_DEC
,
1124 NULL
, 0, "TTL for Multicasted Responses", HFILL
}},
1127 { "Query ID", "igmp.mtrace.q_id", FT_UINT24
, BASE_DEC
,
1128 NULL
, 0, "Identifier for this Traceroute Request", HFILL
}},
1130 { &hf_mtrace_q_arrival
,
1131 { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32
, BASE_DEC
,
1132 NULL
, 0, "Query Arrival Time", HFILL
}},
1134 { &hf_mtrace_q_inaddr
,
1135 { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4
, BASE_NONE
,
1136 NULL
, 0, "Incoming Interface Address", HFILL
}},
1138 { &hf_mtrace_q_outaddr
,
1139 { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4
, BASE_NONE
,
1140 NULL
, 0, "Outgoing Interface Address", HFILL
}},
1142 { &hf_mtrace_q_prevrtr
,
1143 { "Previous rtr addr", "igmp.mtrace.q_prevrtr", FT_IPv4
, BASE_NONE
,
1144 NULL
, 0, "Previous-Hop Router Address", HFILL
}},
1146 { &hf_mtrace_q_inpkt
,
1147 { "In pkts", "igmp.mtrace.q_inpkt", FT_UINT32
, BASE_DEC
,
1148 NULL
, 0, "Input packet count on incoming interface", HFILL
}},
1150 { &hf_mtrace_q_outpkt
,
1151 { "Out pkts", "igmp.mtrace.q_outpkt", FT_UINT32
, BASE_DEC
,
1152 NULL
, 0, "Output packet count on outgoing interface", HFILL
}},
1154 { &hf_mtrace_q_total
,
1155 { "S,G pkt count", "igmp.mtrace.q_total", FT_UINT32
, BASE_DEC
,
1156 NULL
, 0, "Total number of packets for this source-group pair", HFILL
}},
1158 { &hf_mtrace_q_rtg_proto
,
1159 { "Rtg Protocol", "igmp.mtrace.q_rtg_proto", FT_UINT8
, BASE_DEC
,
1160 VALS(mtrace_rtg_vals
), 0, "Routing protocol between this and previous hop rtr", HFILL
}},
1162 { &hf_mtrace_q_fwd_ttl
,
1163 { "FwdTTL", "igmp.mtrace.q_fwd_ttl", FT_UINT8
, BASE_DEC
,
1164 NULL
, 0, "TTL required for forwarding", HFILL
}},
1167 { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8
, BASE_HEX
,
1168 NULL
, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL
}},
1171 { "S", "igmp.mtrace.q_s", FT_UINT8
, BASE_HEX
,
1172 NULL
, 0x40, "Set if S,G packet count is for source network", HFILL
}},
1174 { &hf_mtrace_q_src_mask
,
1175 { "Src Mask", "igmp.mtrace.q_src_mask", FT_UINT8
, BASE_HEX
,
1176 NULL
, 0x3F, "Source mask length. 63 when forwarding on group state", HFILL
}},
1178 { &hf_mtrace_q_fwd_code
,
1179 { "Forwarding Code", "igmp.mtrace.q_fwd_code", FT_UINT8
, BASE_HEX
,
1180 VALS(mtrace_fwd_code_vals
), 0, "Forwarding information/error code", HFILL
}},
1183 static gint
*ett
[] = {
1191 proto_igmp
= proto_register_protocol("Internet Group Management Protocol",
1193 proto_register_field_array(proto_igmp
, hf
, array_length(hf
));
1194 proto_register_subtree_array(ett
, array_length(ett
));
1198 proto_reg_handoff_igmp(void)
1200 dissector_handle_t igmp_handle
;
1202 igmp_handle
= create_dissector_handle(dissect_igmp
, proto_igmp
);
1203 dissector_add_uint("ip.proto", IP_PROTO_IGMP
, igmp_handle
);
1207 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1212 * indent-tabs-mode: t
1215 * vi: set shiftwidth=4 tabstop=8 noexpandtab:
1216 * :indentSize=4:tabSize=8:noTabs=false: