/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 | | |