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