Do the standard "next entry offset" stuff in NT NOTIFY replies, so as to
[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.3 2002/01/24 09:20:49 guy 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
40 #define SCTP_PORT_M2TP        9908  /* unassigned port number (not assigned by IANA) */
41 #define M2TP_PAYLOAD_PROTO_ID 99    /* s-link */
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)) && (message_class != MESSAGE_CLASS_DATA_MESSAGE)){
276     col_append_str(pinfo->cinfo, COL_INFO,
277         val_to_str(message_class * 256 + message_type, m2tp_message_class_type_acro_values, "reserved"));
278     col_append_str(pinfo->cinfo, COL_INFO, " ");
279   };
280
281   if (m2tp_tree) {
282     /* add the components of the common header to the protocol tree */
283     proto_tree_add_uint(m2tp_tree, hf_m2tp_version, common_header_tvb, VERSION_OFFSET, VERSION_LENGTH, version);
284     proto_tree_add_uint(m2tp_tree, hf_m2tp_reserved, common_header_tvb, RESERVED_OFFSET, RESERVED_LENGTH, reserved);
285     proto_tree_add_uint(m2tp_tree, hf_m2tp_message_class, common_header_tvb, MESSAGE_CLASS_OFFSET, MESSAGE_CLASS_LENGTH, message_class);
286     proto_tree_add_uint_format(m2tp_tree, hf_m2tp_message_type, 
287                                common_header_tvb, MESSAGE_TYPE_OFFSET, MESSAGE_TYPE_LENGTH,
288                                message_type, "Message type: %u (%s)",
289                                message_type, val_to_str(message_class * 256 + message_type, m2tp_message_class_type_values, "reserved"));
290     proto_tree_add_uint(m2tp_tree, hf_m2tp_message_length, common_header_tvb, MESSAGE_LENGTH_OFFSET, MESSAGE_LENGTH_LENGTH, message_length);
291   };
292 }
293
294 /* Interface Identifier */
295 static void
296 dissect_m2tp_interface_identifier_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
297 {
298   guint32 parameter_value;
299
300   if (parameter_tree) {
301     parameter_value = tvb_get_ntohl(parameter_tvb, PARAMETER_VALUE_OFFSET);
302     proto_tree_add_uint(parameter_tree, hf_m2tp_interface_identifier, parameter_tvb, INTERFACE_IDENTIFIER_OFFSET, INTERFACE_IDENTIFIER_LENGTH, parameter_value);
303     proto_item_set_text(parameter_item, "Interface Identifier (%u)", parameter_value);
304   }
305 }
306
307 /* Master Slave Indicator */
308 static void
309 dissect_m2tp_master_slave_parameter (tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
310 {
311   guint32 parameter_value;
312
313   if (parameter_tree) {
314     parameter_value = tvb_get_ntohl(parameter_tvb, PARAMETER_VALUE_OFFSET);
315     proto_tree_add_uint(parameter_tree, hf_m2tp_master_slave, parameter_tvb, MASTER_SLAVE_OFFSET, MASTER_SLAVE_LENGTH, parameter_value);
316     proto_item_set_text(parameter_item, "Master Slave Indicator (%s)", val_to_str(parameter_value, m2tp_mode_values, "unknown"));
317   }
318 }
319
320 /* M2tp User Identifier */
321 static void
322 dissect_m2tp_user_identifier_parameter (tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
323 {
324   guint32 parameter_value;
325
326   if (parameter_tree) {
327     parameter_value = tvb_get_ntohl(parameter_tvb, PARAMETER_VALUE_OFFSET);
328     proto_tree_add_uint(parameter_tree, hf_m2tp_user, parameter_tvb, M2TP_USER_OFFSET, M2TP_USER_LENGTH, parameter_value);
329     proto_item_set_text(parameter_item, "M2TP User Identifier (%u)", parameter_value);
330   }
331 }
332
333 /* Info String */
334 static void
335 dissect_m2tp_info_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
336 {
337   guint16 length, info_string_length;
338   char *info_string;
339
340   if (parameter_tree) {
341     length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
342     info_string_length = length - PARAMETER_HEADER_LENGTH;
343     info_string = (char *)tvb_get_ptr(parameter_tvb, INFO_STRING_OFFSET, info_string_length);
344     proto_tree_add_string(parameter_tree, hf_m2tp_info_string, parameter_tvb, INFO_STRING_OFFSET, info_string_length, info_string);
345     proto_item_set_text(parameter_item, "Info String (%.*s)", info_string_length, info_string);
346   }
347 }
348
349 /* Diagnostic Information */
350 static void
351 dissect_m2tp_diagnostic_information_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
352 {
353   guint16 length, diagnostic_info_length;
354   
355   if (parameter_tree) {
356     length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);  
357     diagnostic_info_length = length - PARAMETER_HEADER_LENGTH;
358     proto_tree_add_bytes(parameter_tree, hf_m2tp_diagnostic_info, parameter_tvb, PARAMETER_VALUE_OFFSET, diagnostic_info_length,
359                          tvb_get_ptr(parameter_tvb, PARAMETER_VALUE_OFFSET, diagnostic_info_length));
360     proto_item_set_text(parameter_item, "Diagnostic information (%u byte%s)", diagnostic_info_length, plurality(diagnostic_info_length, "", "s"));
361   }
362 }
363
364 /* Heartbeat Data */
365 static void
366 dissect_m2tp_heartbeat_data_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
367 {
368   guint16 length, heartbeat_data_length;
369   
370   if (parameter_tree) {
371     length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
372     heartbeat_data_length = length - PARAMETER_HEADER_LENGTH;
373     proto_tree_add_bytes(parameter_tree, hf_m2tp_heartbeat_data, parameter_tvb, PARAMETER_VALUE_OFFSET, heartbeat_data_length,
374                          tvb_get_ptr(parameter_tvb, PARAMETER_VALUE_OFFSET, heartbeat_data_length));
375     proto_item_set_text(parameter_item, "Heartbeat data (%u byte%s)", heartbeat_data_length, plurality(heartbeat_data_length, "", "s"));
376   }
377 }
378
379 /* Reason Parameter */
380 static void
381 dissect_m2tp_reason_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
382 {
383   guint32 reason;
384
385   if (parameter_tree) {
386     reason = tvb_get_ntohl(parameter_tvb, REASON_OFFSET);
387     proto_tree_add_uint(parameter_tree, hf_m2tp_reason, parameter_tvb, REASON_OFFSET, REASON_LENGTH, reason);
388     proto_item_set_text(parameter_item, "Reason parameter (%s)", val_to_str(reason, m2tp_reason_code_values, "unknown"));
389   }
390 }
391
392 /* Error Code */
393 static void
394 dissect_m2tp_error_code_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
395 {
396   guint32 error_code;
397
398   if (parameter_tree) {
399     error_code = tvb_get_ntohl(parameter_tvb, ERROR_CODE_OFFSET);
400     proto_tree_add_uint(parameter_tree, hf_m2tp_error_code, parameter_tvb, ERROR_CODE_OFFSET, ERROR_CODE_LENGTH, error_code);
401     proto_item_set_text(parameter_item, "Error code parameter (%s)", val_to_str(error_code, m2tp_error_code_values, "unknown"));
402   }
403 }
404
405 /* Protocol Data */
406 static void
407 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)
408 {
409   guint16 length, protocol_data_length, padding_length;
410   tvbuff_t *mtp2_tvb;
411
412   length               = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
413   padding_length       = nr_of_padding_bytes(length);
414   protocol_data_length = length - PARAMETER_HEADER_LENGTH;
415
416   mtp2_tvb = tvb_new_subset(parameter_tvb, PARAMETER_VALUE_OFFSET, protocol_data_length, protocol_data_length);
417   call_dissector(mtp2_handle, mtp2_tvb, pinfo, tree);
418
419   if ((check_col(pinfo->cinfo, COL_INFO)) && (!proto_is_protocol_enabled(mtp2_proto_id)))
420     col_append_str(pinfo->cinfo, COL_INFO, "DATA");
421
422   if (parameter_tree) {
423     proto_item_set_text(parameter_item, "Protocol data (SS7 message)");
424     proto_item_set_len(parameter_item, proto_item_get_len(parameter_item) - protocol_data_length - padding_length);
425     proto_item_set_len(m2tp_item,      proto_item_get_len(m2tp_item)      - protocol_data_length - padding_length);
426
427   }
428 }
429
430 /* Unknown Parameter */
431 static void
432 dissect_m2tp_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
433 {
434   guint16 tag, length, parameter_value_length;
435   
436   if (parameter_tree) {
437     tag    = tvb_get_ntohs(parameter_tvb, PARAMETER_TAG_OFFSET);
438     length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
439     
440     parameter_value_length = length - PARAMETER_HEADER_LENGTH;
441     proto_tree_add_bytes(parameter_tree, hf_m2tp_parameter_value, 
442                         parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length,
443                         tvb_get_ptr(parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length));
444   
445     proto_item_set_text(parameter_item, "Parameter with tag %u and %u byte%s value", tag, parameter_value_length, plurality(parameter_value_length, "", "s"));
446   }
447 }
448
449 /* M2TP Parameter */
450 static void
451 dissect_m2tp_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *m2tp_tree, proto_item *m2tp_item, proto_tree *tree)
452 {
453   guint16 tag, length, padding_length, total_length;
454   proto_item *parameter_item = NULL;
455   proto_tree *parameter_tree = NULL;
456
457   /* extract tag and length from the parameter */
458   tag            = tvb_get_ntohs(parameter_tvb, PARAMETER_TAG_OFFSET);
459   length         = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
460
461   /* calculate padding and total length */
462   padding_length = nr_of_padding_bytes(length);
463   total_length   = length + padding_length;
464
465   if (tree) {
466     /* create proto_tree stuff */
467     parameter_item   = proto_tree_add_text(m2tp_tree, parameter_tvb, PARAMETER_HEADER_OFFSET, total_length, "Incomplete parameter");
468     parameter_tree   = proto_item_add_subtree(parameter_item, ett_m2tp_parameter);
469   
470     /* add tag and length to the m2tp tree */
471     proto_tree_add_uint(parameter_tree, hf_m2tp_parameter_tag, parameter_tvb, PARAMETER_TAG_OFFSET, PARAMETER_TAG_LENGTH, tag);
472     proto_tree_add_uint(parameter_tree, hf_m2tp_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, length);
473   }
474     
475   switch(tag) {
476     case INTERFACE_IDENTIFIER_PARAMETER_TAG:
477       dissect_m2tp_interface_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
478       break;
479     case MASTER_SLAVE_INDICATOR_PARAMETER_TAG:
480       dissect_m2tp_master_slave_parameter(parameter_tvb, parameter_tree, parameter_item);
481       break;
482     case M2TP_USER_IDENTIFIER_PARAMETER_TAG:
483       dissect_m2tp_user_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
484       break;
485     case INFO_PARAMETER_TAG:
486       dissect_m2tp_info_parameter(parameter_tvb, parameter_tree, parameter_item);
487       break;
488     case DIAGNOSTIC_INFORMATION_PARAMETER_TAG:
489       dissect_m2tp_diagnostic_information_parameter(parameter_tvb, parameter_tree, parameter_item);
490       break;
491     case HEARTBEAT_DATA_PARAMETER_TAG:
492       dissect_m2tp_heartbeat_data_parameter(parameter_tvb, parameter_tree, parameter_item);
493       break;
494     case REASON_PARAMETER_TAG:
495       dissect_m2tp_reason_parameter(parameter_tvb, parameter_tree, parameter_item);
496       break;
497     case ERROR_CODE_PARAMETER_TAG:
498       dissect_m2tp_error_code_parameter(parameter_tvb, parameter_tree, parameter_item);
499       break;
500     case PROTOCOL_DATA_PARAMETER_TAG:
501       dissect_m2tp_protocol_data_parameter(parameter_tvb, parameter_tree, parameter_item, pinfo, m2tp_item, tree);
502       break;
503     default:
504       dissect_m2tp_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
505       break;
506   };
507
508   if ((parameter_tree) && (padding_length > 0))
509     proto_tree_add_bytes(parameter_tree, hf_m2tp_parameter_padding, 
510                          parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length,
511                          tvb_get_ptr(parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length));
512 }
513
514 /* M2TP Message */
515 static void
516 dissect_m2tp_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_item *m2tp_item, proto_tree *m2tp_tree, proto_tree *tree)
517 {
518   gint offset, length, padding_length, total_length;
519   tvbuff_t *common_header_tvb, *parameter_tvb;
520
521   offset = 0;
522
523   /* extract and process the common header */
524   common_header_tvb = tvb_new_subset(message_tvb, offset, COMMON_HEADER_LENGTH, COMMON_HEADER_LENGTH);
525   dissect_m2tp_common_header(common_header_tvb, pinfo, m2tp_tree);
526   offset += COMMON_HEADER_LENGTH;
527   
528   /* extract zero or more parameters and process them individually */
529   while(tvb_reported_length_remaining(message_tvb, offset)) {
530     length         = tvb_get_ntohs(message_tvb, offset + PARAMETER_LENGTH_OFFSET);
531     padding_length = nr_of_padding_bytes(length);
532     total_length   = length + padding_length;
533     /* create a tvb for the parameter including the padding bytes */
534     parameter_tvb    = tvb_new_subset(message_tvb, offset, total_length, total_length);
535     dissect_m2tp_parameter(parameter_tvb, pinfo, m2tp_tree, m2tp_item, tree); 
536     /* get rid of the handled parameter */
537     offset += total_length;
538   }
539 }
540
541 /* M2tp */
542 static void
543 dissect_m2tp(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree)
544 {
545   proto_item *m2tp_item;
546   proto_tree *m2tp_tree;
547
548   /* make entry in the Protocol column on summary display */
549   if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
550     col_set_str(pinfo->cinfo, COL_PROTOCOL, "M2TP");
551   
552   /* In the interest of speed, if "tree" is NULL, don't do any work not
553      necessary to generate protocol tree items. */
554   if (tree) {
555     /* create the m2tp protocol tree */
556     m2tp_item = proto_tree_add_item(tree, proto_m2tp, message_tvb, 0, -1, FALSE);
557     m2tp_tree = proto_item_add_subtree(m2tp_item, ett_m2tp);
558   } else {
559     m2tp_item = NULL;
560     m2tp_tree = NULL;
561   };
562   /* dissect the message */
563   dissect_m2tp_message(message_tvb, pinfo, m2tp_item, m2tp_tree, tree);
564 }
565
566 /* Register the protocol with Ethereal */
567 void
568 proto_register_m2tp(void)
569 {                 
570
571   /* Setup list of header fields */
572   static hf_register_info hf[] = {
573     { &hf_m2tp_version,
574       { "Version", "m2tp.version",
575         FT_UINT8, BASE_DEC, VALS(m2tp_protocol_version_values), 0x0,          
576         "", HFILL}
577     },
578     { &hf_m2tp_reserved,
579       { "Reserved", "m2tp.reserved",
580         FT_UINT8, BASE_HEX, NULL, 0x0,          
581         "", HFILL}
582     }, 
583     { &hf_m2tp_message_class,
584       { "Message class", "m2tp.message_class",
585         FT_UINT8, BASE_DEC, VALS(m2tp_message_class_values), 0x0,          
586         "", HFILL}
587     },
588     { &hf_m2tp_message_type,
589       { "Message Type", "m2tp.message_type",
590         FT_UINT8, BASE_DEC, NULL, 0x0,          
591         "", HFILL}
592     },
593     { &hf_m2tp_message_length,
594       { "Message length", "m2tp.message_length",
595         FT_UINT32, BASE_DEC, NULL, 0x0,          
596         "", HFILL}
597     }, 
598     { &hf_m2tp_parameter_tag,
599       { "Parameter Tag", "m2tp.parameter_tag",
600         FT_UINT16, BASE_DEC, VALS(m2tp_parameter_tag_values), 0x0,          
601         "", HFILL}
602     },
603     { &hf_m2tp_parameter_length,
604       { "Parameter length", "m2tp.parameter_length",
605         FT_UINT16, BASE_DEC, NULL, 0x0,          
606         "", HFILL}
607     }, 
608     { &hf_m2tp_parameter_value,
609       { "Parameter Value", "m2tp.parameter_value",
610               FT_BYTES, BASE_NONE, NULL, 0x0,          
611               "", HFILL }
612     },
613     { &hf_m2tp_parameter_padding,
614       { "Padding", "m2tp.parameter_padding",
615               FT_BYTES, BASE_NONE, NULL, 0x0,          
616               "", HFILL }
617     },   
618     { &hf_m2tp_interface_identifier,
619       { "Interface Identifier", "m2tp.interface_identifier",
620         FT_UINT32, BASE_DEC, NULL, 0x0,          
621         "", HFILL}
622     }, 
623     { &hf_m2tp_user,
624       { "M2tp User Identifier", "m2tp.user_identifier",
625         FT_UINT32, BASE_DEC, VALS(m2tp_user_identifier_values), 0x0,          
626         "", HFILL}
627     }, 
628     { &hf_m2tp_master_slave,
629       { "Master Slave Indicator", "m2tp.master_slave",
630         FT_UINT32, BASE_DEC, VALS(m2tp_mode_values), 0x0,          
631         "", HFILL}
632     }, 
633     { &hf_m2tp_info_string,
634       { "Info string", "m2tp.info_string",
635         FT_STRING, BASE_DEC, NULL, 0x0,          
636         "", HFILL}
637     }, 
638     { &hf_m2tp_diagnostic_info,
639       { "Diagnostic information", "m2tp.diagnostic_info",
640                FT_BYTES, BASE_NONE, NULL, 0x0,          
641                "", HFILL }
642     },
643     { &hf_m2tp_heartbeat_data,
644       { "Heartbeat data", "m2tp.heartbeat_data",
645                FT_BYTES, BASE_NONE, NULL, 0x0,          
646                "", HFILL }
647     },
648     { &hf_m2tp_error_code,
649       { "Error code", "m2tp.error_code",
650         FT_UINT32, BASE_DEC, VALS(m2tp_error_code_values), 0x0,          
651         "", HFILL}
652     }, 
653     { &hf_m2tp_reason,
654       { "Reason", "m2tp.reason",
655         FT_UINT32, BASE_DEC, NULL, 0x0,          
656         "", HFILL}
657     }, 
658   };
659   
660   /* Setup protocol subtree array */
661   static gint *ett[] = {
662     &ett_m2tp,
663     &ett_m2tp_parameter,
664   };
665   
666   /* Register the protocol name and description */
667   proto_m2tp = proto_register_protocol("MTP 2 Transparent Proxy", "M2TP",  "m2tp");
668
669   /* Required function calls to register the header fields and subtrees used */
670   proto_register_field_array(proto_m2tp, hf, array_length(hf));
671   proto_register_subtree_array(ett, array_length(ett));
672 };
673
674 void
675 proto_reg_handoff_m2tp(void)
676 {
677   dissector_handle_t m2tp_handle;
678   mtp2_handle   = find_dissector("mtp2");
679   mtp2_proto_id = proto_get_id_by_filter_name("mtp2");
680   m2tp_handle   = create_dissector_handle(dissect_m2tp, proto_m2tp);
681   dissector_add("sctp.ppi",  M2TP_PAYLOAD_PROTO_ID, m2tp_handle);
682   dissector_add("sctp.port", SCTP_PORT_M2TP, m2tp_handle);
683 }