Put the IGMP type field value into the PIM tree, as is done for other
[obnox/wireshark/wip.git] / packet-igmp.c
1 /* packet-igmp.c   2001 Ronnie Sahlberg <rsahlber@bigpond.net.au>
2  * Routines for IGMP packet disassembly
3  *
4  * $Id: packet-igmp.c,v 1.8 2001/07/02 09:23:02 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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         draft-ietf-idmr-igmp-v3-07      Version 3
31
32         Size in bytes for each packet
33         type    RFC988  RFC1054 RFC2236 RFC????  DVMRP  MRDISC  MSNIP
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
54
55    * Differs in second byte of protocol. Always 0 in V1
56
57    x DVMRP Protocol  see packet-dvmrp.c
58
59         DVMRP is defined in the following RFCs
60         RFC1075 Version 1
61         draft-ietf-idmr-dvmrp-v3-10.txt Version 3
62
63         V1 and V3 can be distinguished by looking at bytes 6 and 7 in the 
64         IGMP header.
65         If header[6]==0xff and header[7]==0x03 we have version 3.
66
67    a MRDISC Protocol  see packet-mrdisc.c
68
69         MRDISC : IGMP Multicast Router DISCovery
70         draft-ietf-idmr-igmp-mrdisc-06.txt
71         TTL == 1 and IP.DST==224.0.0.2 for all packets
72
73    b MSNIP Protocol  see packet-msnip.c
74
75         MSNIP : Multicast Source Notification of Interest Protocol
76         draft-ietf-idmr-msnip-00.txt
77         0x23, 0x24 are sent with ip.dst==224.0.0.22
78         0x25 is sent as unicast.
79
80 */
81
82 #ifdef HAVE_CONFIG_H
83 # include "config.h"
84 #endif
85
86 #ifdef HAVE_SYS_TYPES_H
87 # include <sys/types.h>
88 #endif
89
90 #include <stdio.h>
91 #include <string.h>
92 #include <glib.h>
93
94 #include "packet.h"
95 #include "ipproto.h"
96 #include "in_cksum.h"
97 #include "packet-dvmrp.h"
98 #include "packet-pim.h"
99 #include "packet-mrdisc.h"
100 #include "packet-msnip.h"
101
102 static int proto_igmp = -1;
103 static int hf_type = -1;
104 static int hf_version = -1;
105 static int hf_group_type = -1;
106 static int hf_reply_code = -1;
107 static int hf_reply_pending = -1;
108 static int hf_checksum = -1;
109 static int hf_checksum_bad = -1;
110 static int hf_identifier = -1;
111 static int hf_access_key = -1;
112 static int hf_max_resp = -1;
113 static int hf_max_resp_exp = -1;
114 static int hf_max_resp_mant = -1;
115 static int hf_supress = -1;
116 static int hf_qrv = -1;
117 static int hf_qqic = -1;
118 static int hf_num_src = -1;
119 static int hf_saddr = -1;
120 static int hf_num_grp_recs = -1;
121 static int hf_record_type = -1;
122 static int hf_aux_data_len = -1;
123 static int hf_maddr = -1;
124 static int hf_aux_data = -1;
125
126 static int ett_igmp = -1;
127 static int ett_group_record = -1;
128 static int ett_sqrv_bits = -1;
129 static int ett_max_resp = -1;
130
131 #define MC_ALL_ROUTERS          0xe0000002
132 #define MC_ALL_IGMPV3_ROUTERS   0xe0000016
133
134
135 #define IGMP_V0_CREATE_GROUP_REQUEST    0x01
136 #define IGMP_V0_CREATE_GROUP_REPLY      0x02
137 #define IGMP_V0_JOIN_GROUP_REQUEST      0x03
138 #define IGMP_V0_JOIN_GROUP_REPLY        0x04
139 #define IGMP_V0_LEAVE_GROUP_REQUEST     0x05
140 #define IGMP_V0_LEAVE_GROUP_REPLY       0x06
141 #define IGMP_V0_CONFIRM_GROUP_REQUEST   0x07
142 #define IGMP_V0_CONFIRM_GROUP_REPLY     0x08
143 #define IGMP_V1_HOST_MEMBERSHIP_QUERY   0x11
144 #define IGMP_V1_HOST_MEMBERSHIP_REPORT  0x12
145 #define IGMP_DVMRP                      0x13
146 #define IGMP_V1_PIM_ROUTING_MESSAGE     0x14
147 #define IGMP_V2_MEMBERSHIP_REPORT       0x16
148 #define IGMP_V2_LEAVE_GROUP             0x17
149 #define IGMP_V1_TRACEROUTE_RESPONSE     0x1e    /* XXX */
150 #define IGMP_V1_TRACEROUTE_MESSAGE      0x1f    /* XXX */
151 #define IGMP_V3_MEMBERSHIP_REPORT       0x22
152 #define IGMP_TYPE_0x23                  0x23
153 #define IGMP_TYPE_0x24                  0x24
154 #define IGMP_TYPE_0x25                  0x25
155 #define IGMP_TYPE_0x26                  0x26
156         
157 static const value_string commands[] = {
158         {IGMP_V0_CREATE_GROUP_REQUEST,  "Create Group Request"          },
159         {IGMP_V0_CREATE_GROUP_REPLY,    "Create Group Reply"            },
160         {IGMP_V0_JOIN_GROUP_REQUEST,    "Join Group Request"            },
161         {IGMP_V0_JOIN_GROUP_REPLY,      "Join Group Reply"              },
162         {IGMP_V0_LEAVE_GROUP_REQUEST,   "Leave Group Request"           },
163         {IGMP_V0_LEAVE_GROUP_REPLY,     "Leave Group Reply"             },
164         {IGMP_V0_CONFIRM_GROUP_REQUEST, "Confirm Group Request"         },
165         {IGMP_V0_CONFIRM_GROUP_REPLY,   "Confirm Group Reply"           },
166         {IGMP_V1_HOST_MEMBERSHIP_QUERY, "Membership Query"              },
167         {IGMP_V1_HOST_MEMBERSHIP_REPORT,"Membership Report"             },
168         {IGMP_DVMRP,                    "DVMRP Protocol"                },
169         {IGMP_V1_PIM_ROUTING_MESSAGE,   "PIM Routing Message"           },
170         {IGMP_V2_MEMBERSHIP_REPORT,     "Membership Report"             },
171         {IGMP_V2_LEAVE_GROUP,           "Leave Group"                   },
172         {IGMP_V1_TRACEROUTE_RESPONSE,   "Traceroute Response"           },
173         {IGMP_V1_TRACEROUTE_MESSAGE,    "Traceroute Message"            },
174         {IGMP_V3_MEMBERSHIP_REPORT,     "Membership Report"             },
175         {0,             NULL}
176 };
177
178 #define IGMP_V3_S               0x08
179 #define IGMP_V3_QRV_MASK        0x07
180
181 #define IGMP_MAX_RESP_EXP       0x70
182 #define IGMP_MAX_RESP_MANT      0x0f
183
184 #define IGMP_V0_GROUP_PUBLIC    0x00
185 #define IGMP_V0_GROUP_PRIVATE   0x01
186
187 static const value_string vs_group_type[] = {
188         {IGMP_V0_GROUP_PUBLIC,          "Public Group"                  },
189         {IGMP_V0_GROUP_PRIVATE,         "Private Group"                 },
190         {0,             NULL}
191 };
192
193 #define IGMP_V0_REPLY_GRANTED   0x00
194 #define IGMP_V0_REPLY_NO_RESOURCES      0x01
195 #define IGMP_V0_REPLY_INVALID_CODE      0x02
196 #define IGMP_V0_REPLY_INVALID_GROUP     0x03
197 #define IGMP_V0_REPLY_INVALID_KEY       0x04
198
199 static const value_string vs_reply_code[] = {
200         {IGMP_V0_REPLY_GRANTED, "Request Granted"       },
201         {IGMP_V0_REPLY_NO_RESOURCES,    "Request Denied, No Resources"  },
202         {IGMP_V0_REPLY_INVALID_CODE,    "Request Denied, Invalid Code"  },
203         {IGMP_V0_REPLY_INVALID_GROUP,   "Request Denied, Invalid Group" },
204         {IGMP_V0_REPLY_INVALID_KEY,     "Request Denied, Invalid Key"   },
205         {0,             NULL}
206 };
207
208 static const true_false_string tfs_s = {
209         "SUPRESS router side processing",
210         "Do not supress router side processing"
211 };
212
213 #define IGMP_V3_MODE_IS_INCLUDE         1
214 #define IGMP_V3_MODE_IS_EXCLUDE         2
215 #define IGMP_V3_CHANGE_TO_INCLUDE_MODE  3
216 #define IGMP_V3_CHANGE_TO_EXCLUDE_MODE  4
217 #define IGMP_V3_ALLOW_NEW_SOURCES       5
218 #define IGMP_V3_BLOCK_OLD_SOURCES       6
219
220 static const value_string vs_record_type[] = {
221         {IGMP_V3_MODE_IS_INCLUDE,       "Mode Is Include"               },
222         {IGMP_V3_MODE_IS_EXCLUDE,       "Mode Is Exclude"               },
223         {IGMP_V3_CHANGE_TO_INCLUDE_MODE,"Change To Include Mode"        },
224         {IGMP_V3_CHANGE_TO_EXCLUDE_MODE,"Change To Exclude Mode"        },
225         {IGMP_V3_ALLOW_NEW_SOURCES,     "Allow New Sources"             },
226         {IGMP_V3_BLOCK_OLD_SOURCES,     "Block Old Sources"             },
227         { 0,    NULL}
228 };
229
230 #define PRINT_IGMP_VERSION(version)                                     \
231         if (check_col(pinfo->fd, COL_INFO)) {                           \
232                 col_add_fstr(pinfo->fd, COL_INFO,                       \
233                         "V%d %s",version,val_to_str(type, commands,     \
234                                 "Unknown Type:0x%02x"));                \
235         }                                                               \
236         /* version of IGMP protocol */                                  \
237         proto_tree_add_uint(tree, hf_version, tvb, 0, 0, version);      \
238         /* type of command */                                           \
239         proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);       \
240         offset += 1;
241
242 static void igmp_checksum(proto_tree *tree,tvbuff_t *tvb, int len)
243 {
244         guint16 cksum,hdrcksum;
245         vec_t cksum_vec[1];
246
247         cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, len);
248         cksum_vec[0].len = len;
249
250         hdrcksum = tvb_get_ntohs(tvb, 2);
251         cksum = in_cksum(&cksum_vec[0],1);
252
253         if (cksum==0) {
254                 proto_tree_add_uint_format(tree, hf_checksum, tvb, 2, 2, hdrcksum, "Header checksum: 0x%04x (correct)", hdrcksum);
255         } else {
256                 proto_tree_add_item_hidden(tree, hf_checksum_bad, tvb, 2, 2, TRUE);
257                 proto_tree_add_uint_format(tree, hf_checksum, tvb, 2, 2, hdrcksum, "Header checksum: 0x%04x (incorrect, should be 0x%04x)", hdrcksum,in_cksum_shouldbe(hdrcksum,cksum));
258         }
259
260         return;
261 }
262
263
264 /* Unknown IGMP message type */
265 static int
266 dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
267 {
268         int len;
269
270         if (check_col(pinfo->fd, COL_INFO)) {
271                 col_add_str(pinfo->fd, COL_INFO,
272                         val_to_str(type, commands, "Unknown Type:0x%02x"));
273         }
274
275         /* type of command */
276         proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);
277         offset += 1;
278
279         /* Just call the rest of it "data" */
280         len = tvb_length_remaining(tvb, offset);
281         proto_tree_add_text(tree, tvb, offset, len, "Data");
282         offset += len;
283
284         return offset;
285 }
286
287
288
289 /*************************************************************
290  * IGMP Protocol dissectors
291  *************************************************************/
292 static int
293 dissect_v3_max_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
294 {
295         proto_tree *tree;
296         proto_item *item;
297         guint8 bits;
298         guint32 tsecs;
299
300         bits = tvb_get_guint8(tvb, offset);
301         if (bits&0x80) {
302                 tsecs = ((bits&IGMP_MAX_RESP_MANT)|0x10);
303                 tsecs = tsecs << ( ((bits&IGMP_MAX_RESP_EXP)>>4) + 3);
304         } else {
305                 tsecs = bits;
306         }               
307
308         item = proto_tree_add_uint_format(parent_tree, hf_max_resp, tvb,
309                         offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)",tsecs*0.1,bits);
310
311         if (bits&0x80) {
312                 tree = proto_item_add_subtree(item, ett_max_resp);
313
314                 proto_tree_add_uint(tree, hf_max_resp_exp, tvb, offset, 1,
315                         bits);
316                 proto_tree_add_uint(tree, hf_max_resp_mant, tvb, offset, 1,
317                         bits);
318         }
319
320         offset += 1;
321
322         return offset;
323 }
324
325 static int
326 dissect_v3_sqrv_bits(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
327 {
328         proto_tree *tree;
329         proto_item *item;
330         guint8 bits;
331
332         bits = tvb_get_guint8(tvb, offset);
333
334         item = proto_tree_add_text(parent_tree, tvb, offset, 1, 
335                 "QRV=%d S=%s", bits&IGMP_V3_QRV_MASK,
336                         (bits&IGMP_V3_S)?tfs_s.true_string:tfs_s.false_string);
337         tree = proto_item_add_subtree(item, ett_sqrv_bits);
338
339         /* S flag */
340         proto_tree_add_boolean(tree, hf_supress, tvb, offset, 1, bits);
341         /* QRV */
342         proto_tree_add_uint(tree, hf_qrv, tvb, offset, 1, bits);
343         offset += 1;
344
345         return offset;
346 }
347
348 static int
349 dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
350 {
351         proto_tree *tree;
352         proto_item *item;
353         int old_offset = offset;
354         guint8  adl;
355         guint16 num;
356         guint32 ip;
357
358         ip = tvb_get_letohl(tvb, offset+4);
359         item = proto_tree_add_text(parent_tree, tvb, offset, 0, 
360                 "Group Record : %s  %s", 
361                         ip_to_str((gchar*)&ip), 
362                         val_to_str(tvb_get_guint8(tvb, offset), vs_record_type,"")
363                 );
364         tree = proto_item_add_subtree(item, ett_group_record);
365
366         /* record type */
367         proto_tree_add_uint(tree, hf_record_type, tvb, offset, 1, tvb_get_guint8(tvb, offset));
368         offset += 1;
369
370         /* aux data len */
371         adl = tvb_get_guint8(tvb, offset);
372         proto_tree_add_uint(tree, hf_aux_data_len, tvb, offset, 1, adl);
373         offset += 1;
374
375         /*number of sources*/
376         num = tvb_get_ntohs(tvb, offset);
377         proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
378         offset += 2;
379
380         /* multicast address */
381         proto_tree_add_ipv4(tree, hf_maddr, tvb, 
382                 offset, 4, tvb_get_letohl(tvb, offset));
383         offset += 4;
384
385         /* source addresses */
386         while(num--){
387                 proto_tree_add_ipv4(tree, hf_saddr, tvb, 
388                         offset, 4, tvb_get_letohl(tvb, offset));
389                 offset += 4;
390         }
391
392         /* aux data */
393         if(adl){
394                 proto_tree_add_bytes(tree, hf_aux_data, tvb, offset, adl*4, tvb_get_ptr(tvb, offset, adl*4));
395                 offset += adl*4;
396         }
397
398         proto_item_set_len(item, offset-old_offset);
399         return offset;
400 }
401
402 /* dissectors for version 3, rfc???? */
403 static int
404 dissect_igmp_v3_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
405 {
406         guint16 num;
407
408         PRINT_IGMP_VERSION(3);
409
410         /* skip reserved field*/
411         offset += 1;
412
413         /* checksum */
414         igmp_checksum(tree, tvb, pinfo->iplen-pinfo->iphdrlen*4);
415         offset +=2;
416
417         /* skip reserved field */
418         offset += 2;
419
420         /* number of group records */
421         num = tvb_get_ntohs(tvb, offset);
422         proto_tree_add_uint(tree, hf_num_grp_recs, tvb, offset, 2, num);
423         offset += 2;
424         
425         while (num--) {
426                 offset = dissect_v3_group_record(tvb,pinfo,tree,offset);
427         }
428
429         return offset;
430 }
431
432 static int
433 dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
434 {
435         guint16 num;
436
437         PRINT_IGMP_VERSION(3);
438
439         num = tvb_get_ntohs(tvb, offset+9);
440         /* max resp code */
441         offset = dissect_v3_max_resp(tvb, pinfo, tree, offset);
442
443         /* checksum */
444         igmp_checksum(tree, tvb, pinfo->iplen-pinfo->iphdrlen*4);
445         offset += 2;
446
447         /* group address */
448         proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
449         offset +=4;
450
451         /* bitmask for S and QRV */
452         offset = dissect_v3_sqrv_bits(tvb, pinfo, tree, offset);
453
454         /* qqic */
455         proto_tree_add_uint(tree, hf_qqic, tvb, offset, 1, tvb_get_guint8(tvb, offset));
456         offset += 1;
457
458         /*number of sources*/
459         proto_tree_add_uint(tree, hf_num_src, tvb, offset, 2, num);
460         offset += 2;
461
462         while(num--){
463                 proto_tree_add_ipv4(tree, hf_saddr, tvb, 
464                         offset, 4, tvb_get_letohl(tvb, offset));
465                 offset += 4;
466         }
467
468         return offset;
469 }
470
471 /* dissector for version 2, rfc2236 */
472 static int
473 dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
474 {
475         guint8 tsecs;
476
477         PRINT_IGMP_VERSION(2);
478
479         /* max resp time */
480         tsecs = tvb_get_guint8(tvb, offset);
481         proto_tree_add_uint_format(tree, hf_max_resp, tvb,
482                 offset, 1, tsecs, "Max Response Time: %.1f sec (0x%02x)", tsecs*0.1,tsecs);
483         offset += 1;
484
485         /* checksum */
486         igmp_checksum(tree, tvb, 8);
487         offset += 2;
488
489         /* group address */
490         proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
491         offset +=4;
492
493         return offset;
494 }
495
496 /* dissector for version 1, rfc1054 */
497 static int
498 dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
499 {
500         PRINT_IGMP_VERSION(1);
501
502         /* skip unused byte */
503         offset += 1;
504
505         /* checksum */
506         igmp_checksum(tree, tvb, 8);
507         offset += 2;
508
509         /* group address */
510         proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
511         offset +=4;
512
513         return offset;
514 }
515
516 /* dissector for version 0, rfc988 */
517 static int
518 dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
519 {
520         unsigned char code;
521
522         PRINT_IGMP_VERSION(0);
523
524         /* Code */
525         code = tvb_get_guint8(tvb, offset);
526         if (type==IGMP_V0_CREATE_GROUP_REQUEST) {
527                 proto_tree_add_uint(tree, hf_group_type, tvb, offset, 1, code);
528         } else if (!(type&0x01)) {
529                 if (code <5) {
530                         proto_tree_add_uint(tree, hf_reply_code, tvb, offset, 1, code);
531                 } else {
532                         proto_tree_add_uint(tree, hf_reply_pending, tvb, offset, 1, code);
533                 }
534         }
535         offset += 1;
536
537         /* checksum */
538         igmp_checksum(tree, tvb, 20);
539         offset += 2;
540
541         /* identifier */
542         proto_tree_add_uint(tree, hf_identifier, tvb, offset, 4, tvb_get_ntohl(tvb, offset));
543         offset += 4;
544
545         /* group address */
546         proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
547         offset +=4;
548
549         /* access key */
550         proto_tree_add_bytes(tree, hf_access_key, tvb, offset, 8, tvb_get_ptr(tvb, offset, 8));
551         offset +=8;
552
553         return offset;          
554
555
556 static void
557 dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
558 {
559         proto_tree *tree;
560         proto_item *item;
561         int offset = 0;
562         unsigned char type;
563         guint32 dst;
564
565         item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, 0, FALSE);
566         tree = proto_item_add_subtree(item, ett_igmp);
567
568
569         if (check_col(pinfo->fd, COL_PROTOCOL)) {
570                 col_set_str(pinfo->fd, COL_PROTOCOL, "IGMP");
571         }
572         if (check_col(pinfo->fd, COL_INFO)) {
573                 col_clear(pinfo->fd, COL_INFO);
574         }
575
576
577         type = tvb_get_guint8(tvb, offset);
578
579
580         /* version 0 */
581         if ((type&0xf0)==0){
582                 offset = dissect_igmp_v0(tvb, pinfo, tree, type, offset);
583         }
584
585
586         switch (type) {
587
588         case IGMP_V1_HOST_MEMBERSHIP_QUERY:     /* 0x11 v1/v2/v3 */
589                 if ( (pinfo->iplen-pinfo->iphdrlen*4)>=12 ) {
590                         /* version 3 */
591                         offset = dissect_igmp_v3_query(tvb, pinfo, tree, type, offset);
592                 } else {
593                         /* v1 and v2 differs in second byte of header */
594                         if (tvb_get_guint8(tvb, offset)) {
595                                 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
596                         } else {
597                                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
598                         }
599                 }
600                 break;
601
602         case IGMP_V1_HOST_MEMBERSHIP_REPORT:    /* 0x12  v1/v2 */
603                 /* v1 and v2 differs in second byte of header */
604                 if (tvb_get_guint8(tvb, offset)) {
605                         offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
606                 } else {
607                         offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
608                 }
609                 break;
610
611         case IGMP_DVMRP:
612                 offset = dissect_dvmrp(tvb, pinfo, parent_tree, offset);
613                 break;
614
615         case IGMP_V1_PIM_ROUTING_MESSAGE:
616                 offset = dissect_pimv1(tvb, pinfo, parent_tree, offset);
617                 break;
618
619         case IGMP_V2_MEMBERSHIP_REPORT:
620         case IGMP_V2_LEAVE_GROUP:
621                 offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
622                 break;
623
624         case IGMP_V1_TRACEROUTE_RESPONSE:
625                 /* XXX - V1 or V2? */
626                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
627                 /*
628                  * XXX - dissect the rest as traceroute response; see the
629                  * tcpdump IGMP dissector.
630                  */
631                 break;
632
633         case IGMP_V1_TRACEROUTE_MESSAGE:
634                 /* XXX - V1 or V2? */
635                 offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
636                 /*
637                  * XXX - dissect the rest as traceroute message; see the
638                  * tcpdump IGMP dissector.
639                  */
640                 break;
641
642         case IGMP_V3_MEMBERSHIP_REPORT:
643                 offset = dissect_igmp_v3_response(tvb, pinfo, tree, type, offset);
644                 break;
645
646         case IGMP_TYPE_0x23:
647                 dst = htonl(MC_ALL_IGMPV3_ROUTERS);
648                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
649                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
650                 }
651                 break;
652
653         case IGMP_TYPE_0x24:
654                 dst = htonl(MC_ALL_ROUTERS);
655                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
656                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
657                 }  
658                 dst = htonl(MC_ALL_IGMPV3_ROUTERS);
659                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
660                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
661                 }
662                 break;
663
664         case IGMP_TYPE_0x25:
665                 if ( (pinfo->iplen-pinfo->iphdrlen*4)>=8 ) {
666                         /* if len of igmp packet>=8 we assume it is MSNIP */
667                         offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
668                 } else {
669                         /* ok its not MSNIP, check if it might be MRDISC */
670                         dst = htonl(MC_ALL_ROUTERS);
671                         if (!memcmp(pinfo->dst.data, &dst, 4)) {
672                                 offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
673                         }
674                 }
675                 break;
676
677         case IGMP_TYPE_0x26:
678                 dst = htonl(MC_ALL_ROUTERS);
679                 if (!memcmp(pinfo->dst.data, &dst, 4)) {
680                         offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset);
681                 }
682                 break;
683
684         default:
685                 offset = dissect_igmp_unknown(tvb, pinfo, tree, type, offset);
686                 break;
687         }
688
689
690         proto_item_set_len(item, offset);
691 }
692
693 void
694 proto_register_igmp(void)
695 {
696         static hf_register_info hf[] = {
697                 { &hf_type,
698                         { "Type", "igmp.type", FT_UINT8, BASE_HEX,
699                           VALS(commands), 0, "IGMP Packet Type", HFILL }},
700
701                 { &hf_version,
702                         { "IGMP Version", "igmp.version", FT_UINT8, BASE_DEC,
703                           NULL, 0, "IGMP Version", HFILL }},
704
705                 { &hf_group_type,
706                         { "Type Of Group", "igmp.group_type", FT_UINT8, BASE_DEC,
707                           VALS(vs_group_type), 0, "IGMP V0 Type Of Group", HFILL }},
708
709                 { &hf_reply_code,
710                         { "Reply", "igmp.reply", FT_UINT8, BASE_DEC,
711                           VALS(vs_reply_code), 0, "IGMP V0 Reply", HFILL }},
712
713                 { &hf_reply_pending,
714                         { "Reply Pending", "igmp.reply.pending", FT_UINT8, BASE_DEC,
715                           NULL, 0, "IGMP V0 Reply Pending, Retry in this many seconds", HFILL }},
716
717                 { &hf_checksum,
718                         { "Checksum", "igmp.checksum", FT_UINT16, BASE_HEX,
719                           NULL, 0, "IGMP Checksum", HFILL }},
720
721                 { &hf_checksum_bad,
722                         { "Bad Checksum", "igmp.checksum_bad", FT_BOOLEAN, BASE_NONE,
723                           NULL, 0, "Bad IGMP Checksum", HFILL }},
724
725                 { &hf_identifier,
726                         { "Identifier", "igmp.identifier", FT_UINT32, BASE_DEC,
727                           NULL, 0, "IGMP V0 Identifier", HFILL }},
728
729                 { &hf_access_key,
730                         { "Access Key", "igmp.access_key", FT_BYTES, BASE_HEX,
731                           NULL, 0, "IGMP V0 Access Key", HFILL }},
732
733                 { &hf_max_resp,
734                         { "Max Resp Time", "igmp.max_resp", FT_UINT8, BASE_DEC,
735                           NULL, 0, "Max Response Time", HFILL }},
736
737                 { &hf_supress,
738                         { "S", "igmp.s", FT_BOOLEAN, 8,
739                           TFS(&tfs_s), IGMP_V3_S, "Supress Router Side Processing", HFILL }},
740
741                 { &hf_qrv,
742                         { "QRV", "igmp.qrv", FT_UINT8, BASE_DEC,
743                         NULL, IGMP_V3_QRV_MASK, "Querier's Robustness Value", HFILL }},
744
745                 { &hf_qqic,
746                         { "QQIC", "igmp.qqic", FT_UINT8, BASE_DEC,
747                           NULL, 0, "Querier's Query Interval Code", HFILL }},
748
749                 { &hf_num_src,
750                         { "Num Src", "igmp.num_src", FT_UINT16, BASE_DEC,
751                           NULL, 0, "Number Of Sources", HFILL }},
752
753                 { &hf_saddr,
754                         { "Source Address", "igmp.saddr", FT_IPv4, BASE_NONE,
755                           NULL, 0, "Source Address", HFILL }},
756
757                 { &hf_num_grp_recs,
758                         { "Num Group Records", "igmp.num_grp_recs", FT_UINT16, BASE_DEC,
759                           NULL, 0, "Number Of Group Records", HFILL }},
760
761                 { &hf_record_type,
762                         { "Record Type", "igmp.record_type", FT_UINT8, BASE_DEC,
763                         VALS(vs_record_type), 0, "Record Type", HFILL }},
764
765                 { &hf_aux_data_len,
766                         { "Aux Data Len", "igmp.aux_data_len", FT_UINT8, BASE_DEC,
767                         NULL, 0, "Aux Data Len, In units of 32bit words", HFILL }},
768
769                 { &hf_maddr,
770                         { "Multicast Address", "igmp.maddr", FT_IPv4, BASE_NONE,
771                           NULL, 0, "Multicast Address", HFILL }},
772
773                 { &hf_aux_data,
774                         { "Aux Data", "igmp.aux_data", FT_BYTES, BASE_HEX,
775                           NULL, 0, "IGMP V3 Auxiliary Data", HFILL }},
776
777                 { &hf_max_resp_exp,
778                         { "Exponent", "igmp.max_resp.exp", FT_UINT8, BASE_HEX,
779                         NULL, IGMP_MAX_RESP_EXP, "Maxmimum Response Time, Exponent", HFILL }},
780
781                 { &hf_max_resp_mant,
782                         { "Mantissa", "igmp.max_resp.mant", FT_UINT8, BASE_HEX,
783                         NULL, IGMP_MAX_RESP_MANT, "Maxmimum Response Time, Mantissa", HFILL }},
784
785         };
786         static gint *ett[] = {
787                 &ett_igmp,
788                 &ett_group_record,
789                 &ett_sqrv_bits,
790                 &ett_max_resp,
791         };
792
793         proto_igmp = proto_register_protocol("Internet Group Management Protocol",
794             "IGMP", "igmp");
795         proto_register_field_array(proto_igmp, hf, array_length(hf));
796         proto_register_subtree_array(ett, array_length(ett));
797 }
798
799 void
800 proto_reg_handoff_igmp(void)
801 {
802         dissector_add("ip.proto", IP_PROTO_IGMP, dissect_igmp, proto_igmp);
803 }