2 * Routines for Automatic Multicast Tunneling (AMT) dissection
3 * Copyright 2017, Alexis La Goutte (See AUTHORS)
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * RFC 7450 : Automatic Multicast Tunneling
17 #include <epan/packet.h>
18 #include <epan/expert.h>
21 #define AMT_UDP_PORT 2268
23 void proto_reg_handoff_amt(void);
24 void proto_register_amt(void);
26 static dissector_handle_t amt_handle
;
29 static int hf_amt_version
;
30 static int hf_amt_type
;
31 static int hf_amt_reserved
;
32 static int hf_amt_discovery_nonce
;
33 static int hf_amt_relay_address_ipv4
;
34 static int hf_amt_relay_address_ipv6
;
35 static int hf_amt_request_nonce
;
36 static int hf_amt_request_reserved
;
37 static int hf_amt_request_p
;
38 static int hf_amt_membership_query_reserved
;
39 static int hf_amt_membership_query_l
;
40 static int hf_amt_membership_query_g
;
41 static int hf_amt_response_mac
;
42 static int hf_amt_gateway_port_number
;
43 static int hf_amt_gateway_ip_address
;
44 static int hf_amt_multicast_data
;
46 static expert_field ei_amt_relay_address_unknown
;
47 static expert_field ei_amt_unknown
;
51 #define RELAY_DISCOVERY 1
52 #define RELAY_ADVERTISEMENT 2
54 #define MEMBERSHIP_QUERY 4
55 #define MEMBERSHIP_UPDATE 5
56 #define MULTICAST_DATA 6
59 static const value_string amt_type_vals
[] = {
60 { RELAY_DISCOVERY
, "Relay Discovery" },
61 { RELAY_ADVERTISEMENT
, "Relay Advertisement" },
62 { REQUEST
, "Request" },
63 { MEMBERSHIP_QUERY
, "Membership Query" },
64 { MEMBERSHIP_UPDATE
, "Membership Update" },
65 { MULTICAST_DATA
, "Multicast Data" },
66 { TEARDOWN
, "Teardown" },
70 static const true_false_string tfs_request_p
= {
71 "IPv4 packet carrying an IGMPv3 General Query",
72 "IPv6 packet carrying an MLDv2 General Query"
75 static dissector_handle_t ip_handle
;
77 /* Code to actually dissect the packets */
79 dissect_amt(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
87 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "AMT");
89 ti
= proto_tree_add_item(tree
, proto_amt
, tvb
, 0, -1, ENC_NA
);
91 amt_tree
= proto_item_add_subtree(ti
, ett_amt
);
93 proto_tree_add_item(amt_tree
, hf_amt_version
, tvb
, offset
, 1, ENC_NA
);
94 proto_tree_add_item_ret_uint(amt_tree
, hf_amt_type
, tvb
, offset
, 1, ENC_NA
, &type
);
95 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(type
, amt_type_vals
, "Unknown AMT TYPE"));
99 case RELAY_DISCOVERY
: /* 1 */
100 proto_tree_add_item(amt_tree
, hf_amt_reserved
, tvb
, offset
, 3, ENC_NA
);
102 proto_tree_add_item(amt_tree
, hf_amt_discovery_nonce
, tvb
, offset
, 4, ENC_NA
);
105 case RELAY_ADVERTISEMENT
:{ /* 2 */
106 uint32_t relay_length
;
107 proto_tree_add_item(amt_tree
, hf_amt_reserved
, tvb
, offset
, 3, ENC_NA
);
109 proto_tree_add_item(amt_tree
, hf_amt_discovery_nonce
, tvb
, offset
, 4, ENC_NA
);
111 relay_length
= tvb_reported_length_remaining(tvb
, offset
);
112 switch(relay_length
){
113 case 4: /* IPv4 Address */
114 proto_tree_add_item(amt_tree
, hf_amt_relay_address_ipv4
, tvb
, offset
, 4, ENC_NA
);
117 case 16: /* IPv6 Address */
118 proto_tree_add_item(amt_tree
, hf_amt_relay_address_ipv6
, tvb
, offset
, 16, ENC_NA
);
121 default: /* Unknown type.. */
122 proto_tree_add_expert(amt_tree
, pinfo
, &ei_amt_relay_address_unknown
, tvb
, offset
, relay_length
);
123 offset
+= relay_length
;
128 case REQUEST
: /* 3 */
129 proto_tree_add_item(amt_tree
, hf_amt_request_reserved
, tvb
, offset
, 1, ENC_NA
);
130 proto_tree_add_item(amt_tree
, hf_amt_request_p
, tvb
, offset
, 1, ENC_NA
);
132 proto_tree_add_item(amt_tree
, hf_amt_reserved
, tvb
, offset
, 2, ENC_NA
);
134 proto_tree_add_item(amt_tree
, hf_amt_request_nonce
, tvb
, offset
, 4, ENC_NA
);
137 case MEMBERSHIP_QUERY
:{ /* 4 */
139 proto_tree_add_item(amt_tree
, hf_amt_membership_query_reserved
, tvb
, offset
, 1, ENC_NA
);
140 proto_tree_add_item(amt_tree
, hf_amt_membership_query_l
, tvb
, offset
, 1, ENC_NA
);
141 proto_tree_add_item_ret_uint(amt_tree
, hf_amt_membership_query_g
, tvb
, offset
, 1, ENC_NA
, &flags_g
);
143 proto_tree_add_item(amt_tree
, hf_amt_response_mac
, tvb
, offset
, 6, ENC_NA
);
145 proto_tree_add_item(amt_tree
, hf_amt_request_nonce
, tvb
, offset
, 4, ENC_NA
);
147 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
148 call_dissector(ip_handle
, next_tvb
, pinfo
, amt_tree
);
149 offset
+= tvb_reported_length_remaining(tvb
, offset
);
153 proto_tree_add_item(amt_tree
, hf_amt_gateway_port_number
, tvb
, offset
, 2, ENC_NA
);
155 proto_tree_add_item(amt_tree
, hf_amt_gateway_ip_address
, tvb
, offset
, 16, ENC_NA
);
160 case MEMBERSHIP_UPDATE
: /* 5 */
161 proto_tree_add_item(amt_tree
, hf_amt_reserved
, tvb
, offset
, 1, ENC_NA
);
163 proto_tree_add_item(amt_tree
, hf_amt_response_mac
, tvb
, offset
, 6, ENC_NA
);
165 proto_tree_add_item(amt_tree
, hf_amt_request_nonce
, tvb
, offset
, 4, ENC_NA
);
167 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
168 call_dissector(ip_handle
, next_tvb
, pinfo
, amt_tree
);
169 offset
+= tvb_reported_length_remaining(tvb
, offset
);
171 case MULTICAST_DATA
: /* 6 */
172 proto_tree_add_item(amt_tree
, hf_amt_reserved
, tvb
, offset
, 1, ENC_NA
);
174 proto_tree_add_item(amt_tree
, hf_amt_multicast_data
, tvb
, offset
, -1, ENC_NA
);
175 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
176 call_dissector(ip_handle
, next_tvb
, pinfo
, amt_tree
);
177 offset
+= tvb_reported_length_remaining(tvb
, offset
);
179 case TEARDOWN
:{ /* 7 */
180 proto_tree_add_item(amt_tree
, hf_amt_reserved
, tvb
, offset
, 1, ENC_NA
);
182 proto_tree_add_item(amt_tree
, hf_amt_response_mac
, tvb
, offset
, 6, ENC_NA
);
184 proto_tree_add_item(amt_tree
, hf_amt_request_nonce
, tvb
, offset
, 4, ENC_NA
);
186 proto_tree_add_item(amt_tree
, hf_amt_gateway_port_number
, tvb
, offset
, 2, ENC_NA
);
188 proto_tree_add_item(amt_tree
, hf_amt_gateway_ip_address
, tvb
, offset
, 16, ENC_NA
);
193 uint32_t len_unknown
;
194 len_unknown
= tvb_reported_length_remaining(tvb
, offset
);
195 proto_tree_add_expert(amt_tree
, pinfo
, &ei_amt_unknown
, tvb
, offset
, len_unknown
);
196 offset
+= len_unknown
;
204 proto_register_amt(void)
206 expert_module_t
*expert_amt
;
208 static hf_register_info hf
[] = {
210 { "Version", "amt.version",
211 FT_UINT8
, BASE_DEC
, NULL
, 0xF0,
212 "Must be always 0", HFILL
}
215 { "Type", "amt.type",
216 FT_UINT8
, BASE_DEC
, VALS(amt_type_vals
), 0x0F,
220 { "Reserved", "amt.reserved",
221 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
224 { &hf_amt_discovery_nonce
,
225 { "Discovery Nonce", "amt.discovery_nonce",
226 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
229 { &hf_amt_relay_address_ipv4
,
230 { "Relay Address (IPv4)", "amt.relay_address.ipv4",
231 FT_IPv4
, BASE_NONE
, NULL
, 0x0,
234 { &hf_amt_relay_address_ipv6
,
235 { "Relay Address (IPv6)", "amt.relay_address.ipv6",
236 FT_IPv6
, BASE_NONE
, NULL
, 0x0,
239 { &hf_amt_request_nonce
,
240 { "Request Nonce", "amt.request_nonce",
241 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
244 { &hf_amt_request_reserved
,
245 { "Reserved", "amt.request.reserved",
246 FT_UINT8
, BASE_HEX
, NULL
, 0xFE,
250 { "P Flags", "amt.request.p",
251 FT_BOOLEAN
, 8, TFS(&tfs_request_p
), 0x01,
254 { &hf_amt_membership_query_reserved
,
255 { "Reserved", "amt.membership_query.reserved",
256 FT_UINT8
, BASE_HEX
, NULL
, 0xFC,
259 { &hf_amt_membership_query_l
,
260 { "L Flags", "amt.membership_query.l",
261 FT_UINT8
, BASE_DEC
, NULL
, 0x02,
264 { &hf_amt_membership_query_g
,
265 { "G Flags", "amt.membership_query.g",
266 FT_UINT8
, BASE_DEC
, NULL
, 0x01,
269 { &hf_amt_response_mac
,
270 { "Response MAC", "amt.response_mac",
271 FT_UINT48
, BASE_HEX
, NULL
, 0x0,
274 { &hf_amt_gateway_port_number
,
275 { "Gateway Port Number", "amt.gateway.port_number",
276 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
279 { &hf_amt_gateway_ip_address
,
280 { "Gateway IP Address", "amt.gateway.ip_address",
281 FT_IPv6
, BASE_NONE
, NULL
, 0x0,
284 { &hf_amt_multicast_data
,
285 { "Multicast Data", "amt.multicast_data",
286 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
291 static int *ett
[] = {
296 static ei_register_info ei
[] = {
297 { &ei_amt_relay_address_unknown
,
298 { "amt.relay_address.unknown", PI_UNDECODED
, PI_NOTE
,
299 "Relay Address (Unknown Type)", EXPFILL
}
302 { "amt.unknown", PI_UNDECODED
, PI_NOTE
,
303 "Unknown Data", EXPFILL
}
308 proto_amt
= proto_register_protocol("Automatic Multicast Tunneling", "AMT", "amt");
310 proto_register_field_array(proto_amt
, hf
, array_length(hf
));
311 proto_register_subtree_array(ett
, array_length(ett
));
314 expert_amt
= expert_register_protocol(proto_amt
);
315 expert_register_field_array(expert_amt
, ei
, array_length(ei
));
317 amt_handle
= register_dissector("amt", dissect_amt
, proto_amt
);
321 proto_reg_handoff_amt(void)
323 ip_handle
= find_dissector_add_dependency("ip", proto_amt
);
325 dissector_add_uint_with_preference("udp.port", AMT_UDP_PORT
, amt_handle
);
329 * Editor modelines - https://www.wireshark.org/tools/modelines.html
334 * indent-tabs-mode: nil
337 * vi: set shiftwidth=4 tabstop=8 expandtab:
338 * :indentSize=4:tabSize=8:noTabs=true: