Coverage Report

Created: 2026-06-30 07:22

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