Don't do fcn calls in arg of g_?to??(); Macro may very well eval args multiple times.
[obnox/wireshark/wip.git] / epan / dissectors / packet-igmp.c
1 /* packet-igmp.c
2  * Routines for IGMP packet disassembly
3  * 2001 Ronnie Sahlberg
4  * 2007 Thomas Morin
5  * <See AUTHORS for emails>
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
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.
17  *
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.
22  *
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.
26  */
27 /*
28         IGMP is defined in the following RFCs
29         RFC988  Version 0       Obsolete
30         RFC1054 Version 1
31         RFC1112 Version 1       (same as RFC1054 as far as we are concerned)
32         RFC2236 Version 2
33         RFC3376 Version 3
34
35         Size in bytes for each packet
36         type    RFC988  RFC1054 RFC2236 RFC3376  DVMRP  MRDISC  MSNIP  IGAP  RGMP
37                 v0      v1      v2      v3       v1/v3
38         0x01      20
39         0x02      20
40         0x03      20
41         0x04      20
42         0x05      20
43         0x06      20
44         0x07      20
45         0x08      20
46         0x11               8*     8*     >=12
47         0x12               8*     8*
48         0x13                                     x
49         0x16                      8
50         0x17                      8
51         0x22                            >=8
52         0x23                                                    >=8b
53         0x24                                            >=8a    8b
54         0x25                                            4a      >=8b
55         0x26                                            4a
56         0x40                                                           ??c
57         0x41                                                           ??c
58         0x42                                                           ??c
59         0xfc                                                                  8
60         0xfd                                                                  8
61         0xfe                                                                  8
62         0xff                                                                  8
63
64    * Differs in second byte of protocol. Always 0 in V1
65
66
67         Multicast traceroute was taken from
68         draft-ietf-idmr-traceroute-ipm-07.txt
69
70         Size in bytes for each packet
71         type    draft-ietf-idmr-traceroute-ipm-07.ps
72         0x1e      24 + n*32
73         0x1f      24 + n*32 (n == 0 for Query)
74
75    x DVMRP Protocol  see packet-dvmrp.c
76
77         DVMRP is defined in the following RFCs
78         RFC1075 Version 1
79         draft-ietf-idmr-dvmrp-v3-10.txt Version 3
80
81         V1 and V3 can be distinguished by looking at bytes 6 and 7 in the
82         IGMP header.
83         If header[6]==0xff and header[7]==0x03 we have version 3.
84
85    a MRDISC Protocol  see packet-mrdisc.c
86
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
90
91    b MSNIP Protocol  see packet-msnip.c
92
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.
97
98    c IGAP Protocol  see packet-igap.c
99
100         IGAP : Internet Group membership Authentication Protocol
101         draft-hayashi-igap-03.txt
102
103    d RGMP Protocol  see packet-rgmp.c
104
105         RGMP : Router-port Group Management Protocol
106         RFC3488
107         TTL == 1 and IP.DST==224.0.0.25 for all packets
108
109 */
110
111 #ifdef HAVE_CONFIG_H
112 # include "config.h"
113 #endif
114
115 #include <string.h>
116 #include <glib.h>
117
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"
128
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;
171
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;
177
178 #define MC_ALL_ROUTERS          0xe0000002
179 #define MC_ALL_IGMPV3_ROUTERS   0xe0000016
180 #define MC_RGMP                 0xe0000019
181
182
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
204
205 #define IGMP_TRACEROUTE_HDR_LEN           24
206 #define IGMP_TRACEROUTE_RSP_LEN           32
207
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"             },
226         {0,             NULL}
227 };
228
229 #define IGMP_V3_S               0x08
230 #define IGMP_V3_QRV_MASK        0x07
231
232 #define IGMP_MAX_RESP_EXP       0x70
233 #define IGMP_MAX_RESP_MANT      0x0f
234
235 #define IGMP_V0_GROUP_PUBLIC    0x00
236 #define IGMP_V0_GROUP_PRIVATE   0x01
237
238 static const value_string vs_group_type[] = {
239         {IGMP_V0_GROUP_PUBLIC,          "Public Group"                  },
240         {IGMP_V0_GROUP_PRIVATE,         "Private Group"                 },
241         {0,             NULL}
242 };
243
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
249
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"   },
256         {0,             NULL}
257 };
258
259 static const true_false_string tfs_s = {
260         "SUPPRESS router side processing",
261         "Do not suppress router side processing"
262 };
263
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
270
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"             },
278         { 0,    NULL}
279 };
280
281 static const value_string mtrace_rtg_vals[] = {
282         {1,  "DVMRP"                                        },
283         {2,  "MOSPF"                                        },
284         {3,  "PIM"                                          },
285         {4,  "CBT"                                          },
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" },
293         {0,  NULL}
294 };
295
296 static const value_string mtrace_fwd_code_vals[] = {
297         {0x00, "NO_ERROR"       },
298         {0x01, "WRONG_IF"       },
299         {0x02, "PRUNE_SENT"     },
300         {0x03, "PRUNE_RCVD"     },
301         {0x04, "SCOPED"         },
302         {0x05, "NO_ROUTE"       },
303         {0x06, "WRONG_LAST_HOP" },
304         {0x07, "NOT_FORWARDING" },
305         {0x08, "REACHED_RP"     },
306         {0x09, "RPF_IF"         },
307         {0x0A, "NO_MULTICAST"   },
308         {0x0B, "INFO_HIDDEN"    },
309         {0x81, "NO_SPACE"       },
310         {0x82, "OLD_ROUTER"     },
311         {0x83, "ADMIN_PROHIB"   },
312         {0, NULL}
313 };
314
315 #define PRINT_IGMP_VERSION(version)                                     \
316         do {                                                            \
317                 proto_item *ti;                                         \
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);\
326                 offset += 1;                                            \
327         } while (0);
328
329 void igmp_checksum(proto_tree *tree, tvbuff_t *tvb, int hf_index,
330         int hf_index_bad, packet_info *pinfo, guint len)
331 {
332         guint16 cksum, hdrcksum;
333         vec_t cksum_vec[1];
334         proto_item *hidden_item;
335
336         if (len == 0) {
337                 /*
338                  * Checksum the entire IGMP packet.
339                  */
340                 len = tvb_reported_length(tvb);
341         }
342
343         hdrcksum = tvb_get_ntohs(tvb, 2);
344         if (!pinfo->fragmented && tvb_length(tvb) >= len) {
345                 /*
346                  * The packet isn't part of a fragmented datagram and isn't
347                  * truncated, so we can checksum it.
348                  */
349                 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, len);
350                 cksum_vec[0].len = len;
351
352                 cksum = in_cksum(&cksum_vec[0],1);
353
354                 if (cksum == 0) {
355                         proto_tree_add_uint_format(tree, hf_index, tvb, 2, 2, hdrcksum,
356                                 "Header checksum: 0x%04x [correct]", hdrcksum);
357                 } else {
358                         hidden_item = proto_tree_add_boolean(tree, hf_index_bad,
359                                 tvb, 2, 2, TRUE);
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));
364                 }
365         } else
366                 proto_tree_add_uint(tree, hf_index, tvb, 2, 2, hdrcksum);
367
368         return;
369 }
370
371
372 /* Unknown IGMP message type */
373 static int
374 dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
375 {
376         int len;
377
378         col_add_str(pinfo->cinfo, COL_INFO,
379                 val_to_str(type, commands, "Unknown Type:0x%02x"));
380
381         /* type of command */
382         proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);
383         offset += 1;
384
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");
388         offset += len;
389
390         return offset;
391 }
392
393
394
395 /*************************************************************
396  * IGMP Protocol dissectors
397  *************************************************************/
398 static int
399 dissect_v3_max_resp(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
400 {
401         proto_tree *tree;
402         proto_item *item;
403         guint8 bits;
404         guint32 tsecs;
405
406         bits = tvb_get_guint8(tvb, offset);
407         if (bits&0x80) {
408                 tsecs = ((bits&IGMP_MAX_RESP_MANT)|0x10);
409                 tsecs = tsecs << ( ((bits&IGMP_MAX_RESP_EXP)>>4) + 3);
410         } else {
411                 tsecs = bits;
412         }
413
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);
416
417         if (bits&0x80) {
418                 tree = proto_item_add_subtree(item, ett_max_resp);
419
420                 proto_tree_add_uint(tree, hf_max_resp_exp, tvb, offset, 1,
421                         bits);
422                 proto_tree_add_uint(tree, hf_max_resp_mant, tvb, offset, 1,
423                         bits);
424         }
425
426         offset += 1;
427
428         return offset;
429 }
430
431 static int
432 dissect_v3_sqrv_bits(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
433 {
434         proto_tree *tree;
435         proto_item *item;
436         guint8 bits;
437
438         bits = tvb_get_guint8(tvb, offset);
439
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);
444
445         /* S flag */
446         proto_tree_add_boolean(tree, hf_suppress, tvb, offset, 1, bits);
447         /* QRV */
448         proto_tree_add_uint(tree, hf_qrv, tvb, offset, 1, bits);
449         offset += 1;
450
451         return offset;
452 }
453
454 static int
455 dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
456 {
457         proto_tree *tree;
458         proto_item *item;
459         int old_offset = offset;
460         guint8  adl;
461         guint16 num;
462         guint32 ip;
463         guint32 maddr;
464         guint8 record_type;
465
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,"")
471                 );
472         tree = proto_item_add_subtree(item, ett_group_record);
473
474         /* record type */
475         record_type = tvb_get_guint8(tvb, offset);
476         proto_tree_add_item(tree, hf_record_type, tvb, offset, 1, ENC_BIG_ENDIAN);
477         offset += 1;
478
479         /* aux data len */
480         adl = tvb_get_guint8(tvb, offset);
481         proto_tree_add_uint(tree, hf_aux_data_len, tvb, offset, 1, adl);
482         offset += 1;
483
484         /*number of sources*/
485         num = tvb_get_ntohs(tvb, offset);
486         proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
487         offset += 2;
488
489         /* multicast address */
490         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
491         maddr = tvb_get_ipv4(tvb, offset);
492         offset += 4;
493
494         if (num == 0) {
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));
500                         break;
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));
505                         break;
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));
510                         break;
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));
515                         break;
516                 default:
517                         col_append_fstr(pinfo->cinfo, COL_INFO,
518                                 " / Group %s, unknown record type (?)",
519                                 ip_to_str((guint8*)&maddr));
520                                 break;;
521                 }
522         } else {
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" : "");
529                         break;
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");
535                         break;
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" : "");
540                         break;
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" : "");
545                         break;
546                 default:
547                         col_append_fstr(pinfo->cinfo, COL_INFO,
548                                 " / Group %s, unknown record type (?), sources {",
549                                 ip_to_str((guint8*)&maddr));
550                         break;
551                 }
552         }
553
554         /* source addresses */
555         while(num--){
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?", ":"}"));
559                 }
560                 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, ENC_BIG_ENDIAN);
561                 offset += 4;
562         }
563
564         /* aux data */
565         if(adl){
566                 proto_tree_add_item(tree, hf_aux_data, tvb, offset, adl*4, ENC_NA);
567                 offset += adl*4;
568         }
569
570         proto_item_set_len(item, offset-old_offset);
571         return offset;
572 }
573
574 /* dissectors for version 3, rfc3376 */
575 static int
576 dissect_igmp_v3_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
577 {
578         guint16 num;
579
580         PRINT_IGMP_VERSION(3);
581
582         /* skip reserved field*/
583         offset += 1;
584
585         /* checksum */
586         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
587         offset += 2;
588
589         /* skip reserved field */
590         offset += 2;
591
592         /* number of group records */
593         num = tvb_get_ntohs(tvb, offset);
594         if (!num)
595                 col_append_fstr(pinfo->cinfo, COL_INFO, " - General query");
596
597         proto_tree_add_uint(tree, hf_num_grp_recs, tvb, offset, 2, num);
598         offset += 2;
599
600         while (num--)
601                 offset = dissect_v3_group_record(tvb, pinfo, tree, offset);
602
603         return offset;
604 }
605
606 static int
607 dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
608 {
609         guint16 num;
610         guint32 maddr;
611
612         PRINT_IGMP_VERSION(3);
613
614         num = tvb_get_ntohs(tvb, offset+9);
615         /* max resp code */
616         offset = dissect_v3_max_resp(tvb, tree, offset);
617
618         /* checksum */
619         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
620         offset += 2;
621
622         /* group address */
623         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
624
625         maddr = tvb_get_ipv4(tvb, offset);
626         if (! maddr) {
627                 col_append_fstr(pinfo->cinfo, COL_INFO, ", general");
628         } else {
629                 col_append_fstr(pinfo->cinfo, COL_INFO, ", specific for group %s",
630                         ip_to_str((guint8*)&maddr));
631         }
632         offset +=4;
633
634         /* bitmask for S and QRV */
635         offset = dissect_v3_sqrv_bits(tvb, tree, offset);
636
637         /* qqic */
638         proto_tree_add_item(tree, hf_qqic, tvb, offset, 1, ENC_BIG_ENDIAN);
639         offset += 1;
640
641         /*number of sources*/
642         proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
643         if (num) {
644                 col_append_fstr(pinfo->cinfo, COL_INFO, ", source%s {", (num>1)?"s":"");
645         }
646         offset += 2;
647
648         while(num--){
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);
652                 offset += 4;
653         }
654
655         return offset;
656 }
657
658 /* dissector for version 2 query and report, rfc2236 */
659 static int
660 dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
661 {
662         guint8 tsecs;
663         guint32 maddr;
664
665         PRINT_IGMP_VERSION(2);
666
667         /* max resp time */
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);
671         offset += 1;
672
673         /* checksum */
674         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
675         offset += 2;
676
677         /* group address */
678         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
679
680         maddr = tvb_get_ipv4(tvb, offset);
681         if (! maddr) {
682                 col_append_fstr(pinfo->cinfo, COL_INFO, ", general");
683         } else {
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));
693                 }
694         }
695         offset +=4;
696
697         return offset;
698 }
699
700 /* dissector for version 1 query and report, rfc1054 */
701 static int
702 dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
703 {
704         PRINT_IGMP_VERSION(1);
705
706         /* skip unused byte */
707         offset += 1;
708
709         /* checksum */
710         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
711         offset += 2;
712
713         /* group address */
714         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
715         offset +=4;
716
717         return offset;
718 }
719
720 /* dissector for version 0, rfc988 */
721 static int
722 dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
723 {
724         unsigned char code;
725
726         PRINT_IGMP_VERSION(0);
727
728         /* Code */
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)) {
733                 if (code <5) {
734                         proto_tree_add_uint(tree, hf_reply_code, tvb, offset, 1, code);
735                 } else {
736                         proto_tree_add_uint(tree, hf_reply_pending, tvb, offset, 1, code);
737                 }
738         }
739         offset += 1;
740
741         /* checksum */
742         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 20);
743         offset += 2;
744
745         /* identifier */
746         proto_tree_add_item(tree, hf_identifier, tvb, offset, 4, ENC_BIG_ENDIAN);
747         offset += 4;
748
749         /* group address */
750         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
751         offset += 4;
752
753         /* access key */
754         proto_tree_add_item(tree, hf_access_key, tvb, offset, 8, ENC_NA);
755         offset += 8;
756
757         return offset;
758 }
759
760 /* dissector for multicast traceroute, rfc???? */
761 static int
762 dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
763 {
764         const char *typestr, *blocks = NULL;
765         char buf[20];
766
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.
774          */
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";
779                 blocks = buf;
780         } else if (tvb_reported_length_remaining(tvb, offset) == IGMP_TRACEROUTE_HDR_LEN)
781                 typestr = "Traceroute Query";
782         else
783                 typestr = "Traceroute Request";
784
785         col_set_str(pinfo->cinfo, COL_INFO, typestr);
786         if (blocks)
787                 col_append_str(pinfo->cinfo, COL_INFO, blocks);
788
789         proto_tree_add_uint_format(tree, hf_type, tvb, offset, 1, type,
790                 "Type: %s (0x%02x)", typestr, type);
791         offset += 1;
792
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);
795         offset += 1;
796
797         /* checksum */
798         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
799         offset += 2;
800
801         /* group address to be traced */
802         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
803         offset += 4;
804
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);
807         offset += 4;
808
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);
811         offset += 4;
812
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);
815         offset += 4;
816
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);
819         offset += 1;
820
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);
823         offset += 3;
824
825         /* If this was Query, we only had the fixed header */
826         if (tvb_reported_length_remaining(tvb, offset) == 0)
827                 return offset;
828
829         /* Loop through the response data blocks */
830         while (tvb_reported_length_remaining(tvb, offset) >= IGMP_TRACEROUTE_RSP_LEN) {
831                 proto_item *bi;
832                 proto_tree *block_tree;
833
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);
841
842                 /* Query Arrival Time */
843                 proto_tree_add_item(block_tree, hf_mtrace_q_arrival, tvb, offset, 4, ENC_BIG_ENDIAN);
844                 offset += 4;
845
846                 /* Incoming Interface Address */
847                 proto_tree_add_item(block_tree, hf_mtrace_q_inaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
848                 offset += 4;
849
850                 /* Outgoing Interface Address */
851                 proto_tree_add_item(block_tree, hf_mtrace_q_outaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
852                 offset += 4;
853
854                 /* Previous-Hop Router Address */
855                 proto_tree_add_item(block_tree, hf_mtrace_q_prevrtr, tvb, offset, 4, ENC_BIG_ENDIAN);
856                 offset += 4;
857
858                 /* Input packet count on incoming interface */
859                 proto_tree_add_item(block_tree, hf_mtrace_q_inpkt, tvb, offset, 4, ENC_BIG_ENDIAN);
860                 offset += 4;
861
862                 /* Output packet count on outgoing interface */
863                 proto_tree_add_item(block_tree, hf_mtrace_q_outpkt, tvb, offset, 4, ENC_BIG_ENDIAN);
864                 offset += 4;
865
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);
868                 offset += 4;
869
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);
872                 offset += 1;
873
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);
876                 offset += 1;
877
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);
882                 offset += 1;
883
884                 /* Forwarding information/error code */
885                 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_code, tvb, offset, 1, ENC_BIG_ENDIAN);
886                 offset += 1;
887         }
888
889         return offset;
890 }
891
892 static void
893 dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
894 {
895         proto_tree *tree;
896         proto_item *item;
897         int offset = 0;
898         unsigned char type;
899         guint32 dst;
900
901         item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, ENC_NA);
902         tree = proto_item_add_subtree(item, ett_igmp);
903
904         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP");
905         col_clear(pinfo->cinfo, COL_INFO);
906
907         type = tvb_get_guint8(tvb, offset);
908
909         /* version 0 */
910         if ((type&0xf0)==0){
911                 offset = dissect_igmp_v0(tvb, pinfo, tree, type, offset);
912         }
913
914         switch (type) {
915         case IGMP_V1_HOST_MEMBERSHIP_QUERY:     /* 0x11 v1/v2/v3 */
916                 if ( (pinfo->iplen-pinfo->iphdrlen)>=12 ) {
917                         /* version 3 */
918                         offset = dissect_igmp_v3_query(tvb, pinfo, tree, type, offset);
919                 } else {
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);
923                         } else {
924                                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
925                         }
926                 }
927                 break;
928
929         case IGMP_V1_HOST_MEMBERSHIP_REPORT:    /* 0x12  v1 only */
930                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
931                 break;
932
933         case IGMP_DVMRP:
934                 offset = dissect_dvmrp(tvb, pinfo, parent_tree, offset);
935                 break;
936
937         case IGMP_V1_PIM_ROUTING_MESSAGE:
938                 offset = dissect_pimv1(tvb, pinfo, parent_tree, offset);
939                 break;
940
941         case IGMP_V2_MEMBERSHIP_REPORT:
942         case IGMP_V2_LEAVE_GROUP:
943                 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
944                 break;
945
946         case IGMP_TRACEROUTE_RESPONSE:
947         case IGMP_TRACEROUTE_QUERY_REQ:
948                 offset = dissect_igmp_mtrace(tvb, pinfo, tree, type, offset);
949                 break;
950
951         case IGMP_V3_MEMBERSHIP_REPORT:
952                 offset = dissect_igmp_v3_report(tvb, pinfo, tree, type, offset);
953                 break;
954
955         case IGMP_TYPE_0x23:
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);
959                 }
960                 break;
961
962         case IGMP_TYPE_0x24:
963                 dst = g_htonl(MC_ALL_ROUTERS);
964                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
965                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
966                 }
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);
970                 }
971                 break;
972
973         case IGMP_TYPE_0x25:
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);
977                 } else {
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);
982                         }
983                 }
984                 break;
985
986         case IGMP_TYPE_0x26:
987                 dst = g_htonl(MC_ALL_ROUTERS);
988                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
989                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
990                 }
991                 break;
992
993         case IGMP_IGAP_JOIN:
994         case IGMP_IGAP_QUERY:
995         case IGMP_IGAP_LEAVE:
996                 offset = dissect_igap(tvb, pinfo, parent_tree, offset);
997                 break;
998
999         case IGMP_RGMP_HELLO:
1000         case IGMP_RGMP_BYE:
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);
1006                 }
1007                 break;
1008
1009         default:
1010                 offset = dissect_igmp_unknown(tvb, pinfo, tree, type, offset);
1011                 break;
1012         }
1013
1014         proto_item_set_len(item, offset);
1015 }
1016
1017 void
1018 proto_register_igmp(void)
1019 {
1020         static hf_register_info hf[] = {
1021                 { &hf_type,
1022                         { "Type", "igmp.type", FT_UINT8, BASE_HEX,
1023                           VALS(commands), 0, "IGMP Packet Type", HFILL }},
1024
1025                 { &hf_version,
1026                         { "IGMP Version", "igmp.version", FT_UINT8, BASE_DEC,
1027                           NULL, 0, NULL, HFILL }},
1028
1029                 { &hf_group_type,
1030                         { "Type Of Group", "igmp.group_type", FT_UINT8, BASE_DEC,
1031                           VALS(vs_group_type), 0, "IGMP V0 Type Of Group", HFILL }},
1032
1033                 { &hf_reply_code,
1034                         { "Reply", "igmp.reply", FT_UINT8, BASE_DEC,
1035                           VALS(vs_reply_code), 0, "IGMP V0 Reply", HFILL }},
1036
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 }},
1040
1041                 { &hf_checksum,
1042                         { "Checksum", "igmp.checksum", FT_UINT16, BASE_HEX,
1043                           NULL, 0, "IGMP Checksum", HFILL }},
1044
1045                 { &hf_checksum_bad,
1046                         { "Bad Checksum", "igmp.checksum_bad", FT_BOOLEAN, BASE_NONE,
1047                           NULL, 0x0, "Bad IGMP Checksum", HFILL }},
1048
1049                 { &hf_identifier,
1050                         { "Identifier", "igmp.identifier", FT_UINT32, BASE_DEC,
1051                           NULL, 0, "IGMP V0 Identifier", HFILL }},
1052
1053                 { &hf_access_key,
1054                         { "Access Key", "igmp.access_key", FT_BYTES, BASE_NONE,
1055                           NULL, 0, "IGMP V0 Access Key", HFILL }},
1056
1057                 { &hf_max_resp,
1058                         { "Max Resp Time", "igmp.max_resp", FT_UINT8, BASE_DEC,
1059                           NULL, 0, "Max Response Time", HFILL }},
1060
1061                 { &hf_suppress,
1062                         { "S", "igmp.s", FT_BOOLEAN, 8,
1063                           TFS(&tfs_s), IGMP_V3_S, "Suppress Router Side Processing", HFILL }},
1064
1065                 { &hf_qrv,
1066                         { "QRV", "igmp.qrv", FT_UINT8, BASE_DEC,
1067                         NULL, IGMP_V3_QRV_MASK, "Querier's Robustness Value", HFILL }},
1068
1069                 { &hf_qqic,
1070                         { "QQIC", "igmp.qqic", FT_UINT8, BASE_DEC,
1071                           NULL, 0, "Querier's Query Interval Code", HFILL }},
1072
1073                 { &hf_num_src,
1074                         { "Num Src", "igmp.num_src", FT_UINT16, BASE_DEC,
1075                           NULL, 0, "Number Of Sources", HFILL }},
1076
1077                 { &hf_saddr,
1078                         { "Source Address", "igmp.saddr", FT_IPv4, BASE_NONE,
1079                           NULL, 0, NULL, HFILL }},
1080
1081                 { &hf_num_grp_recs,
1082                         { "Num Group Records", "igmp.num_grp_recs", FT_UINT16, BASE_DEC,
1083                           NULL, 0, "Number Of Group Records", HFILL }},
1084
1085                 { &hf_record_type,
1086                         { "Record Type", "igmp.record_type", FT_UINT8, BASE_DEC,
1087                         VALS(vs_record_type), 0, NULL, HFILL }},
1088
1089                 { &hf_aux_data_len,
1090                         { "Aux Data Len", "igmp.aux_data_len", FT_UINT8, BASE_DEC,
1091                         NULL, 0, "Aux Data Len, In units of 32bit words", HFILL }},
1092
1093                 { &hf_maddr,
1094                         { "Multicast Address", "igmp.maddr", FT_IPv4, BASE_NONE,
1095                           NULL, 0, NULL, HFILL }},
1096
1097                 { &hf_aux_data,
1098                         { "Aux Data", "igmp.aux_data", FT_BYTES, BASE_NONE,
1099                           NULL, 0, "IGMP V3 Auxiliary Data", HFILL }},
1100
1101                 { &hf_max_resp_exp,
1102                         { "Exponent", "igmp.max_resp.exp", FT_UINT8, BASE_HEX,
1103                         NULL, IGMP_MAX_RESP_EXP, "Maximum Response Time, Exponent", HFILL }},
1104
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 }},
1108
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 }},
1112
1113                 { &hf_mtrace_saddr,
1114                         { "Source Address", "igmp.mtrace.saddr", FT_IPv4, BASE_NONE,
1115                           NULL, 0, "Multicast Source for the Path Being Traced", HFILL }},
1116
1117                 { &hf_mtrace_raddr,
1118                         { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4, BASE_NONE,
1119                           NULL, 0, "Multicast Receiver for the Path Being Traced", HFILL }},
1120
1121                 { &hf_mtrace_rspaddr,
1122                         { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4, BASE_NONE,
1123                           NULL, 0, "Destination of Completed Traceroute Response", HFILL }},
1124
1125                 { &hf_mtrace_resp_ttl,
1126                         { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8, BASE_DEC,
1127                         NULL, 0, "TTL for Multicasted Responses", HFILL }},
1128
1129                 { &hf_mtrace_q_id,
1130                         { "Query ID", "igmp.mtrace.q_id", FT_UINT24, BASE_DEC,
1131                         NULL, 0, "Identifier for this Traceroute Request", HFILL }},
1132
1133                 { &hf_mtrace_q_arrival,
1134                         { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32, BASE_DEC,
1135                         NULL, 0, "Query Arrival Time", HFILL }},
1136
1137                 { &hf_mtrace_q_inaddr,
1138                         { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4, BASE_NONE,
1139                         NULL, 0, "Incoming Interface Address", HFILL }},
1140
1141                 { &hf_mtrace_q_outaddr,
1142                         { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4, BASE_NONE,
1143                         NULL, 0, "Outgoing Interface Address", HFILL }},
1144
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 }},
1148
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 }},
1152
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 }},
1156
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 }},
1160
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 }},
1164
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 }},
1168
1169                 { &hf_mtrace_q_mbz,
1170                         { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8, BASE_HEX,
1171                         NULL, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL }},
1172
1173                 { &hf_mtrace_q_s,
1174                         { "S", "igmp.mtrace.q_s", FT_UINT8, BASE_HEX,
1175                         NULL, 0x40, "Set if S,G packet count is for source network", HFILL }},
1176
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 }},
1180
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 }},
1184
1185         };
1186         static gint *ett[] = {
1187                 &ett_igmp,
1188                 &ett_group_record,
1189                 &ett_sqrv_bits,
1190                 &ett_max_resp,
1191                 &ett_mtrace_block,
1192         };
1193
1194         proto_igmp = proto_register_protocol("Internet Group Management Protocol",
1195                 "IGMP", "igmp");
1196         proto_register_field_array(proto_igmp, hf, array_length(hf));
1197         proto_register_subtree_array(ett, array_length(ett));
1198 }
1199
1200 void
1201 proto_reg_handoff_igmp(void)
1202 {
1203         dissector_handle_t igmp_handle;
1204
1205         igmp_handle = create_dissector_handle(dissect_igmp, proto_igmp);
1206         dissector_add_uint("ip.proto", IP_PROTO_IGMP, igmp_handle);
1207 }
1208
1209 /*
1210  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1211  *
1212  * Local variables:
1213  * c-basic-offset: 4
1214  * tab-width: 8
1215  * indent-tabs-mode: t
1216  * End:
1217  *
1218  * vi: set shiftwidth=4 tabstop=8 noexpandtab:
1219  * :indentSize=4:tabSize=8:noTabs=false:
1220  */
1221