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