e16f94324decc19a3696f3ee5b80feb9226e2502
[obnox/wireshark/wip.git] / epan / dissectors / packet-igmp.c
1 /* packet-igmp.c   2001 Ronnie Sahlberg <See AUTHORS for email>
2  * Routines for IGMP packet disassembly
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24 /*
25         IGMP is defined in the following RFCs
26         RFC988  Version 0       Obsolete
27         RFC1054 Version 1
28         RFC1112 Version 1       (same as RFC1054 as far as we are concerned)
29         RFC2236 Version 2
30         RFC3376 Version 3
31
32         Size in bytes for each packet
33         type    RFC988  RFC1054 RFC2236 RFC3376  DVMRP  MRDISC  MSNIP  IGAP
34                 v0      v1      v2      v3       v1/v3
35         0x01      20
36         0x02      20
37         0x03      20
38         0x04      20
39         0x05      20
40         0x06      20
41         0x07      20
42         0x08      20
43         0x11               8*     8*     >=12
44         0x12               8*     8*
45         0x13                                     x
46         0x16                      8
47         0x17                      8
48         0x22                            >=8
49         0x23                                                    >=8b
50         0x24                                            >=8a    8b
51         0x25                                            4a      >=8b
52         0x26                                            4a
53         0x40                                                           ??c
54         0x41                                                           ??c
55         0x42                                                           ??c
56
57    * Differs in second byte of protocol. Always 0 in V1
58
59
60         Multicast traceroute was taken from
61         draft-ietf-idmr-traceroute-ipm-07.txt
62
63         Size in bytes for each packet
64         type    draft-ietf-idmr-traceroute-ipm-07.ps
65         0x1e      24 + n*32
66         0x1f      24 + n*32 (n == 0 for Query)
67
68    x DVMRP Protocol  see packet-dvmrp.c
69
70         DVMRP is defined in the following RFCs
71         RFC1075 Version 1
72         draft-ietf-idmr-dvmrp-v3-10.txt Version 3
73
74         V1 and V3 can be distinguished by looking at bytes 6 and 7 in the
75         IGMP header.
76         If header[6]==0xff and header[7]==0x03 we have version 3.
77
78    a MRDISC Protocol  see packet-mrdisc.c
79
80         MRDISC : IGMP Multicast Router DISCovery
81         draft-ietf-idmr-igmp-mrdisc-06.txt
82         TTL == 1 and IP.DST==224.0.0.2 for all packets
83
84    b MSNIP Protocol  see packet-msnip.c
85
86         MSNIP : Multicast Source Notification of Interest Protocol
87         draft-ietf-idmr-msnip-00.txt
88         0x23, 0x24 are sent with ip.dst==224.0.0.22
89         0x25 is sent as unicast.
90
91    c IGAP Protocol  see packet-igap.c
92
93         IGAP : Internet Group membership Authentication Protocol
94         draft-hayashi-igap-03.txt
95
96 */
97
98 #ifdef HAVE_CONFIG_H
99 # include "config.h"
100 #endif
101
102 #include <stdio.h>
103 #include <string.h>
104 #include <glib.h>
105
106 #include <epan/packet.h>
107 #include <epan/ipproto.h>
108 #include <epan/in_cksum.h>
109 #include "packet-igmp.h"
110 #include "packet-dvmrp.h"
111 #include "packet-pim.h"
112 #include "packet-mrdisc.h"
113 #include "packet-msnip.h"
114 #include "packet-igap.h"
115
116 static int proto_igmp = -1;
117 static int hf_type = -1;
118 static int hf_version = -1;
119 static int hf_group_type = -1;
120 static int hf_reply_code = -1;
121 static int hf_reply_pending = -1;
122 static int hf_checksum = -1;
123 static int hf_checksum_bad = -1;
124 static int hf_identifier = -1;
125 static int hf_access_key = -1;
126 static int hf_max_resp = -1;
127 static int hf_max_resp_exp = -1;
128 static int hf_max_resp_mant = -1;
129 static int hf_suppress = -1;
130 static int hf_qrv = -1;
131 static int hf_qqic = -1;
132 static int hf_num_src = -1;
133 static int hf_saddr = -1;
134 static int hf_num_grp_recs = -1;
135 static int hf_record_type = -1;
136 static int hf_aux_data_len = -1;
137 static int hf_maddr = -1;
138 static int hf_aux_data = -1;
139 static int hf_mtrace_max_hops = -1;
140 static int hf_mtrace_saddr = -1;
141 static int hf_mtrace_raddr = -1;
142 static int hf_mtrace_rspaddr = -1;
143 static int hf_mtrace_resp_ttl = -1;
144 static int hf_mtrace_q_id = -1;
145 static int hf_mtrace_q_arrival = -1;
146 static int hf_mtrace_q_inaddr = -1;
147 static int hf_mtrace_q_outaddr = -1;
148 static int hf_mtrace_q_prevrtr = -1;
149 static int hf_mtrace_q_inpkt = -1;
150 static int hf_mtrace_q_outpkt = -1;
151 static int hf_mtrace_q_total = -1;
152 static int hf_mtrace_q_rtg_proto = -1;
153 static int hf_mtrace_q_fwd_ttl = -1;
154 static int hf_mtrace_q_mbz = -1;
155 static int hf_mtrace_q_s = -1;
156 static int hf_mtrace_q_src_mask = -1;
157 static int hf_mtrace_q_fwd_code = -1;
158
159 static int ett_igmp = -1;
160 static int ett_group_record = -1;
161 static int ett_sqrv_bits = -1;
162 static int ett_max_resp = -1;
163 static int ett_mtrace_block = -1;
164
165 #define MC_ALL_ROUTERS          0xe0000002
166 #define MC_ALL_IGMPV3_ROUTERS   0xe0000016
167
168
169 #define IGMP_V0_CREATE_GROUP_REQUEST    0x01
170 #define IGMP_V0_CREATE_GROUP_REPLY      0x02
171 #define IGMP_V0_JOIN_GROUP_REQUEST      0x03
172 #define IGMP_V0_JOIN_GROUP_REPLY        0x04
173 #define IGMP_V0_LEAVE_GROUP_REQUEST     0x05
174 #define IGMP_V0_LEAVE_GROUP_REPLY       0x06
175 #define IGMP_V0_CONFIRM_GROUP_REQUEST   0x07
176 #define IGMP_V0_CONFIRM_GROUP_REPLY     0x08
177 #define IGMP_V1_HOST_MEMBERSHIP_QUERY   0x11
178 #define IGMP_V1_HOST_MEMBERSHIP_REPORT  0x12
179 #define IGMP_DVMRP                      0x13
180 #define IGMP_V1_PIM_ROUTING_MESSAGE     0x14
181 #define IGMP_V2_MEMBERSHIP_REPORT       0x16
182 #define IGMP_V2_LEAVE_GROUP             0x17
183 #define IGMP_TRACEROUTE_RESPONSE        0x1e
184 #define IGMP_TRACEROUTE_QUERY_REQ       0x1f
185 #define IGMP_V3_MEMBERSHIP_REPORT       0x22
186 #define IGMP_TYPE_0x23                  0x23
187 #define IGMP_TYPE_0x24                  0x24
188 #define IGMP_TYPE_0x25                  0x25
189 #define IGMP_TYPE_0x26                  0x26
190
191 #define IGMP_TRACEROUTE_HDR_LEN           24
192 #define IGMP_TRACEROUTE_RSP_LEN           32
193
194 static const value_string commands[] = {
195         {IGMP_V0_CREATE_GROUP_REQUEST,  "Create Group Request"          },
196         {IGMP_V0_CREATE_GROUP_REPLY,    "Create Group Reply"            },
197         {IGMP_V0_JOIN_GROUP_REQUEST,    "Join Group Request"            },
198         {IGMP_V0_JOIN_GROUP_REPLY,      "Join Group Reply"              },
199         {IGMP_V0_LEAVE_GROUP_REQUEST,   "Leave Group Request"           },
200         {IGMP_V0_LEAVE_GROUP_REPLY,     "Leave Group Reply"             },
201         {IGMP_V0_CONFIRM_GROUP_REQUEST, "Confirm Group Request"         },
202         {IGMP_V0_CONFIRM_GROUP_REPLY,   "Confirm Group Reply"           },
203         {IGMP_V1_HOST_MEMBERSHIP_QUERY, "Membership Query"              },
204         {IGMP_V1_HOST_MEMBERSHIP_REPORT,"Membership Report"             },
205         {IGMP_DVMRP,                    "DVMRP Protocol"                },
206         {IGMP_V1_PIM_ROUTING_MESSAGE,   "PIM Routing Message"           },
207         {IGMP_V2_MEMBERSHIP_REPORT,     "Membership Report"             },
208         {IGMP_V2_LEAVE_GROUP,           "Leave Group"                   },
209         {IGMP_TRACEROUTE_RESPONSE,      "Traceroute Response"           },
210         {IGMP_TRACEROUTE_QUERY_REQ,     "Traceroute Query or Request"   },
211         {IGMP_V3_MEMBERSHIP_REPORT,     "Membership Report"             },
212         {0,             NULL}
213 };
214
215 #define IGMP_V3_S               0x08
216 #define IGMP_V3_QRV_MASK        0x07
217
218 #define IGMP_MAX_RESP_EXP       0x70
219 #define IGMP_MAX_RESP_MANT      0x0f
220
221 #define IGMP_V0_GROUP_PUBLIC    0x00
222 #define IGMP_V0_GROUP_PRIVATE   0x01
223
224 static const value_string vs_group_type[] = {
225         {IGMP_V0_GROUP_PUBLIC,          "Public Group"                  },
226         {IGMP_V0_GROUP_PRIVATE,         "Private Group"                 },
227         {0,             NULL}
228 };
229
230 #define IGMP_V0_REPLY_GRANTED   0x00
231 #define IGMP_V0_REPLY_NO_RESOURCES      0x01
232 #define IGMP_V0_REPLY_INVALID_CODE      0x02
233 #define IGMP_V0_REPLY_INVALID_GROUP     0x03
234 #define IGMP_V0_REPLY_INVALID_KEY       0x04
235
236 static const value_string vs_reply_code[] = {
237         {IGMP_V0_REPLY_GRANTED, "Request Granted"       },
238         {IGMP_V0_REPLY_NO_RESOURCES,    "Request Denied, No Resources"  },
239         {IGMP_V0_REPLY_INVALID_CODE,    "Request Denied, Invalid Code"  },
240         {IGMP_V0_REPLY_INVALID_GROUP,   "Request Denied, Invalid Group" },
241         {IGMP_V0_REPLY_INVALID_KEY,     "Request Denied, Invalid Key"   },
242         {0,             NULL}
243 };
244
245 static const true_false_string tfs_s = {
246         "SUPPRESS router side processing",
247         "Do not suppress router side processing"
248 };
249
250 #define IGMP_V3_MODE_IS_INCLUDE         1
251 #define IGMP_V3_MODE_IS_EXCLUDE         2
252 #define IGMP_V3_CHANGE_TO_INCLUDE_MODE  3
253 #define IGMP_V3_CHANGE_TO_EXCLUDE_MODE  4
254 #define IGMP_V3_ALLOW_NEW_SOURCES       5
255 #define IGMP_V3_BLOCK_OLD_SOURCES       6
256
257 static const value_string vs_record_type[] = {
258         {IGMP_V3_MODE_IS_INCLUDE,       "Mode Is Include"               },
259         {IGMP_V3_MODE_IS_EXCLUDE,       "Mode Is Exclude"               },
260         {IGMP_V3_CHANGE_TO_INCLUDE_MODE,"Change To Include Mode"        },
261         {IGMP_V3_CHANGE_TO_EXCLUDE_MODE,"Change To Exclude Mode"        },
262         {IGMP_V3_ALLOW_NEW_SOURCES,     "Allow New Sources"             },
263         {IGMP_V3_BLOCK_OLD_SOURCES,     "Block Old Sources"             },
264         { 0,    NULL}
265 };
266
267 static const value_string mtrace_rtg_vals[] = {
268         {1,  "DVMRP"                                        },
269         {2,  "MOSPF"                                        },
270         {3,  "PIM"                                          },
271         {4,  "CBT"                                          },
272         {5,  "PIM using special routing table"              },
273         {6,  "PIM using a static route"                     },
274         {7,  "DVMRP using a static route"                   },
275         {8,  "PIM using MBGP (aka BGP4+) route"             },
276         {9,  "CBT using special routing table"              },
277         {10, "CBT using a static route"                     },
278         {11, "PIM using state created by Assert processing" },
279         {0,  NULL}
280 };
281
282 static const value_string mtrace_fwd_code_vals[] = {
283         {0x00, "NO_ERROR"       },
284         {0x01, "WRONG_IF"       },
285         {0x02, "PRUNE_SENT"     },
286         {0x03, "PRUNE_RCVD"     },
287         {0x04, "SCOPED"         },
288         {0x05, "NO_ROUTE"       },
289         {0x06, "WRONG_LAST_HOP" },
290         {0x07, "NOT_FORWARDING" },
291         {0x08, "REACHED_RP"     },
292         {0x09, "RPF_IF"         },
293         {0x0A, "NO_MULTICAST"   },
294         {0x0B, "INFO_HIDDEN"    },
295         {0x81, "NO_SPACE"       },
296         {0x82, "OLD_ROUTER"     },
297         {0x83, "ADMIN_PROHIB"   },
298         {0, NULL}
299 };
300
301 #define PRINT_IGMP_VERSION(version)                                     \
302         if (check_col(pinfo->cinfo, COL_INFO)) {                        \
303                 col_add_fstr(pinfo->cinfo, COL_INFO,                    \
304                         "V%d %s",version,val_to_str(type, commands,     \
305                                 "Unknown Type:0x%02x"));                \
306         }                                                               \
307         /* version of IGMP protocol */                                  \
308         proto_tree_add_uint(tree, hf_version, tvb, 0, 0, version);      \
309         /* type of command */                                           \
310         proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);       \
311         offset += 1;
312
313 void igmp_checksum(proto_tree *tree, tvbuff_t *tvb, int hf_index,
314     int hf_index_bad, packet_info *pinfo, guint len)
315 {
316         guint16 cksum, hdrcksum;
317         vec_t cksum_vec[1];
318
319         if (len == 0) {
320                 /*
321                  * Checksum the entire IGMP packet.
322                  */
323                 len = tvb_reported_length(tvb);
324         }
325
326         hdrcksum = tvb_get_ntohs(tvb, 2);
327         if (!pinfo->fragmented && tvb_length(tvb) >= len) {
328                 /*
329                  * The packet isn't part of a fragmented datagram and isn't
330                  * truncated, so we can checksum it.
331                  */
332                 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, len);
333                 cksum_vec[0].len = len;
334
335                 cksum = in_cksum(&cksum_vec[0],1);
336
337                 if (cksum == 0) {
338                         proto_tree_add_uint_format(tree, hf_index,
339                             tvb, 2, 2, hdrcksum,
340                             "Header checksum: 0x%04x [correct]", hdrcksum);
341                 } else {
342                         proto_tree_add_boolean_hidden(tree, hf_index_bad,
343                             tvb, 2, 2, TRUE);
344                         proto_tree_add_uint_format(tree, hf_index,
345                             tvb, 2, 2, hdrcksum,
346                             "Header checksum: 0x%04x [incorrect, should be 0x%04x]", hdrcksum,in_cksum_shouldbe(hdrcksum,cksum));
347                 }
348         } else
349                 proto_tree_add_uint(tree, hf_index, tvb, 2, 2, hdrcksum);
350
351         return;
352 }
353
354
355 /* Unknown IGMP message type */
356 static int
357 dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
358 {
359         int len;
360
361         if (check_col(pinfo->cinfo, COL_INFO)) {
362                 col_add_str(pinfo->cinfo, COL_INFO,
363                         val_to_str(type, commands, "Unknown Type:0x%02x"));
364         }
365
366         /* type of command */
367         proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);
368         offset += 1;
369
370         /* Just call the rest of it "data" */
371         len = tvb_length_remaining(tvb, offset);
372         proto_tree_add_text(tree, tvb, offset, len, "Data");
373         offset += len;
374
375         return offset;
376 }
377
378
379
380 /*************************************************************
381  * IGMP Protocol dissectors
382  *************************************************************/
383 static int
384 dissect_v3_max_resp(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
385 {
386         proto_tree *tree;
387         proto_item *item;
388         guint8 bits;
389         guint32 tsecs;
390
391         bits = tvb_get_guint8(tvb, offset);
392         if (bits&0x80) {
393                 tsecs = ((bits&IGMP_MAX_RESP_MANT)|0x10);
394                 tsecs = tsecs << ( ((bits&IGMP_MAX_RESP_EXP)>>4) + 3);
395         } else {
396                 tsecs = bits;
397         }
398
399         item = proto_tree_add_uint_format(parent_tree, hf_max_resp, tvb,
400                         offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)",tsecs*0.1,bits);
401
402         if (bits&0x80) {
403                 tree = proto_item_add_subtree(item, ett_max_resp);
404
405                 proto_tree_add_uint(tree, hf_max_resp_exp, tvb, offset, 1,
406                         bits);
407                 proto_tree_add_uint(tree, hf_max_resp_mant, tvb, offset, 1,
408                         bits);
409         }
410
411         offset += 1;
412
413         return offset;
414 }
415
416 static int
417 dissect_v3_sqrv_bits(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
418 {
419         proto_tree *tree;
420         proto_item *item;
421         guint8 bits;
422
423         bits = tvb_get_guint8(tvb, offset);
424
425         item = proto_tree_add_text(parent_tree, tvb, offset, 1,
426                 "QRV=%d S=%s", bits&IGMP_V3_QRV_MASK,
427                         (bits&IGMP_V3_S)?tfs_s.true_string:tfs_s.false_string);
428         tree = proto_item_add_subtree(item, ett_sqrv_bits);
429
430         /* S flag */
431         proto_tree_add_boolean(tree, hf_suppress, tvb, offset, 1, bits);
432         /* QRV */
433         proto_tree_add_uint(tree, hf_qrv, tvb, offset, 1, bits);
434         offset += 1;
435
436         return offset;
437 }
438
439 static int
440 dissect_v3_group_record(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
441 {
442         proto_tree *tree;
443         proto_item *item;
444         int old_offset = offset;
445         guint8  adl;
446         guint16 num;
447         guint32 ip;
448
449         ip = tvb_get_ipv4(tvb, offset+4);
450         item = proto_tree_add_text(parent_tree, tvb, offset, -1,
451                 "Group Record : %s  %s",
452                         ip_to_str((guint8*)&ip),
453                         val_to_str(tvb_get_guint8(tvb, offset), vs_record_type,"")
454                 );
455         tree = proto_item_add_subtree(item, ett_group_record);
456
457         /* record type */
458         proto_tree_add_item(tree, hf_record_type, tvb, offset, 1, FALSE);
459         offset += 1;
460
461         /* aux data len */
462         adl = tvb_get_guint8(tvb, offset);
463         proto_tree_add_uint(tree, hf_aux_data_len, tvb, offset, 1, adl);
464         offset += 1;
465
466         /*number of sources*/
467         num = tvb_get_ntohs(tvb, offset);
468         proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
469         offset += 2;
470
471         /* multicast address */
472         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
473         offset += 4;
474
475         /* source addresses */
476         while(num--){
477                 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, FALSE);
478                 offset += 4;
479         }
480
481         /* aux data */
482         if(adl){
483                 proto_tree_add_item(tree, hf_aux_data, tvb, offset, adl*4,
484                     FALSE);
485                 offset += adl*4;
486         }
487
488         proto_item_set_len(item, offset-old_offset);
489         return offset;
490 }
491
492 /* dissectors for version 3, rfc???? */
493 static int
494 dissect_igmp_v3_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
495 {
496         guint16 num;
497
498         PRINT_IGMP_VERSION(3);
499
500         /* skip reserved field*/
501         offset += 1;
502
503         /* checksum */
504         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
505         offset += 2;
506
507         /* skip reserved field */
508         offset += 2;
509
510         /* number of group records */
511         num = tvb_get_ntohs(tvb, offset);
512         proto_tree_add_uint(tree, hf_num_grp_recs, tvb, offset, 2, num);
513         offset += 2;
514
515         while (num--) {
516                 offset = dissect_v3_group_record(tvb, tree, offset);
517         }
518
519         return offset;
520 }
521
522 static int
523 dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
524 {
525         guint16 num;
526
527         PRINT_IGMP_VERSION(3);
528
529         num = tvb_get_ntohs(tvb, offset+9);
530         /* max resp code */
531         offset = dissect_v3_max_resp(tvb, tree, offset);
532
533         /* checksum */
534         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
535         offset += 2;
536
537         /* group address */
538         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
539         offset +=4;
540
541         /* bitmask for S and QRV */
542         offset = dissect_v3_sqrv_bits(tvb, tree, offset);
543
544         /* qqic */
545         proto_tree_add_item(tree, hf_qqic, tvb, offset, 1, FALSE);
546         offset += 1;
547
548         /*number of sources*/
549         proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
550         offset += 2;
551
552         while(num--){
553                 proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, FALSE);
554                 offset += 4;
555         }
556
557         return offset;
558 }
559
560 /* dissector for version 2, rfc2236 */
561 static int
562 dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
563 {
564         guint8 tsecs;
565
566         PRINT_IGMP_VERSION(2);
567
568         /* max resp time */
569         tsecs = tvb_get_guint8(tvb, offset);
570         proto_tree_add_uint_format(tree, hf_max_resp, tvb,
571                 offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)", tsecs*0.1,tsecs);
572         offset += 1;
573
574         /* checksum */
575         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
576         offset += 2;
577
578         /* group address */
579         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
580         offset +=4;
581
582         return offset;
583 }
584
585 /* dissector for version 1, rfc1054 */
586 static int
587 dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
588 {
589         PRINT_IGMP_VERSION(1);
590
591         /* skip unused byte */
592         offset += 1;
593
594         /* checksum */
595         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
596         offset += 2;
597
598         /* group address */
599         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
600         offset +=4;
601
602         return offset;
603 }
604
605 /* dissector for version 0, rfc988 */
606 static int
607 dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
608 {
609         unsigned char code;
610
611         PRINT_IGMP_VERSION(0);
612
613         /* Code */
614         code = tvb_get_guint8(tvb, offset);
615         if (type==IGMP_V0_CREATE_GROUP_REQUEST) {
616                 proto_tree_add_uint(tree, hf_group_type, tvb, offset, 1, code);
617         } else if (!(type&0x01)) {
618                 if (code <5) {
619                         proto_tree_add_uint(tree, hf_reply_code, tvb, offset, 1, code);
620                 } else {
621                         proto_tree_add_uint(tree, hf_reply_pending, tvb, offset, 1, code);
622                 }
623         }
624         offset += 1;
625
626         /* checksum */
627         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 20);
628         offset += 2;
629
630         /* identifier */
631         proto_tree_add_item(tree, hf_identifier, tvb, offset, 4, FALSE);
632         offset += 4;
633
634         /* group address */
635         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
636         offset +=4;
637
638         /* access key */
639         proto_tree_add_item(tree, hf_access_key, tvb, offset, 8, FALSE);
640         offset +=8;
641
642         return offset;
643 }
644
645 /* dissector for multicast traceroute, rfc???? */
646 static int
647 dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
648 {
649         const char *typestr, *blocks = NULL;
650         char buf[20];
651
652         /* All multicast traceroute packets (Query, Request and
653          * Response) have the same fixed header. Request and Response
654          * have one or more response data blocks following this fixed
655          * header. Since Query and Request share the same IGMP type,
656          * the method to differentiate between them is to check the
657          * IGMP packet length. Queries are only
658          * IGMP_TRACEROUTE_HDR_LEN bytes long.
659          */
660         if (type == IGMP_TRACEROUTE_RESPONSE) {
661                 int i = (tvb_reported_length_remaining(tvb, offset) - IGMP_TRACEROUTE_HDR_LEN) / IGMP_TRACEROUTE_RSP_LEN;
662                 g_snprintf(buf, sizeof buf, ", %d block%s", i, plurality(i, "", "s"));
663                 typestr = "Traceroute Response";
664                 blocks = buf;
665         } else if (tvb_reported_length_remaining(tvb, offset) == IGMP_TRACEROUTE_HDR_LEN)
666                 typestr = "Traceroute Query";
667         else
668                 typestr = "Traceroute Request";
669
670         if (check_col(pinfo->cinfo, COL_INFO)) {
671                 col_set_str(pinfo->cinfo, COL_INFO, typestr);
672                 if (blocks) col_append_str(pinfo->cinfo, COL_INFO, blocks);
673         }
674
675         proto_tree_add_uint_format(tree, hf_type, tvb, offset, 1, type,
676             "Type: %s (0x%02x)", typestr, type);
677         offset += 1;
678
679         /* maximum number of hops that the requester wants to trace */
680         proto_tree_add_item(tree, hf_mtrace_max_hops, tvb, offset, 1, FALSE);
681         offset += 1;
682
683         /* checksum */
684         igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
685         offset += 2;
686
687         /* group address to be traced */
688         proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
689         offset += 4;
690
691         /* address of multicast source for the path being traced */
692         proto_tree_add_item(tree, hf_mtrace_saddr, tvb, offset, 4, FALSE);
693         offset += 4;
694
695         /* address of multicast receiver for the path being traced */
696         proto_tree_add_item(tree, hf_mtrace_raddr, tvb, offset, 4, FALSE);
697         offset += 4;
698
699         /* address where the completed traceroute response packet gets sent */
700         proto_tree_add_item(tree, hf_mtrace_rspaddr, tvb, offset, 4, FALSE);
701         offset += 4;
702
703         /* for multicasted responses, TTL at which to multicast the response */
704         proto_tree_add_item(tree, hf_mtrace_resp_ttl, tvb, offset, 1, FALSE);
705         offset += 1;
706
707         /* unique identifier for this traceroute request (for e.g. duplicate/delay detection) */
708         proto_tree_add_item(tree, hf_mtrace_q_id, tvb, offset, 3, FALSE);
709         offset += 3;
710
711         /* If this was Query, we only had the fixed header */
712         if (tvb_reported_length_remaining(tvb, offset) == 0)
713                 return offset;
714
715         /* Loop through the response data blocks */
716         while (tvb_reported_length_remaining(tvb, offset) >= IGMP_TRACEROUTE_RSP_LEN) {
717                 proto_item *bi;
718                 proto_tree *block_tree;
719
720                 bi = proto_tree_add_text(tree, tvb, offset, IGMP_TRACEROUTE_RSP_LEN,
721                                          "Response data block: %s -> %s,  Proto: %s,  Forwarding Code: %s",
722                                          ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)),
723                                          ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)),
724                                          val_to_str(tvb_get_guint8(tvb, offset + 28), mtrace_rtg_vals, "Unknown"),
725                                          val_to_str(tvb_get_guint8(tvb, offset + 31), mtrace_fwd_code_vals, "Unknown"));
726                 block_tree = proto_item_add_subtree(bi, ett_mtrace_block);
727
728                 /* Query Arrival Time */
729                 proto_tree_add_item(block_tree, hf_mtrace_q_arrival, tvb, offset, 4, FALSE);
730                 offset += 4;
731
732                 /* Incoming Interface Address */
733                 proto_tree_add_item(block_tree, hf_mtrace_q_inaddr, tvb, offset, 4, FALSE);
734                 offset += 4;
735
736                 /* Outgoing Interface Address */
737                 proto_tree_add_item(block_tree, hf_mtrace_q_outaddr, tvb, offset, 4, FALSE);
738                 offset += 4;
739
740                 /* Previous-Hop Router Address */
741                 proto_tree_add_item(block_tree, hf_mtrace_q_prevrtr, tvb, offset, 4, FALSE);
742                 offset += 4;
743
744                 /* Input packet count on incoming interface */
745                 proto_tree_add_item(block_tree, hf_mtrace_q_inpkt, tvb, offset, 4, FALSE);
746                 offset += 4;
747
748                 /* Output packet count on outgoing interface */
749                 proto_tree_add_item(block_tree, hf_mtrace_q_outpkt, tvb, offset, 4, FALSE);
750                 offset += 4;
751
752                 /* Total number of packets for this source-group pair */
753                 proto_tree_add_item(block_tree, hf_mtrace_q_total, tvb, offset, 4, FALSE);
754                 offset += 4;
755
756                 /* Routing protocol in use between this and previous-hop router */
757                 proto_tree_add_item(block_tree, hf_mtrace_q_rtg_proto, tvb, offset, 1, FALSE);
758                 offset += 1;
759
760                 /* TTL that a packet is required to be forwarded */
761                 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_ttl, tvb, offset, 1, FALSE);
762                 offset += 1;
763
764                 /* Must be zeroed and ignored bit, S bit and src network mask length */
765                 proto_tree_add_item(block_tree, hf_mtrace_q_mbz, tvb, offset, 1, FALSE);
766                 proto_tree_add_item(block_tree, hf_mtrace_q_s, tvb, offset, 1, FALSE);
767                 proto_tree_add_item(block_tree, hf_mtrace_q_src_mask, tvb, offset, 1, FALSE);
768                 offset += 1;
769
770                 /* Forwarding information/error code */
771                 proto_tree_add_item(block_tree, hf_mtrace_q_fwd_code, tvb, offset, 1, FALSE);
772                 offset += 1;
773         }
774
775
776         return offset;
777 }
778
779 static void
780 dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
781 {
782         proto_tree *tree;
783         proto_item *item;
784         int offset = 0;
785         unsigned char type;
786         guint32 dst;
787
788         item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, FALSE);
789         tree = proto_item_add_subtree(item, ett_igmp);
790
791
792         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
793                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP");
794         }
795         if (check_col(pinfo->cinfo, COL_INFO)) {
796                 col_clear(pinfo->cinfo, COL_INFO);
797         }
798
799
800         type = tvb_get_guint8(tvb, offset);
801
802
803         /* version 0 */
804         if ((type&0xf0)==0){
805                 offset = dissect_igmp_v0(tvb, pinfo, tree, type, offset);
806         }
807
808
809         switch (type) {
810
811         case IGMP_V1_HOST_MEMBERSHIP_QUERY:     /* 0x11 v1/v2/v3 */
812                 if ( (pinfo->iplen-pinfo->iphdrlen)>=12 ) {
813                         /* version 3 */
814                         offset = dissect_igmp_v3_query(tvb, pinfo, tree, type, offset);
815                 } else {
816                         /* v1 and v2 differs in second byte of header */
817                         if (tvb_get_guint8(tvb, offset+1)) {
818                                 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
819                         } else {
820                                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
821                         }
822                 }
823                 break;
824
825         case IGMP_V1_HOST_MEMBERSHIP_REPORT:    /* 0x12  v1 only */
826                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
827                 break;
828
829         case IGMP_DVMRP:
830                 offset = dissect_dvmrp(tvb, pinfo, parent_tree, offset);
831                 break;
832
833         case IGMP_V1_PIM_ROUTING_MESSAGE:
834                 offset = dissect_pimv1(tvb, pinfo, parent_tree, offset);
835                 break;
836
837         case IGMP_V2_MEMBERSHIP_REPORT:
838         case IGMP_V2_LEAVE_GROUP:
839                 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
840                 break;
841
842         case IGMP_TRACEROUTE_RESPONSE:
843         case IGMP_TRACEROUTE_QUERY_REQ:
844                 offset = dissect_igmp_mtrace(tvb, pinfo, tree, type, offset);
845                 break;
846
847         case IGMP_V3_MEMBERSHIP_REPORT:
848                 offset = dissect_igmp_v3_response(tvb, pinfo, tree, type, offset);
849                 break;
850
851         case IGMP_TYPE_0x23:
852                 dst = g_htonl(MC_ALL_IGMPV3_ROUTERS);
853                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
854                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
855                 }
856                 break;
857
858         case IGMP_TYPE_0x24:
859                 dst = g_htonl(MC_ALL_ROUTERS);
860                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
861                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
862                 }
863                 dst = g_htonl(MC_ALL_IGMPV3_ROUTERS);
864                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
865                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
866                 }
867                 break;
868
869         case IGMP_TYPE_0x25:
870                 if ( (pinfo->iplen-pinfo->iphdrlen)>=8 ) {
871                         /* if len of igmp packet>=8 we assume it is MSNIP */
872                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
873                 } else {
874                         /* ok its not MSNIP, check if it might be MRDISC */
875                         dst = g_htonl(MC_ALL_ROUTERS);
876                         if (!memcmp(pinfo->dst.data, &dst, 4)) {
877                                 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
878                         }
879                 }
880                 break;
881
882         case IGMP_TYPE_0x26:
883                 dst = g_htonl(MC_ALL_ROUTERS);
884                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
885                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
886                 }
887                 break;
888
889         case IGMP_IGAP_JOIN:
890         case IGMP_IGAP_QUERY:
891         case IGMP_IGAP_LEAVE:
892                 offset = dissect_igap(tvb, pinfo, parent_tree, offset);
893                 break;
894
895         default:
896                 offset = dissect_igmp_unknown(tvb, pinfo, tree, type, offset);
897                 break;
898         }
899
900
901         proto_item_set_len(item, offset);
902 }
903
904 void
905 proto_register_igmp(void)
906 {
907         static hf_register_info hf[] = {
908                 { &hf_type,
909                         { "Type", "igmp.type", FT_UINT8, BASE_HEX,
910                           VALS(commands), 0, "IGMP Packet Type", HFILL }},
911
912                 { &hf_version,
913                         { "IGMP Version", "igmp.version", FT_UINT8, BASE_DEC,
914                           NULL, 0, "IGMP Version", HFILL }},
915
916                 { &hf_group_type,
917                         { "Type Of Group", "igmp.group_type", FT_UINT8, BASE_DEC,
918                           VALS(vs_group_type), 0, "IGMP V0 Type Of Group", HFILL }},
919
920                 { &hf_reply_code,
921                         { "Reply", "igmp.reply", FT_UINT8, BASE_DEC,
922                           VALS(vs_reply_code), 0, "IGMP V0 Reply", HFILL }},
923
924                 { &hf_reply_pending,
925                         { "Reply Pending", "igmp.reply.pending", FT_UINT8, BASE_DEC,
926                           NULL, 0, "IGMP V0 Reply Pending, Retry in this many seconds", HFILL }},
927
928                 { &hf_checksum,
929                         { "Checksum", "igmp.checksum", FT_UINT16, BASE_HEX,
930                           NULL, 0, "IGMP Checksum", HFILL }},
931
932                 { &hf_checksum_bad,
933                         { "Bad Checksum", "igmp.checksum_bad", FT_BOOLEAN, BASE_NONE,
934                           NULL, 0, "Bad IGMP Checksum", HFILL }},
935
936                 { &hf_identifier,
937                         { "Identifier", "igmp.identifier", FT_UINT32, BASE_DEC,
938                           NULL, 0, "IGMP V0 Identifier", HFILL }},
939
940                 { &hf_access_key,
941                         { "Access Key", "igmp.access_key", FT_BYTES, BASE_HEX,
942                           NULL, 0, "IGMP V0 Access Key", HFILL }},
943
944                 { &hf_max_resp,
945                         { "Max Resp Time", "igmp.max_resp", FT_UINT8, BASE_DEC,
946                           NULL, 0, "Max Response Time", HFILL }},
947
948                 { &hf_suppress,
949                         { "S", "igmp.s", FT_BOOLEAN, 8,
950                           TFS(&tfs_s), IGMP_V3_S, "Suppress Router Side Processing", HFILL }},
951
952                 { &hf_qrv,
953                         { "QRV", "igmp.qrv", FT_UINT8, BASE_DEC,
954                         NULL, IGMP_V3_QRV_MASK, "Querier's Robustness Value", HFILL }},
955
956                 { &hf_qqic,
957                         { "QQIC", "igmp.qqic", FT_UINT8, BASE_DEC,
958                           NULL, 0, "Querier's Query Interval Code", HFILL }},
959
960                 { &hf_num_src,
961                         { "Num Src", "igmp.num_src", FT_UINT16, BASE_DEC,
962                           NULL, 0, "Number Of Sources", HFILL }},
963
964                 { &hf_saddr,
965                         { "Source Address", "igmp.saddr", FT_IPv4, BASE_NONE,
966                           NULL, 0, "Source Address", HFILL }},
967
968                 { &hf_num_grp_recs,
969                         { "Num Group Records", "igmp.num_grp_recs", FT_UINT16, BASE_DEC,
970                           NULL, 0, "Number Of Group Records", HFILL }},
971
972                 { &hf_record_type,
973                         { "Record Type", "igmp.record_type", FT_UINT8, BASE_DEC,
974                         VALS(vs_record_type), 0, "Record Type", HFILL }},
975
976                 { &hf_aux_data_len,
977                         { "Aux Data Len", "igmp.aux_data_len", FT_UINT8, BASE_DEC,
978                         NULL, 0, "Aux Data Len, In units of 32bit words", HFILL }},
979
980                 { &hf_maddr,
981                         { "Multicast Address", "igmp.maddr", FT_IPv4, BASE_NONE,
982                           NULL, 0, "Multicast Address", HFILL }},
983
984                 { &hf_aux_data,
985                         { "Aux Data", "igmp.aux_data", FT_BYTES, BASE_HEX,
986                           NULL, 0, "IGMP V3 Auxiliary Data", HFILL }},
987
988                 { &hf_max_resp_exp,
989                         { "Exponent", "igmp.max_resp.exp", FT_UINT8, BASE_HEX,
990                         NULL, IGMP_MAX_RESP_EXP, "Maxmimum Response Time, Exponent", HFILL }},
991
992                 { &hf_max_resp_mant,
993                         { "Mantissa", "igmp.max_resp.mant", FT_UINT8, BASE_HEX,
994                         NULL, IGMP_MAX_RESP_MANT, "Maxmimum Response Time, Mantissa", HFILL }},
995
996                 { &hf_mtrace_max_hops,
997                         { "# hops", "igmp.mtrace.max_hops", FT_UINT8, BASE_DEC,
998                         NULL, 0, "Maxmimum Number of Hops to Trace", HFILL }},
999
1000                 { &hf_mtrace_saddr,
1001                         { "Source Address", "igmp.mtrace.saddr", FT_IPv4, BASE_NONE,
1002                           NULL, 0, "Multicast Source for the Path Being Traced", HFILL }},
1003
1004                 { &hf_mtrace_raddr,
1005                         { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4, BASE_NONE,
1006                           NULL, 0, "Multicast Receiver for the Path Being Traced", HFILL }},
1007
1008                 { &hf_mtrace_rspaddr,
1009                         { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4, BASE_NONE,
1010                           NULL, 0, "Destination of Completed Traceroute Response", HFILL }},
1011
1012                 { &hf_mtrace_resp_ttl,
1013                         { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8, BASE_DEC,
1014                         NULL, 0, "TTL for Multicasted Responses", HFILL }},
1015
1016                 { &hf_mtrace_q_id,
1017                         { "Query ID", "igmp.mtrace.q_id", FT_UINT24, BASE_DEC,
1018                         NULL, 0, "Identifier for this Traceroute Request", HFILL }},
1019
1020                 { &hf_mtrace_q_arrival,
1021                         { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32, BASE_DEC,
1022                         NULL, 0, "Query Arrival Time", HFILL }},
1023
1024                 { &hf_mtrace_q_inaddr,
1025                         { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4, BASE_NONE,
1026                         NULL, 0, "Incoming Interface Address", HFILL }},
1027
1028                 { &hf_mtrace_q_outaddr,
1029                         { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4, BASE_NONE,
1030                         NULL, 0, "Outgoing Interface Address", HFILL }},
1031
1032                 { &hf_mtrace_q_prevrtr,
1033                         { "Previous rtr addr", "igmp.mtrace.q_prevrtr", FT_IPv4, BASE_NONE,
1034                         NULL, 0, "Previous-Hop Router Address", HFILL }},
1035
1036                 { &hf_mtrace_q_inpkt,
1037                         { "In pkts", "igmp.mtrace.q_inpkt", FT_UINT32, BASE_DEC,
1038                         NULL, 0, "Input packet count on incoming interface", HFILL }},
1039
1040                 { &hf_mtrace_q_outpkt,
1041                         { "Out pkts", "igmp.mtrace.q_outpkt", FT_UINT32, BASE_DEC,
1042                         NULL, 0, "Output packet count on outgoing interface", HFILL }},
1043
1044                 { &hf_mtrace_q_total,
1045                         { "S,G pkt count", "igmp.mtrace.q_total", FT_UINT32, BASE_DEC,
1046                         NULL, 0, "Total number of packets for this source-group pair", HFILL }},
1047
1048                 { &hf_mtrace_q_rtg_proto,
1049                         { "Rtg Protocol", "igmp.mtrace.q_rtg_proto", FT_UINT8, BASE_DEC,
1050                         VALS(&mtrace_rtg_vals), 0, "Routing protocol between this and previous hop rtr", HFILL }},
1051
1052                 { &hf_mtrace_q_fwd_ttl,
1053                         { "FwdTTL", "igmp.mtrace.q_fwd_ttl", FT_UINT8, BASE_DEC,
1054                         NULL, 0, "TTL required for forwarding", HFILL }},
1055
1056                 { &hf_mtrace_q_mbz,
1057                         { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8, BASE_HEX,
1058                         NULL, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL }},
1059
1060                 { &hf_mtrace_q_s,
1061                         { "S", "igmp.mtrace.q_s", FT_UINT8, BASE_HEX,
1062                         NULL, 0x40, "Set if S,G packet count is for source network", HFILL }},
1063
1064                 { &hf_mtrace_q_src_mask,
1065                         { "Src Mask", "igmp.mtrace.q_src_mask", FT_UINT8, BASE_HEX,
1066                         NULL, 0x3F, "Source mask length. 63 when forwarding on group state", HFILL }},
1067
1068                 { &hf_mtrace_q_fwd_code,
1069                         { "Forwarding Code", "igmp.mtrace.q_fwd_code", FT_UINT8, BASE_HEX,
1070                         VALS(&mtrace_fwd_code_vals), 0, "Forwarding information/error code", HFILL }},
1071
1072         };
1073         static gint *ett[] = {
1074                 &ett_igmp,
1075                 &ett_group_record,
1076                 &ett_sqrv_bits,
1077                 &ett_max_resp,
1078                 &ett_mtrace_block,
1079         };
1080
1081         proto_igmp = proto_register_protocol("Internet Group Management Protocol",
1082             "IGMP", "igmp");
1083         proto_register_field_array(proto_igmp, hf, array_length(hf));
1084         proto_register_subtree_array(ett, array_length(ett));
1085 }
1086
1087 void
1088 proto_reg_handoff_igmp(void)
1089 {
1090         dissector_handle_t igmp_handle;
1091
1092         igmp_handle = create_dissector_handle(dissect_igmp, proto_igmp);
1093         dissector_add("ip.proto", IP_PROTO_IGMP, igmp_handle);
1094 }