Revert "Fixup: tvb_* -> tvb_captured"
[metze/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  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  */
25 /*
26         IGMP is defined in the following RFCs
27         RFC988  Version 0       Obsolete
28         RFC1054 Version 1
29         RFC1112 Version 1       (same as RFC1054 as far as we are concerned)
30         RFC2236 Version 2
31         RFC3376 Version 3
32
33         Size in bytes for each packet
34         type    RFC988  RFC1054 RFC2236 RFC3376  DVMRP  MRDISC  MSNIP  IGAP  RGMP
35                 v0      v1      v2      v3       v1/v3
36         0x01      20
37         0x02      20
38         0x03      20
39         0x04      20
40         0x05      20
41         0x06      20
42         0x07      20
43         0x08      20
44         0x11               8*     8*     >=12
45         0x12               8*     8*
46         0x13                                     x
47         0x16                      8
48         0x17                      8
49         0x22                            >=8
50         0x23                                                    >=8b
51         0x24                                            >=8a    8b
52         0x25                                            4a      >=8b
53         0x26                                            4a
54         0x40                                                           ??c
55         0x41                                                           ??c
56         0x42                                                           ??c
57         0xfc                                                                  8
58         0xfd                                                                  8
59         0xfe                                                                  8
60         0xff                                                                  8
61
62    * Differs in second byte of protocol. Always 0 in V1
63
64
65         Multicast traceroute was taken from
66         draft-ietf-idmr-traceroute-ipm-07.txt
67
68         Size in bytes for each packet
69         type    draft-ietf-idmr-traceroute-ipm-07.ps
70         0x1e      24 + n*32
71         0x1f      24 + n*32 (n == 0 for Query)
72
73    x DVMRP Protocol  see packet-dvmrp.c
74
75         DVMRP is defined in the following RFCs
76         RFC1075 Version 1
77         draft-ietf-idmr-dvmrp-v3-10.txt Version 3
78
79         V1 and V3 can be distinguished by looking at bytes 6 and 7 in the
80         IGMP header.
81         If header[6]==0xff and header[7]==0x03 we have version 3.
82
83    a MRDISC Protocol  see packet-mrdisc.c
84
85         MRDISC : IGMP Multicast Router DISCovery
86         draft-ietf-idmr-igmp-mrdisc-06.txt
87         TTL == 1 and IP.DST==224.0.0.2 for all packets
88
89    b MSNIP Protocol  see packet-msnip.c
90
91         MSNIP : Multicast Source Notification of Interest Protocol
92         draft-ietf-idmr-msnip-00.txt
93         0x23, 0x24 are sent with ip.dst==224.0.0.22
94         0x25 is sent as unicast.
95
96    c IGAP Protocol  see packet-igap.c
97
98         IGAP : Internet Group membership Authentication Protocol
99         draft-hayashi-igap-03.txt
100
101    d RGMP Protocol  see packet-rgmp.c
102
103         RGMP : Router-port Group Management Protocol
104         RFC3488
105         TTL == 1 and IP.DST==224.0.0.25 for all packets
106
107 */
108
109 #include "config.h"
110
111 #include <string.h>
112 #include <glib.h>
113
114 #include <epan/packet.h>
115 #include <epan/to_str.h>
116 #include <epan/ipproto.h>
117 #include <epan/in_cksum.h>
118 #include "packet-igmp.h"
119 #include "packet-dvmrp.h"
120 #include "packet-pim.h"
121 #include "packet-mrdisc.h"
122 #include "packet-msnip.h"
123 #include "packet-igap.h"
124 #include "packet-rgmp.h"
125
126 void proto_register_igmp(void);
127 void proto_reg_handoff_igmp(void);
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_value(parent_tree, hf_max_resp, tvb,
415                         offset, 1, tsecs, "%.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_const(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                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s",
557                                 tvb_ip_to_str(tvb, offset), (num?", ":"}"));
558
559                 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, ENC_BIG_ENDIAN);
560                 offset += 4;
561         }
562
563         /* aux data */
564         if(adl){
565                 proto_tree_add_item(tree, hf_aux_data, tvb, offset, adl*4, ENC_NA);
566                 offset += adl*4;
567         }
568
569         proto_item_set_len(item, offset-old_offset);
570         return offset;
571 }
572
573 /* dissectors for version 3, rfc3376 */
574 static int
575 dissect_igmp_v3_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
576 {
577         guint16 num;
578
579         PRINT_IGMP_VERSION(3);
580
581         /* skip reserved field*/
582         offset += 1;
583
584         /* checksum */
585         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
586         offset += 2;
587
588         /* skip reserved field */
589         offset += 2;
590
591         /* number of group records */
592         num = tvb_get_ntohs(tvb, offset);
593         if (!num)
594                 col_append_str(pinfo->cinfo, COL_INFO, " - General query");
595
596         proto_tree_add_uint(tree, hf_num_grp_recs, tvb, offset, 2, num);
597         offset += 2;
598
599         while (num--)
600                 offset = dissect_v3_group_record(tvb, pinfo, tree, offset);
601
602         return offset;
603 }
604
605 static int
606 dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
607 {
608         guint16 num;
609         guint32 maddr;
610
611         PRINT_IGMP_VERSION(3);
612
613         num = tvb_get_ntohs(tvb, offset+9);
614         /* max resp code */
615         offset = dissect_v3_max_resp(tvb, tree, offset);
616
617         /* checksum */
618         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
619         offset += 2;
620
621         /* group address */
622         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
623
624         maddr = tvb_get_ipv4(tvb, offset);
625         if (! maddr) {
626                 col_append_str(pinfo->cinfo, COL_INFO, ", general");
627         } else {
628                 col_append_fstr(pinfo->cinfo, COL_INFO, ", specific for group %s",
629                         ip_to_str((guint8*)&maddr));
630         }
631         offset +=4;
632
633         /* bitmask for S and QRV */
634         offset = dissect_v3_sqrv_bits(tvb, tree, offset);
635
636         /* qqic */
637         proto_tree_add_item(tree, hf_qqic, tvb, offset, 1, ENC_BIG_ENDIAN);
638         offset += 1;
639
640         /*number of sources*/
641         proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
642         if (num) {
643                 col_append_fstr(pinfo->cinfo, COL_INFO, ", source%s {", (num>1)?"s":"");
644         }
645         offset += 2;
646
647         while(num--){
648                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", tvb_ip_to_str(tvb, offset), (num?", ":"}"));
649                 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, ENC_BIG_ENDIAN);
650                 offset += 4;
651         }
652
653         return offset;
654 }
655
656 /* dissector for version 2 query and report, rfc2236 */
657 static int
658 dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
659 {
660         guint8 tsecs;
661         guint32 maddr;
662
663         PRINT_IGMP_VERSION(2);
664
665         /* max resp time */
666         tsecs = tvb_get_guint8(tvb, offset);
667         proto_tree_add_uint_format_value(tree, hf_max_resp, tvb,
668                 offset, 1, tsecs, "%.1f sec (0x%02x)", tsecs*0.1,tsecs);
669         offset += 1;
670
671         /* checksum */
672         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
673         offset += 2;
674
675         /* group address */
676         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
677
678         maddr = tvb_get_ipv4(tvb, offset);
679         if (! maddr) {
680                 col_append_str(pinfo->cinfo, COL_INFO, ", general");
681         } else {
682                 if (type == IGMP_V2_LEAVE_GROUP) {
683                         col_append_fstr(pinfo->cinfo, COL_INFO,
684                                 " %s", ip_to_str((guint8*)&maddr));
685                 } else if (type == IGMP_V1_HOST_MEMBERSHIP_QUERY) {
686                         col_append_fstr(pinfo->cinfo, COL_INFO,
687                         ", specific for group %s", ip_to_str((guint8*)&maddr));
688                 } else { /* IGMP_V2_MEMBERSHIP_REPORT is the only case left */
689                         col_append_fstr(pinfo->cinfo, COL_INFO,
690                                 " group %s", ip_to_str((guint8*)&maddr));
691                 }
692         }
693         offset +=4;
694
695         return offset;
696 }
697
698 /* dissector for version 1 query and report, rfc1054 */
699 static int
700 dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
701 {
702         PRINT_IGMP_VERSION(1);
703
704         /* skip unused byte */
705         offset += 1;
706
707         /* checksum */
708         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
709         offset += 2;
710
711         /* group address */
712         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
713         offset +=4;
714
715         return offset;
716 }
717
718 /* dissector for version 0, rfc988 */
719 static int
720 dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
721 {
722         unsigned char code;
723
724         PRINT_IGMP_VERSION(0);
725
726         /* Code */
727         code = tvb_get_guint8(tvb, offset);
728         if (type==IGMP_V0_CREATE_GROUP_REQUEST) {
729                 proto_tree_add_uint(tree, hf_group_type, tvb, offset, 1, code);
730         } else if (!(type&0x01)) {
731                 if (code <5) {
732                         proto_tree_add_uint(tree, hf_reply_code, tvb, offset, 1, code);
733                 } else {
734                         proto_tree_add_uint(tree, hf_reply_pending, tvb, offset, 1, code);
735                 }
736         }
737         offset += 1;
738
739         /* checksum */
740         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 20);
741         offset += 2;
742
743         /* identifier */
744         proto_tree_add_item(tree, hf_identifier, tvb, offset, 4, ENC_BIG_ENDIAN);
745         offset += 4;
746
747         /* group address */
748         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
749         offset += 4;
750
751         /* access key */
752         proto_tree_add_item(tree, hf_access_key, tvb, offset, 8, ENC_NA);
753         offset += 8;
754
755         return offset;
756 }
757
758 /* dissector for multicast traceroute, rfc???? */
759 static int
760 dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
761 {
762         const char *typestr, *blocks = NULL;
763         char buf[20];
764
765         /* All multicast traceroute packets (Query, Request and
766          * Response) have the same fixed header. Request and Response
767          * have one or more response data blocks following this fixed
768          * header. Since Query and Request share the same IGMP type,
769          * the method to differentiate between them is to check the
770          * IGMP packet length. Queries are only
771          * IGMP_TRACEROUTE_HDR_LEN bytes long.
772          */
773         if (type == IGMP_TRACEROUTE_RESPONSE) {
774                 int i = (tvb_reported_length_remaining(tvb, offset) - IGMP_TRACEROUTE_HDR_LEN) / IGMP_TRACEROUTE_RSP_LEN;
775                 g_snprintf(buf, sizeof buf, ", %d block%s", i, plurality(i, "", "s"));
776                 typestr = "Traceroute Response";
777                 blocks = buf;
778         } else if (tvb_reported_length_remaining(tvb, offset) == IGMP_TRACEROUTE_HDR_LEN)
779                 typestr = "Traceroute Query";
780         else
781                 typestr = "Traceroute Request";
782
783         col_set_str(pinfo->cinfo, COL_INFO, typestr);
784         if (blocks)
785                 col_append_str(pinfo->cinfo, COL_INFO, blocks);
786
787         proto_tree_add_uint_format_value(tree, hf_type, tvb, offset, 1, type,
788                 "%s (0x%02x)", typestr, type);
789         offset += 1;
790
791         /* maximum number of hops that the requester wants to trace */
792         proto_tree_add_item(tree, hf_mtrace_max_hops, tvb, offset, 1, ENC_BIG_ENDIAN);
793         offset += 1;
794
795         /* checksum */
796         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
797         offset += 2;
798
799         /* group address to be traced */
800         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
801         offset += 4;
802
803         /* address of multicast source for the path being traced */
804         proto_tree_add_item(tree, hf_mtrace_saddr, tvb, offset, 4, ENC_BIG_ENDIAN);
805         offset += 4;
806
807         /* address of multicast receiver for the path being traced */
808         proto_tree_add_item(tree, hf_mtrace_raddr, tvb, offset, 4, ENC_BIG_ENDIAN);
809         offset += 4;
810
811         /* address where the completed traceroute response packet gets sent */
812         proto_tree_add_item(tree, hf_mtrace_rspaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
813         offset += 4;
814
815         /* for multicasted responses, TTL at which to multicast the response */
816         proto_tree_add_item(tree, hf_mtrace_resp_ttl, tvb, offset, 1, ENC_BIG_ENDIAN);
817         offset += 1;
818
819         /* unique identifier for this traceroute request (for e.g. duplicate/delay detection) */
820         proto_tree_add_item(tree, hf_mtrace_q_id, tvb, offset, 3, ENC_BIG_ENDIAN);
821         offset += 3;
822
823         /* If this was Query, we only had the fixed header */
824         if (tvb_reported_length_remaining(tvb, offset) == 0)
825                 return offset;
826
827         /* Loop through the response data blocks */
828         while (tvb_reported_length_remaining(tvb, offset) >= IGMP_TRACEROUTE_RSP_LEN) {
829                 proto_item *bi;
830                 proto_tree *block_tree;
831
832                 bi = proto_tree_add_text(tree, tvb, offset, IGMP_TRACEROUTE_RSP_LEN,
833                         "Response data block: %s -> %s,  Proto: %s,  Forwarding Code: %s",
834                         tvb_ip_to_str(tvb, offset + 4),
835                         tvb_ip_to_str(tvb, offset + 8),
836                         val_to_str_const(tvb_get_guint8(tvb, offset + 28), mtrace_rtg_vals, "Unknown"),
837                         val_to_str_const(tvb_get_guint8(tvb, offset + 31), mtrace_fwd_code_vals, "Unknown"));
838                 block_tree = proto_item_add_subtree(bi, ett_mtrace_block);
839
840                 /* Query Arrival Time */
841                 proto_tree_add_item(block_tree, hf_mtrace_q_arrival, tvb, offset, 4, ENC_BIG_ENDIAN);
842                 offset += 4;
843
844                 /* Incoming Interface Address */
845                 proto_tree_add_item(block_tree, hf_mtrace_q_inaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
846                 offset += 4;
847
848                 /* Outgoing Interface Address */
849                 proto_tree_add_item(block_tree, hf_mtrace_q_outaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
850                 offset += 4;
851
852                 /* Previous-Hop Router Address */
853                 proto_tree_add_item(block_tree, hf_mtrace_q_prevrtr, tvb, offset, 4, ENC_BIG_ENDIAN);
854                 offset += 4;
855
856                 /* Input packet count on incoming interface */
857                 proto_tree_add_item(block_tree, hf_mtrace_q_inpkt, tvb, offset, 4, ENC_BIG_ENDIAN);
858                 offset += 4;
859
860                 /* Output packet count on outgoing interface */
861                 proto_tree_add_item(block_tree, hf_mtrace_q_outpkt, tvb, offset, 4, ENC_BIG_ENDIAN);
862                 offset += 4;
863
864                 /* Total number of packets for this source-group pair */
865                 proto_tree_add_item(block_tree, hf_mtrace_q_total, tvb, offset, 4, ENC_BIG_ENDIAN);
866                 offset += 4;
867
868                 /* Routing protocol in use between this and previous-hop router */
869                 proto_tree_add_item(block_tree, hf_mtrace_q_rtg_proto, tvb, offset, 1, ENC_BIG_ENDIAN);
870                 offset += 1;
871
872                 /* TTL that a packet is required to be forwarded */
873                 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_ttl, tvb, offset, 1, ENC_BIG_ENDIAN);
874                 offset += 1;
875
876                 /* Must be zeroed and ignored bit, S bit and src network mask length */
877                 proto_tree_add_item(block_tree, hf_mtrace_q_mbz, tvb, offset, 1, ENC_BIG_ENDIAN);
878                 proto_tree_add_item(block_tree, hf_mtrace_q_s, tvb, offset, 1, ENC_BIG_ENDIAN);
879                 proto_tree_add_item(block_tree, hf_mtrace_q_src_mask, tvb, offset, 1, ENC_BIG_ENDIAN);
880                 offset += 1;
881
882                 /* Forwarding information/error code */
883                 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_code, tvb, offset, 1, ENC_BIG_ENDIAN);
884                 offset += 1;
885         }
886
887         return offset;
888 }
889
890 static void
891 dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
892 {
893         proto_tree *tree;
894         proto_item *item;
895         int offset = 0;
896         unsigned char type;
897         guint32 dst;
898
899         item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, ENC_NA);
900         tree = proto_item_add_subtree(item, ett_igmp);
901
902         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP");
903         col_clear(pinfo->cinfo, COL_INFO);
904
905         type = tvb_get_guint8(tvb, offset);
906
907         /* version 0 */
908         if ((type&0xf0)==0){
909                 offset = dissect_igmp_v0(tvb, pinfo, tree, type, offset);
910         }
911
912         switch (type) {
913         case IGMP_V1_HOST_MEMBERSHIP_QUERY:     /* 0x11 v1/v2/v3 */
914                 if ( tvb_reported_length(tvb)>=12 ) {
915                         /* version 3 */
916                         offset = dissect_igmp_v3_query(tvb, pinfo, tree, type, offset);
917                 } else {
918                         /* v1 and v2 differs in second byte of header */
919                         if (tvb_get_guint8(tvb, offset+1)) {
920                                 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
921                         } else {
922                                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
923                         }
924                 }
925                 break;
926
927         case IGMP_V1_HOST_MEMBERSHIP_REPORT:    /* 0x12  v1 only */
928                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
929                 break;
930
931         case IGMP_DVMRP:
932                 offset = dissect_dvmrp(tvb, pinfo, parent_tree, offset);
933                 break;
934
935         case IGMP_V1_PIM_ROUTING_MESSAGE:
936                 offset = dissect_pimv1(tvb, pinfo, parent_tree, offset);
937                 break;
938
939         case IGMP_V2_MEMBERSHIP_REPORT:
940         case IGMP_V2_LEAVE_GROUP:
941                 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
942                 break;
943
944         case IGMP_TRACEROUTE_RESPONSE:
945         case IGMP_TRACEROUTE_QUERY_REQ:
946                 offset = dissect_igmp_mtrace(tvb, pinfo, tree, type, offset);
947                 break;
948
949         case IGMP_V3_MEMBERSHIP_REPORT:
950                 offset = dissect_igmp_v3_report(tvb, pinfo, tree, type, offset);
951                 break;
952
953         case IGMP_TYPE_0x23:
954                 dst = g_htonl(MC_ALL_IGMPV3_ROUTERS);
955                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
956                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
957                 }
958                 break;
959
960         case IGMP_TYPE_0x24:
961                 dst = g_htonl(MC_ALL_ROUTERS);
962                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
963                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
964                 }
965                 dst = g_htonl(MC_ALL_IGMPV3_ROUTERS);
966                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
967                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
968                 }
969                 break;
970
971         case IGMP_TYPE_0x25:
972                 if ( tvb_reported_length(tvb)>=8 ) {
973                         /* if len of igmp packet>=8 we assume it is MSNIP */
974                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
975                 } else {
976                         /* ok its not MSNIP, check if it might be MRDISC */
977                         dst = g_htonl(MC_ALL_ROUTERS);
978                         if (!memcmp(pinfo->dst.data, &dst, 4)) {
979                                 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
980                         }
981                 }
982                 break;
983
984         case IGMP_TYPE_0x26:
985                 dst = g_htonl(MC_ALL_ROUTERS);
986                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
987                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
988                 }
989                 break;
990
991         case IGMP_IGAP_JOIN:
992         case IGMP_IGAP_QUERY:
993         case IGMP_IGAP_LEAVE:
994                 offset = dissect_igap(tvb, pinfo, parent_tree, offset);
995                 break;
996
997         case IGMP_RGMP_HELLO:
998         case IGMP_RGMP_BYE:
999         case IGMP_RGMP_JOIN:
1000         case IGMP_RGMP_LEAVE:
1001                 dst = g_htonl(MC_RGMP);
1002                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
1003                         offset = dissect_rgmp(tvb, pinfo, parent_tree, offset);
1004                 }
1005                 break;
1006
1007         default:
1008                 offset = dissect_igmp_unknown(tvb, pinfo, tree, type, offset);
1009                 break;
1010         }
1011
1012         proto_item_set_len(item, offset);
1013 }
1014
1015 void
1016 proto_register_igmp(void)
1017 {
1018         static hf_register_info hf[] = {
1019                 { &hf_type,
1020                         { "Type", "igmp.type", FT_UINT8, BASE_HEX,
1021                           VALS(commands), 0, "IGMP Packet Type", HFILL }},
1022
1023                 { &hf_version,
1024                         { "IGMP Version", "igmp.version", FT_UINT8, BASE_DEC,
1025                           NULL, 0, NULL, HFILL }},
1026
1027                 { &hf_group_type,
1028                         { "Type Of Group", "igmp.group_type", FT_UINT8, BASE_DEC,
1029                           VALS(vs_group_type), 0, "IGMP V0 Type Of Group", HFILL }},
1030
1031                 { &hf_reply_code,
1032                         { "Reply", "igmp.reply", FT_UINT8, BASE_DEC,
1033                           VALS(vs_reply_code), 0, "IGMP V0 Reply", HFILL }},
1034
1035                 { &hf_reply_pending,
1036                         { "Reply Pending", "igmp.reply.pending", FT_UINT8, BASE_DEC,
1037                           NULL, 0, "IGMP V0 Reply Pending, Retry in this many seconds", HFILL }},
1038
1039                 { &hf_checksum,
1040                         { "Checksum", "igmp.checksum", FT_UINT16, BASE_HEX,
1041                           NULL, 0, "IGMP Checksum", HFILL }},
1042
1043                 { &hf_checksum_bad,
1044                         { "Bad Checksum", "igmp.checksum_bad", FT_BOOLEAN, BASE_NONE,
1045                           NULL, 0x0, "Bad IGMP Checksum", HFILL }},
1046
1047                 { &hf_identifier,
1048                         { "Identifier", "igmp.identifier", FT_UINT32, BASE_DEC,
1049                           NULL, 0, "IGMP V0 Identifier", HFILL }},
1050
1051                 { &hf_access_key,
1052                         { "Access Key", "igmp.access_key", FT_BYTES, BASE_NONE,
1053                           NULL, 0, "IGMP V0 Access Key", HFILL }},
1054
1055                 { &hf_max_resp,
1056                         { "Max Resp Time", "igmp.max_resp", FT_UINT8, BASE_DEC,
1057                           NULL, 0, "Max Response Time", HFILL }},
1058
1059                 { &hf_suppress,
1060                         { "S", "igmp.s", FT_BOOLEAN, 8,
1061                           TFS(&tfs_s), IGMP_V3_S, "Suppress Router Side Processing", HFILL }},
1062
1063                 { &hf_qrv,
1064                         { "QRV", "igmp.qrv", FT_UINT8, BASE_DEC,
1065                         NULL, IGMP_V3_QRV_MASK, "Querier's Robustness Value", HFILL }},
1066
1067                 { &hf_qqic,
1068                         { "QQIC", "igmp.qqic", FT_UINT8, BASE_DEC,
1069                           NULL, 0, "Querier's Query Interval Code", HFILL }},
1070
1071                 { &hf_num_src,
1072                         { "Num Src", "igmp.num_src", FT_UINT16, BASE_DEC,
1073                           NULL, 0, "Number Of Sources", HFILL }},
1074
1075                 { &hf_saddr,
1076                         { "Source Address", "igmp.saddr", FT_IPv4, BASE_NONE,
1077                           NULL, 0, NULL, HFILL }},
1078
1079                 { &hf_num_grp_recs,
1080                         { "Num Group Records", "igmp.num_grp_recs", FT_UINT16, BASE_DEC,
1081                           NULL, 0, "Number Of Group Records", HFILL }},
1082
1083                 { &hf_record_type,
1084                         { "Record Type", "igmp.record_type", FT_UINT8, BASE_DEC,
1085                         VALS(vs_record_type), 0, NULL, HFILL }},
1086
1087                 { &hf_aux_data_len,
1088                         { "Aux Data Len", "igmp.aux_data_len", FT_UINT8, BASE_DEC,
1089                         NULL, 0, "Aux Data Len, In units of 32bit words", HFILL }},
1090
1091                 { &hf_maddr,
1092                         { "Multicast Address", "igmp.maddr", FT_IPv4, BASE_NONE,
1093                           NULL, 0, NULL, HFILL }},
1094
1095                 { &hf_aux_data,
1096                         { "Aux Data", "igmp.aux_data", FT_BYTES, BASE_NONE,
1097                           NULL, 0, "IGMP V3 Auxiliary Data", HFILL }},
1098
1099                 { &hf_max_resp_exp,
1100                         { "Exponent", "igmp.max_resp.exp", FT_UINT8, BASE_HEX,
1101                         NULL, IGMP_MAX_RESP_EXP, "Maximum Response Time, Exponent", HFILL }},
1102
1103                 { &hf_max_resp_mant,
1104                         { "Mantissa", "igmp.max_resp.mant", FT_UINT8, BASE_HEX,
1105                         NULL, IGMP_MAX_RESP_MANT, "Maximum Response Time, Mantissa", HFILL }},
1106
1107                 { &hf_mtrace_max_hops,
1108                         { "# hops", "igmp.mtrace.max_hops", FT_UINT8, BASE_DEC,
1109                         NULL, 0, "Maximum Number of Hops to Trace", HFILL }},
1110
1111                 { &hf_mtrace_saddr,
1112                         { "Source Address", "igmp.mtrace.saddr", FT_IPv4, BASE_NONE,
1113                           NULL, 0, "Multicast Source for the Path Being Traced", HFILL }},
1114
1115                 { &hf_mtrace_raddr,
1116                         { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4, BASE_NONE,
1117                           NULL, 0, "Multicast Receiver for the Path Being Traced", HFILL }},
1118
1119                 { &hf_mtrace_rspaddr,
1120                         { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4, BASE_NONE,
1121                           NULL, 0, "Destination of Completed Traceroute Response", HFILL }},
1122
1123                 { &hf_mtrace_resp_ttl,
1124                         { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8, BASE_DEC,
1125                         NULL, 0, "TTL for Multicasted Responses", HFILL }},
1126
1127                 { &hf_mtrace_q_id,
1128                         { "Query ID", "igmp.mtrace.q_id", FT_UINT24, BASE_DEC,
1129                         NULL, 0, "Identifier for this Traceroute Request", HFILL }},
1130
1131                 { &hf_mtrace_q_arrival,
1132                         { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32, BASE_DEC,
1133                         NULL, 0, "Query Arrival Time", HFILL }},
1134
1135                 { &hf_mtrace_q_inaddr,
1136                         { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4, BASE_NONE,
1137                         NULL, 0, "Incoming Interface Address", HFILL }},
1138
1139                 { &hf_mtrace_q_outaddr,
1140                         { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4, BASE_NONE,
1141                         NULL, 0, "Outgoing Interface Address", HFILL }},
1142
1143                 { &hf_mtrace_q_prevrtr,
1144                         { "Previous rtr addr", "igmp.mtrace.q_prevrtr", FT_IPv4, BASE_NONE,
1145                         NULL, 0, "Previous-Hop Router Address", HFILL }},
1146
1147                 { &hf_mtrace_q_inpkt,
1148                         { "In pkts", "igmp.mtrace.q_inpkt", FT_UINT32, BASE_DEC,
1149                         NULL, 0, "Input packet count on incoming interface", HFILL }},
1150
1151                 { &hf_mtrace_q_outpkt,
1152                         { "Out pkts", "igmp.mtrace.q_outpkt", FT_UINT32, BASE_DEC,
1153                         NULL, 0, "Output packet count on outgoing interface", HFILL }},
1154
1155                 { &hf_mtrace_q_total,
1156                         { "S,G pkt count", "igmp.mtrace.q_total", FT_UINT32, BASE_DEC,
1157                         NULL, 0, "Total number of packets for this source-group pair", HFILL }},
1158
1159                 { &hf_mtrace_q_rtg_proto,
1160                         { "Rtg Protocol", "igmp.mtrace.q_rtg_proto", FT_UINT8, BASE_DEC,
1161                         VALS(mtrace_rtg_vals), 0, "Routing protocol between this and previous hop rtr", HFILL }},
1162
1163                 { &hf_mtrace_q_fwd_ttl,
1164                         { "FwdTTL", "igmp.mtrace.q_fwd_ttl", FT_UINT8, BASE_DEC,
1165                         NULL, 0, "TTL required for forwarding", HFILL }},
1166
1167                 { &hf_mtrace_q_mbz,
1168                         { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8, BASE_HEX,
1169                         NULL, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL }},
1170
1171                 { &hf_mtrace_q_s,
1172                         { "S", "igmp.mtrace.q_s", FT_UINT8, BASE_HEX,
1173                         NULL, 0x40, "Set if S,G packet count is for source network", HFILL }},
1174
1175                 { &hf_mtrace_q_src_mask,
1176                         { "Src Mask", "igmp.mtrace.q_src_mask", FT_UINT8, BASE_HEX,
1177                         NULL, 0x3F, "Source mask length. 63 when forwarding on group state", HFILL }},
1178
1179                 { &hf_mtrace_q_fwd_code,
1180                         { "Forwarding Code", "igmp.mtrace.q_fwd_code", FT_UINT8, BASE_HEX,
1181                         VALS(mtrace_fwd_code_vals), 0, "Forwarding information/error code", HFILL }},
1182
1183         };
1184         static gint *ett[] = {
1185                 &ett_igmp,
1186                 &ett_group_record,
1187                 &ett_sqrv_bits,
1188                 &ett_max_resp,
1189                 &ett_mtrace_block,
1190         };
1191
1192         proto_igmp = proto_register_protocol("Internet Group Management Protocol",
1193                 "IGMP", "igmp");
1194         proto_register_field_array(proto_igmp, hf, array_length(hf));
1195         proto_register_subtree_array(ett, array_length(ett));
1196 }
1197
1198 void
1199 proto_reg_handoff_igmp(void)
1200 {
1201         dissector_handle_t igmp_handle;
1202
1203         igmp_handle = create_dissector_handle(dissect_igmp, proto_igmp);
1204         dissector_add_uint("ip.proto", IP_PROTO_IGMP, igmp_handle);
1205 }
1206
1207 /*
1208  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1209  *
1210  * Local variables:
1211  * c-basic-offset: 4
1212  * tab-width: 8
1213  * indent-tabs-mode: t
1214  * End:
1215  *
1216  * vi: set shiftwidth=4 tabstop=8 noexpandtab:
1217  * :indentSize=4:tabSize=8:noTabs=false:
1218  */
1219