1 /* packet-m2tp.c
2 * Routines for M2TP User Adaptation Layer dissection
3 * M2TP - MTP2 Transparent Proxy - is a Radisys proprietary
4 * protocol based on the IETF SIGTRAN standard
5 *
6 * Copyright 2001, Heinz Prantner <heinz.prantner[AT]radisys.com>
7 *
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
11 *
12 * Copied from packet-m3ua.c
13 * Thanks to Michael Tuexen for his valuable improvements
14 *
15 * SPDX-License-Identifier: GPL-2.0-or-later
16 */
17
18 #include "config.h"
19
20 #include <epan/packet.h>
21
22 #include <wsutil/str_util.h>
23
24 #define M2TP_PAYLOAD_PROTOCOL_ID 99 /* s-link, not IANA-registered */
25
26 void proto_register_m2tp(void);
27 void proto_reg_handoff_m2tp(void);
28
29 #define SCTP_PORT_M2TP 9908 /* unassigned port number (not assigned by IANA) */
30
31 #define VERSION_LENGTH 1
32 #define RESERVED_LENGTH 1
33 #define MESSAGE_CLASS_LENGTH 1
34 #define MESSAGE_TYPE_LENGTH 1
35 #define MESSAGE_LENGTH_LENGTH 4
36 #define COMMON_HEADER_LENGTH (VERSION_LENGTH + RESERVED_LENGTH + MESSAGE_CLASS_LENGTH + \
37 MESSAGE_TYPE_LENGTH + MESSAGE_LENGTH_LENGTH)
38
39 #define VERSION_OFFSET 0
40 #define RESERVED_OFFSET (VERSION_OFFSET + VERSION_LENGTH)
41 #define MESSAGE_CLASS_OFFSET (RESERVED_OFFSET + RESERVED_LENGTH)
42 #define MESSAGE_TYPE_OFFSET (MESSAGE_CLASS_OFFSET + MESSAGE_CLASS_LENGTH)
43 #define MESSAGE_LENGTH_OFFSET (MESSAGE_TYPE_OFFSET + MESSAGE_TYPE_LENGTH)
44
45 #define PARAMETER_TAG_LENGTH 2
46 #define PARAMETER_LENGTH_LENGTH 2
47 #define PARAMETER_HEADER_LENGTH (PARAMETER_TAG_LENGTH + PARAMETER_LENGTH_LENGTH)
48
49 #define PARAMETER_TAG_OFFSET 0
50 #define PARAMETER_LENGTH_OFFSET (PARAMETER_TAG_OFFSET + PARAMETER_TAG_LENGTH)
51 #define PARAMETER_VALUE_OFFSET (PARAMETER_LENGTH_OFFSET + PARAMETER_LENGTH_LENGTH)
52 #define PARAMETER_HEADER_OFFSET PARAMETER_TAG_OFFSET
53
54 #define INTERFACE_IDENTIFIER_PARAMETER_TAG 1
55 #define MASTER_SLAVE_INDICATOR_PARAMETER_TAG 2
56 #define M2TP_USER_IDENTIFIER_PARAMETER_TAG 3
57 #define INFO_PARAMETER_TAG 4
58 #define DIAGNOSTIC_INFORMATION_PARAMETER_TAG 7
59 #define HEARTBEAT_DATA_PARAMETER_TAG 9
60 #define REASON_PARAMETER_TAG 10
61 #define ERROR_CODE_PARAMETER_TAG 12
62 #define PROTOCOL_DATA_PARAMETER_TAG 13
63
64
65 static const value_string m2tp_parameter_tag_values[] = {
66 { INTERFACE_IDENTIFIER_PARAMETER_TAG, "Interface Identifier" },
67 { MASTER_SLAVE_INDICATOR_PARAMETER_TAG, "Master Slave Indicator" },
68 { M2TP_USER_IDENTIFIER_PARAMETER_TAG, "M2tp User Identifier" },
69 { INFO_PARAMETER_TAG, "Info" },
70 { DIAGNOSTIC_INFORMATION_PARAMETER_TAG, "Diagnostic Information" },
71 { HEARTBEAT_DATA_PARAMETER_TAG, "Heartbeat Data" },
72 { REASON_PARAMETER_TAG, "Reason" },
73 { ERROR_CODE_PARAMETER_TAG, "Error Code" },
74 { PROTOCOL_DATA_PARAMETER_TAG, "Protocol Data" },
75 { 0, NULL } };
76
77 #define PROTOCOL_VERSION_RELEASE_1 1
78
79 static const value_string m2tp_protocol_version_values[] = {
80 { PROTOCOL_VERSION_RELEASE_1, "Release 1" },
81 { 0, NULL } };
82
83 #define MESSAGE_CLASS_MGMT_MESSAGE 0
84 #define MESSAGE_CLASS_SGSM_MESSAGE 3
85 #define MESSAGE_CLASS_MAUP_MESSAGE 6
86 #define MESSAGE_CLASS_DATA_MESSAGE 255
87
88 static const value_string m2tp_message_class_values[] = {
89 { MESSAGE_CLASS_MGMT_MESSAGE, "Management Messages" },
90 { MESSAGE_CLASS_SGSM_MESSAGE, "SG State Maintenance Messages" },
91 { MESSAGE_CLASS_MAUP_MESSAGE, "MTP2 User Adaptation Messages" },
92 { MESSAGE_CLASS_DATA_MESSAGE, "User Data Messages" },
93 { 0, NULL } };
94
95 /* management messages */
96 #define MESSAGE_TYPE_ERR 0
97
98 /* sg state maintenance messages */
99 #define MESSAGE_TYPE_UP 1
100 #define MESSAGE_TYPE_DOWN 2
101 #define MESSAGE_TYPE_BEAT 3
102 #define MESSAGE_TYPE_UP_ACK 4
103 #define MESSAGE_TYPE_DOWN_ACK 5
104 #define MESSAGE_TYPE_BEAT_ACK 6
105
106 /* mtp2 user message */
107 #define MESSAGE_TYPE_DATA 1
108
109
110 static const value_string m2tp_message_class_type_values[] = {
111 { MESSAGE_CLASS_MGMT_MESSAGE * 256 + MESSAGE_TYPE_ERR, "Error (ERR)" },
112 { MESSAGE_CLASS_DATA_MESSAGE * 256 + MESSAGE_TYPE_DATA, "Payload data (DATA)" },
113 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_UP, "ASP up (UP)" },
114 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_DOWN, "ASP down (DOWN)" },
115 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_BEAT, "Heartbeat (BEAT)" },
116 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_UP_ACK, "ASP up ack (UP ACK)" },
117 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_DOWN_ACK, "ASP down ack (DOWN ACK)" },
118 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_BEAT_ACK, "Heartbeat ack (BEAT ACK)" },
119 { 0, NULL } };
120
121 static const value_string m2tp_message_class_type_acro_values[] = {
122 { MESSAGE_CLASS_MGMT_MESSAGE * 256 + MESSAGE_TYPE_ERR, "ERR" },
123 { MESSAGE_CLASS_DATA_MESSAGE * 256 + MESSAGE_TYPE_DATA, "DATA" },
124 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_UP, "ASP_UP" },
125 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_DOWN, "ASP_DOWN" },
126 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_BEAT, "BEAT" },
127 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_UP_ACK, "ASP_UP_ACK" },
128 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_DOWN_ACK, "ASP_DOWN_ACK" },
129 { MESSAGE_CLASS_SGSM_MESSAGE * 256 + MESSAGE_TYPE_BEAT_ACK, "BEAT_ACK" },
130 { 0, NULL } };
131
132
133
134 #define HEARTBEAT_PERIOD_OFFSET PARAMETER_VALUE_OFFSET
135
136 #define INTERFACE_IDENTIFIER_LENGTH 4
137 #define INTERFACE_IDENTIFIER_OFFSET PARAMETER_VALUE_OFFSET
138
139 #define M2TP_USER_LENGTH 4
140 #define M2TP_USER_OFFSET PARAMETER_VALUE_OFFSET
141
142 #define PROTOCOL_DATA_OFFSET PARAMETER_VALUE_OFFSET
143
144 #define MASTER_SLAVE_LENGTH 4
145 #define MASTER_SLAVE_OFFSET PARAMETER_VALUE_OFFSET
146
147 #define REASON_LENGTH 4
148 #define REASON_OFFSET PARAMETER_VALUE_OFFSET
149
150 #define HEART_BEAT_DATA_OFFSET PARAMETER_VALUE_OFFSET
151
152 #define ERROR_CODE_LENGTH 4
153 #define ERROR_CODE_OFFSET PARAMETER_VALUE_OFFSET
154
155 #define INFO_STRING_OFFSET PARAMETER_VALUE_OFFSET
156
157 #define BSN_OFFSET PARAMETER_VALUE_OFFSET
158 #define FSN_OFFSET PARAMETER_VALUE_OFFSET+1
159
160 #define M2TP_USER_MTP2 1
161 #define M2TP_USER_Q921 2
162 #define M2TP_USER_FRAME_RELAY 3
163
164 static const value_string m2tp_user_identifier_values[] = {
165 { M2TP_USER_MTP2, "MTP2" },
166 { M2TP_USER_Q921, "Q.921" },
167 { M2TP_USER_FRAME_RELAY, "Frame Relay" },
168 { 0, NULL }};
169
170 #define M2TP_MODE_MASTER 1
171 #define M2TP_MODE_SLAVE 2
172
173 static const value_string m2tp_mode_values[] = {
174 { M2TP_MODE_MASTER, "Master" },
175 { M2TP_MODE_SLAVE, "Slave" },
176 { 0, NULL}};
177
178 #define M2TP_ERROR_CODE_INVALID_VERSION 1
179 #define M2TP_ERROR_CODE_INVALID_INTERFACE_IDENTIFIER 2
180 #define M2TP_ERROR_CODE_INVALID_ADAPTATION_LAYER_IDENTIFIER 3
181 #define M2TP_ERROR_CODE_INVALID_MESSAGE_TYPE 4
182 #define M2TP_ERROR_CODE_INVALID_TRAFFIC_HANDLING_MODE 5
183 #define M2TP_ERROR_CODE_UNEXPECTED_MESSAGE 6
184 #define M2TP_ERROR_CODE_PROTOCOL_ERROR 7
185 #define M2TP_ERROR_CODE_INVALID_STREAM_IDENTIFIER 8
186 #define M2TP_ERROR_CODE_INCOMPATIBLE_MASTER_SLAVE_CONFIGURATION 9
187
188 static const value_string m2tp_error_code_values[] = {
189 { M2TP_ERROR_CODE_INVALID_VERSION, "Invalid Version" },
190 { M2TP_ERROR_CODE_INVALID_INTERFACE_IDENTIFIER, "Invalid Interface Identifier" },
191 { M2TP_ERROR_CODE_INVALID_ADAPTATION_LAYER_IDENTIFIER, "Invalid Adaptation Layer Identifier" },
192 { M2TP_ERROR_CODE_INVALID_MESSAGE_TYPE, "Invalid Message Type" },
193 { M2TP_ERROR_CODE_INVALID_TRAFFIC_HANDLING_MODE, "Invalid Traffic Handling Mode" },
194 { M2TP_ERROR_CODE_UNEXPECTED_MESSAGE, "Unexpected Message" },
195 { M2TP_ERROR_CODE_PROTOCOL_ERROR, "Protocol Error" },
196 { M2TP_ERROR_CODE_INVALID_STREAM_IDENTIFIER, "Invalid Stream Identified" },
197 { M2TP_ERROR_CODE_INCOMPATIBLE_MASTER_SLAVE_CONFIGURATION,"Incompatible Master Slave Configuration" },
198 { 0, NULL } };
199
200 #define MANAGEMENT_ORDER_REASON_CODE 1
201 #define MTP_RELEASE_REASON_CODE 2
202
203 static const value_string m2tp_reason_code_values[] = {
204 { MANAGEMENT_ORDER_REASON_CODE, "Management Order" },
205 { MTP_RELEASE_REASON_CODE, "MTP Release" },
206 { 0, NULL } };
207
208
209 /* Initialize the protocol and registered fields */
210 static int proto_m2tp = -1;
211 static int hf_m2tp_version = -1;
212 static int hf_m2tp_reserved = -1;
213 static int hf_m2tp_message_class = -1;
214 static int hf_m2tp_message_type = -1;
215 static int hf_m2tp_message_length = -1;
216 static int hf_m2tp_parameter_tag = -1;
217 static int hf_m2tp_parameter_length = -1;
218 static int hf_m2tp_parameter_value = -1;
219 static int hf_m2tp_parameter_padding = -1;
220 static int hf_m2tp_interface_identifier = -1;
221 static int hf_m2tp_user = -1;
222 static int hf_m2tp_master_slave = -1;
223 static int hf_m2tp_info_string = -1;
224 static int hf_m2tp_heartbeat_data = -1;
225 static int hf_m2tp_diagnostic_info = -1;
226 static int hf_m2tp_error_code = -1;
227 static int hf_m2tp_reason = -1;
228
229 /* Initialize the subtree pointers */
230 static gint ett_m2tp = -1;
231 static gint ett_m2tp_parameter = -1;
232
233 static dissector_handle_t mtp2_handle;
234
235 static guint
nr_of_padding_bytes(guint length)236 nr_of_padding_bytes (guint length)
237 {
238 guint remainder;
239
240 remainder = length % 4;
241
242 if (remainder == 0)
243 return 0;
244 else
245 return 4 - remainder;
246 }
247
248 /* Common Header */
249 static void
dissect_m2tp_common_header(tvbuff_t * common_header_tvb,packet_info * pinfo,proto_tree * m2tp_tree)250 dissect_m2tp_common_header(tvbuff_t *common_header_tvb, packet_info *pinfo, proto_tree *m2tp_tree)
251 {
252 guint8 version, reserved, message_class, message_type;
253 guint32 message_length;
254
255 /* Extract the common header */
256 version = tvb_get_guint8(common_header_tvb, VERSION_OFFSET);
257 reserved = tvb_get_guint8(common_header_tvb, RESERVED_OFFSET);
258 message_class = tvb_get_guint8(common_header_tvb, MESSAGE_CLASS_OFFSET);
259 message_type = tvb_get_guint8(common_header_tvb, MESSAGE_TYPE_OFFSET);
260 message_length = tvb_get_ntohl (common_header_tvb, MESSAGE_LENGTH_OFFSET);
261
262 col_add_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(message_class * 256 + message_type, m2tp_message_class_type_acro_values, "reserved"));
263
264 if (m2tp_tree) {
265 /* add the components of the common header to the protocol tree */
266 proto_tree_add_uint(m2tp_tree, hf_m2tp_version, common_header_tvb, VERSION_OFFSET, VERSION_LENGTH, version);
267 proto_tree_add_uint(m2tp_tree, hf_m2tp_reserved, common_header_tvb, RESERVED_OFFSET, RESERVED_LENGTH, reserved);
268 proto_tree_add_uint(m2tp_tree, hf_m2tp_message_class, common_header_tvb, MESSAGE_CLASS_OFFSET, MESSAGE_CLASS_LENGTH, message_class);
269 proto_tree_add_uint_format_value(m2tp_tree, hf_m2tp_message_type,
270 common_header_tvb, MESSAGE_TYPE_OFFSET, MESSAGE_TYPE_LENGTH,
271 message_type, "%u (%s)",
272 message_type, val_to_str_const(message_class * 256 + message_type, m2tp_message_class_type_values, "reserved"));
273 proto_tree_add_uint(m2tp_tree, hf_m2tp_message_length, common_header_tvb, MESSAGE_LENGTH_OFFSET, MESSAGE_LENGTH_LENGTH, message_length);
274 };
275 }
276
277 /* Interface Identifier */
278 static void
dissect_m2tp_interface_identifier_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)279 dissect_m2tp_interface_identifier_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
280 {
281 guint32 parameter_value;
282
283 if (parameter_tree) {
284 parameter_value = tvb_get_ntohl(parameter_tvb, PARAMETER_VALUE_OFFSET);
285 proto_tree_add_uint(parameter_tree, hf_m2tp_interface_identifier, parameter_tvb, INTERFACE_IDENTIFIER_OFFSET, INTERFACE_IDENTIFIER_LENGTH, parameter_value);
286 proto_item_set_text(parameter_item, "Interface Identifier (%u)", parameter_value);
287 }
288 }
289
290 /* Master Slave Indicator */
291 static void
dissect_m2tp_master_slave_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)292 dissect_m2tp_master_slave_parameter (tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
293 {
294 guint32 parameter_value;
295
296 if (parameter_tree) {
297 parameter_value = tvb_get_ntohl(parameter_tvb, PARAMETER_VALUE_OFFSET);
298 proto_tree_add_uint(parameter_tree, hf_m2tp_master_slave, parameter_tvb, MASTER_SLAVE_OFFSET, MASTER_SLAVE_LENGTH, parameter_value);
299 proto_item_set_text(parameter_item, "Master Slave Indicator (%s)", val_to_str_const(parameter_value, m2tp_mode_values, "unknown"));
300 }
301 }
302
303 /* M2tp User Identifier */
304 static void
dissect_m2tp_user_identifier_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)305 dissect_m2tp_user_identifier_parameter (tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
306 {
307 guint32 parameter_value;
308
309 if (parameter_tree) {
310 parameter_value = tvb_get_ntohl(parameter_tvb, PARAMETER_VALUE_OFFSET);
311 proto_tree_add_uint(parameter_tree, hf_m2tp_user, parameter_tvb, M2TP_USER_OFFSET, M2TP_USER_LENGTH, parameter_value);
312 proto_item_set_text(parameter_item, "M2TP User Identifier (%u)", parameter_value);
313 }
314 }
315
316 /* Info String */
317 static void
dissect_m2tp_info_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)318 dissect_m2tp_info_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
319 {
320 guint16 length, info_string_length;
321 const guint8 *info_string;
322
323 if (parameter_tree) {
324 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
325 info_string_length = length - PARAMETER_HEADER_LENGTH;
326 proto_tree_add_item_ret_string(parameter_tree, hf_m2tp_info_string, parameter_tvb, INFO_STRING_OFFSET, info_string_length, ENC_ASCII, wmem_packet_scope(), &info_string);
327 proto_item_set_text(parameter_item, "Info String (%.*s)", info_string_length, info_string);
328 }
329 }
330
331 /* Diagnostic Information */
332 static void
dissect_m2tp_diagnostic_information_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)333 dissect_m2tp_diagnostic_information_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
334 {
335 guint16 length, diagnostic_info_length;
336
337 if (parameter_tree) {
338 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
339 diagnostic_info_length = length - PARAMETER_HEADER_LENGTH;
340 proto_tree_add_item(parameter_tree, hf_m2tp_diagnostic_info, parameter_tvb, PARAMETER_VALUE_OFFSET, diagnostic_info_length, ENC_NA);
341 proto_item_set_text(parameter_item, "Diagnostic information (%u byte%s)", diagnostic_info_length, plurality(diagnostic_info_length, "", "s"));
342 }
343 }
344
345 /* Heartbeat Data */
346 static void
dissect_m2tp_heartbeat_data_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)347 dissect_m2tp_heartbeat_data_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
348 {
349 guint16 length, heartbeat_data_length;
350
351 if (parameter_tree) {
352 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
353 heartbeat_data_length = length - PARAMETER_HEADER_LENGTH;
354 proto_tree_add_item(parameter_tree, hf_m2tp_heartbeat_data, parameter_tvb, PARAMETER_VALUE_OFFSET, heartbeat_data_length, ENC_NA);
355 proto_item_set_text(parameter_item, "Heartbeat data (%u byte%s)", heartbeat_data_length, plurality(heartbeat_data_length, "", "s"));
356 }
357 }
358
359 /* Reason Parameter */
360 static void
dissect_m2tp_reason_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)361 dissect_m2tp_reason_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
362 {
363 guint32 reason;
364
365 if (parameter_tree) {
366 reason = tvb_get_ntohl(parameter_tvb, REASON_OFFSET);
367 proto_tree_add_uint(parameter_tree, hf_m2tp_reason, parameter_tvb, REASON_OFFSET, REASON_LENGTH, reason);
368 proto_item_set_text(parameter_item, "Reason parameter (%s)", val_to_str_const(reason, m2tp_reason_code_values, "unknown"));
369 }
370 }
371
372 /* Error Code */
373 static void
dissect_m2tp_error_code_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)374 dissect_m2tp_error_code_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
375 {
376 guint32 error_code;
377
378 if (parameter_tree) {
379 error_code = tvb_get_ntohl(parameter_tvb, ERROR_CODE_OFFSET);
380 proto_tree_add_uint(parameter_tree, hf_m2tp_error_code, parameter_tvb, ERROR_CODE_OFFSET, ERROR_CODE_LENGTH, error_code);
381 proto_item_set_text(parameter_item, "Error code parameter (%s)", val_to_str_const(error_code, m2tp_error_code_values, "unknown"));
382 }
383 }
384
385 /* Protocol Data */
386 static void
dissect_m2tp_protocol_data_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item,packet_info * pinfo,proto_item * m2tp_item,proto_tree * tree)387 dissect_m2tp_protocol_data_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, packet_info *pinfo, proto_item *m2tp_item, proto_tree *tree)
388 {
389 guint16 length, protocol_data_length, padding_length;
390 tvbuff_t *mtp2_tvb;
391
392 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
393 padding_length = nr_of_padding_bytes(length);
394 protocol_data_length = length - PARAMETER_HEADER_LENGTH;
395
396 mtp2_tvb = tvb_new_subset_length(parameter_tvb, PARAMETER_VALUE_OFFSET, protocol_data_length);
397 call_dissector(mtp2_handle, mtp2_tvb, pinfo, tree);
398
399 if (parameter_tree) {
400 proto_item_set_text(parameter_item, "Protocol data (SS7 message)");
401 proto_item_set_len(parameter_item, proto_item_get_len(parameter_item) - protocol_data_length - padding_length);
402 proto_item_set_len(m2tp_item, proto_item_get_len(m2tp_item) - protocol_data_length - padding_length);
403
404 }
405 }
406
407 /* Unknown Parameter */
408 static void
dissect_m2tp_unknown_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)409 dissect_m2tp_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
410 {
411 guint16 tag, length, parameter_value_length;
412
413 if (parameter_tree) {
414 tag = tvb_get_ntohs(parameter_tvb, PARAMETER_TAG_OFFSET);
415 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
416
417 parameter_value_length = length - PARAMETER_HEADER_LENGTH;
418 proto_tree_add_item(parameter_tree, hf_m2tp_parameter_value, parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length, ENC_NA);
419
420 proto_item_set_text(parameter_item, "Parameter with tag %u and %u byte%s value", tag, parameter_value_length, plurality(parameter_value_length, "", "s"));
421 }
422 }
423
424 /* M2TP Parameter */
425 static void
dissect_m2tp_parameter(tvbuff_t * parameter_tvb,packet_info * pinfo,proto_tree * m2tp_tree,proto_item * m2tp_item,proto_tree * tree)426 dissect_m2tp_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *m2tp_tree, proto_item *m2tp_item, proto_tree *tree)
427 {
428 guint16 tag, length, padding_length, total_length;
429 proto_item *parameter_item = NULL;
430 proto_tree *parameter_tree = NULL;
431
432 /* extract tag and length from the parameter */
433 tag = tvb_get_ntohs(parameter_tvb, PARAMETER_TAG_OFFSET);
434 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
435
436 /* calculate padding and total length */
437 padding_length = nr_of_padding_bytes(length);
438 total_length = length + padding_length;
439
440 if (tree) {
441 /* create proto_tree stuff */
442 parameter_tree = proto_tree_add_subtree(m2tp_tree, parameter_tvb, PARAMETER_HEADER_OFFSET, total_length,
443 ett_m2tp_parameter, ¶meter_item, "Incomplete parameter");
444
445 /* add tag and length to the m2tp tree */
446 proto_tree_add_uint(parameter_tree, hf_m2tp_parameter_tag, parameter_tvb, PARAMETER_TAG_OFFSET, PARAMETER_TAG_LENGTH, tag);
447 proto_tree_add_uint(parameter_tree, hf_m2tp_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, length);
448 }
449
450 switch(tag) {
451 case INTERFACE_IDENTIFIER_PARAMETER_TAG:
452 dissect_m2tp_interface_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
453 break;
454 case MASTER_SLAVE_INDICATOR_PARAMETER_TAG:
455 dissect_m2tp_master_slave_parameter(parameter_tvb, parameter_tree, parameter_item);
456 break;
457 case M2TP_USER_IDENTIFIER_PARAMETER_TAG:
458 dissect_m2tp_user_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
459 break;
460 case INFO_PARAMETER_TAG:
461 dissect_m2tp_info_parameter(parameter_tvb, parameter_tree, parameter_item);
462 break;
463 case DIAGNOSTIC_INFORMATION_PARAMETER_TAG:
464 dissect_m2tp_diagnostic_information_parameter(parameter_tvb, parameter_tree, parameter_item);
465 break;
466 case HEARTBEAT_DATA_PARAMETER_TAG:
467 dissect_m2tp_heartbeat_data_parameter(parameter_tvb, parameter_tree, parameter_item);
468 break;
469 case REASON_PARAMETER_TAG:
470 dissect_m2tp_reason_parameter(parameter_tvb, parameter_tree, parameter_item);
471 break;
472 case ERROR_CODE_PARAMETER_TAG:
473 dissect_m2tp_error_code_parameter(parameter_tvb, parameter_tree, parameter_item);
474 break;
475 case PROTOCOL_DATA_PARAMETER_TAG:
476 dissect_m2tp_protocol_data_parameter(parameter_tvb, parameter_tree, parameter_item, pinfo, m2tp_item, tree);
477 break;
478 default:
479 dissect_m2tp_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
480 break;
481 };
482
483 if ((parameter_tree) && (padding_length > 0))
484 proto_tree_add_item(parameter_tree, hf_m2tp_parameter_padding, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length, ENC_NA);
485 }
486
487 /* M2TP Message */
488 static void
dissect_m2tp_message(tvbuff_t * message_tvb,packet_info * pinfo,proto_item * m2tp_item,proto_tree * m2tp_tree,proto_tree * tree)489 dissect_m2tp_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_item *m2tp_item, proto_tree *m2tp_tree, proto_tree *tree)
490 {
491 gint offset, length, padding_length, total_length;
492 tvbuff_t *common_header_tvb, *parameter_tvb;
493
494 offset = 0;
495
496 /* extract and process the common header */
497 common_header_tvb = tvb_new_subset_length(message_tvb, offset, COMMON_HEADER_LENGTH);
498 dissect_m2tp_common_header(common_header_tvb, pinfo, m2tp_tree);
499 offset += COMMON_HEADER_LENGTH;
500
501 /* extract zero or more parameters and process them individually */
502 while(tvb_reported_length_remaining(message_tvb, offset) > 0) {
503 length = tvb_get_ntohs(message_tvb, offset + PARAMETER_LENGTH_OFFSET);
504 padding_length = nr_of_padding_bytes(length);
505 total_length = length + padding_length;
506 /* create a tvb for the parameter including the padding bytes */
507 parameter_tvb = tvb_new_subset_length(message_tvb, offset, total_length);
508 dissect_m2tp_parameter(parameter_tvb, pinfo, m2tp_tree, m2tp_item, tree);
509 /* get rid of the handled parameter */
510 offset += total_length;
511 }
512 }
513
514 /* M2tp */
515 static int
dissect_m2tp(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)516 dissect_m2tp(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
517 {
518 proto_item *m2tp_item;
519 proto_tree *m2tp_tree;
520
521 /* make entry in the Protocol column on summary display */
522 col_set_str(pinfo->cinfo, COL_PROTOCOL, "M2TP");
523
524 /* create the m2tp protocol tree */
525 m2tp_item = proto_tree_add_item(tree, proto_m2tp, message_tvb, 0, -1, ENC_NA);
526 m2tp_tree = proto_item_add_subtree(m2tp_item, ett_m2tp);
527
528 /* dissect the message */
529 dissect_m2tp_message(message_tvb, pinfo, m2tp_item, m2tp_tree, tree);
530 return tvb_captured_length(message_tvb);
531 }
532
533 /* Register the protocol with Wireshark */
534 void
proto_register_m2tp(void)535 proto_register_m2tp(void)
536 {
537
538 /* Setup list of header fields */
539 static hf_register_info hf[] = {
540 { &hf_m2tp_version,
541 { "Version", "m2tp.version",
542 FT_UINT8, BASE_DEC, VALS(m2tp_protocol_version_values), 0x0,
543 NULL, HFILL}
544 },
545 { &hf_m2tp_reserved,
546 { "Reserved", "m2tp.reserved",
547 FT_UINT8, BASE_HEX, NULL, 0x0,
548 NULL, HFILL}
549 },
550 { &hf_m2tp_message_class,
551 { "Message class", "m2tp.message_class",
552 FT_UINT8, BASE_DEC, VALS(m2tp_message_class_values), 0x0,
553 NULL, HFILL}
554 },
555 { &hf_m2tp_message_type,
556 { "Message Type", "m2tp.message_type",
557 FT_UINT8, BASE_DEC, NULL, 0x0,
558 NULL, HFILL}
559 },
560 { &hf_m2tp_message_length,
561 { "Message length", "m2tp.message_length",
562 FT_UINT32, BASE_DEC, NULL, 0x0,
563 NULL, HFILL}
564 },
565 { &hf_m2tp_parameter_tag,
566 { "Parameter Tag", "m2tp.parameter_tag",
567 FT_UINT16, BASE_DEC, VALS(m2tp_parameter_tag_values), 0x0,
568 NULL, HFILL}
569 },
570 { &hf_m2tp_parameter_length,
571 { "Parameter length", "m2tp.parameter_length",
572 FT_UINT16, BASE_DEC, NULL, 0x0,
573 NULL, HFILL}
574 },
575 { &hf_m2tp_parameter_value,
576 { "Parameter Value", "m2tp.parameter_value",
577 FT_BYTES, BASE_NONE, NULL, 0x0,
578 NULL, HFILL }
579 },
580 { &hf_m2tp_parameter_padding,
581 { "Padding", "m2tp.parameter_padding",
582 FT_BYTES, BASE_NONE, NULL, 0x0,
583 NULL, HFILL }
584 },
585 { &hf_m2tp_interface_identifier,
586 { "Interface Identifier", "m2tp.interface_identifier",
587 FT_UINT32, BASE_DEC, NULL, 0x0,
588 NULL, HFILL}
589 },
590 { &hf_m2tp_user,
591 { "M2tp User Identifier", "m2tp.user_identifier",
592 FT_UINT32, BASE_DEC, VALS(m2tp_user_identifier_values), 0x0,
593 NULL, HFILL}
594 },
595 { &hf_m2tp_master_slave,
596 { "Master Slave Indicator", "m2tp.master_slave",
597 FT_UINT32, BASE_DEC, VALS(m2tp_mode_values), 0x0,
598 NULL, HFILL}
599 },
600 { &hf_m2tp_info_string,
601 { "Info string", "m2tp.info_string",
602 FT_STRING, BASE_NONE, NULL, 0x0,
603 NULL, HFILL}
604 },
605 { &hf_m2tp_diagnostic_info,
606 { "Diagnostic information", "m2tp.diagnostic_info",
607 FT_BYTES, BASE_NONE, NULL, 0x0,
608 NULL, HFILL }
609 },
610 { &hf_m2tp_heartbeat_data,
611 { "Heartbeat data", "m2tp.heartbeat_data",
612 FT_BYTES, BASE_NONE, NULL, 0x0,
613 NULL, HFILL }
614 },
615 { &hf_m2tp_error_code,
616 { "Error code", "m2tp.error_code",
617 FT_UINT32, BASE_DEC, VALS(m2tp_error_code_values), 0x0,
618 NULL, HFILL}
619 },
620 { &hf_m2tp_reason,
621 { "Reason", "m2tp.reason",
622 FT_UINT32, BASE_DEC, NULL, 0x0,
623 NULL, HFILL}
624 },
625 };
626
627 /* Setup protocol subtree array */
628 static gint *ett[] = {
629 &ett_m2tp,
630 &ett_m2tp_parameter,
631 };
632
633 /* Register the protocol name and description */
634 proto_m2tp = proto_register_protocol("MTP 2 Transparent Proxy", "M2TP", "m2tp");
635
636 /* Required function calls to register the header fields and subtrees used */
637 proto_register_field_array(proto_m2tp, hf, array_length(hf));
638 proto_register_subtree_array(ett, array_length(ett));
639 }
640
641 void
proto_reg_handoff_m2tp(void)642 proto_reg_handoff_m2tp(void)
643 {
644 dissector_handle_t m2tp_handle;
645 mtp2_handle = find_dissector_add_dependency("mtp2", proto_m2tp);
646 m2tp_handle = create_dissector_handle(dissect_m2tp, proto_m2tp);
647 dissector_add_uint("sctp.ppi", M2TP_PAYLOAD_PROTOCOL_ID, m2tp_handle);
648 dissector_add_uint("sctp.port", SCTP_PORT_M2TP, m2tp_handle);
649 }
650
651 /*
652 * Editor modelines - https://www.wireshark.org/tools/modelines.html
653 *
654 * Local Variables:
655 * c-basic-offset: 2
656 * tab-width: 8
657 * indent-tabs-mode: nil
658 * End:
659 *
660 * ex: set shiftwidth=2 tabstop=8 expandtab:
661 * :indentSize=2:tabSize=8:noTabs=true:
662 */
663