From Jamie Fournier: AFS 4 UPDATE server support.
[obnox/wireshark/wip.git] / packet-m2pa.c
1 /* packet-m2pa.c
2  * Routines for MTP2 Peer Adaptation Layer dissection
3  * It is hopefully (needs testing) compliant to
4  * http://www.ietf.org/internet-drafts/draft-ietf-sigtran-m2pa-06.txt
5  *
6  * Copyright 2001, 2002, Jeff Morriss <jeff.morriss[AT]ulticom.com>,
7  * updated by Michael Tuexen <michael.tuexen[AT]siemens.com>
8  *
9  * $Id: packet-m2pa.c,v 1.14 2002/09/22 12:12:32 tuexen Exp $
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
15  * Copied from packet-m3ua.c
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
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <epan/packet.h>
38
39 #define NETWORK_BYTE_ORDER          FALSE
40 #define SCTP_PORT_M2PA              3565
41 #define M2PA_PAYLOAD_PROTOCOL_ID    5
42
43 static int proto_m2pa      = -1;
44 static int hf_version      = -1;
45 static int hf_spare        = -1;
46 static int hf_type         = -1;
47 static int hf_class        = -1;
48 static int hf_length       = -1;
49 static int hf_unused       = -1;
50 static int hf_bsn          = -1;
51 static int hf_fsn          = -1;
52 static int hf_status       = -1;
53 static int hf_li_spare     = -1;
54 static int hf_li_prio      = -1;
55 static int hf_filler       = -1;
56 static int hf_unknown_data = -1;
57
58 static gint ett_m2pa       = -1;
59 static gint ett_m2pa_li    = -1;
60
61 static int mtp3_proto_id;
62 static dissector_handle_t mtp3_handle;
63
64 #define VERSION_LENGTH         1
65 #define SPARE_LENGTH           1
66 #define CLASS_LENGTH           1
67 #define TYPE_LENGTH            1
68 #define LENGTH_LENGTH          4
69 #define UNUSED_LENGTH          1
70 #define BSN_LENGTH             3
71 #define FSN_LENGTH             3
72
73 #define HEADER_LENGTH          (VERSION_LENGTH + SPARE_LENGTH + \
74                                 CLASS_LENGTH + TYPE_LENGTH + LENGTH_LENGTH + \
75                                 UNUSED_LENGTH + BSN_LENGTH + UNUSED_LENGTH + FSN_LENGTH)
76
77 #define HEADER_OFFSET          0
78 #define VERSION_OFFSET         HEADER_OFFSET
79 #define SPARE_OFFSET           (VERSION_OFFSET + VERSION_LENGTH)
80 #define CLASS_OFFSET           (SPARE_OFFSET + SPARE_LENGTH)
81 #define TYPE_OFFSET            (CLASS_OFFSET + CLASS_LENGTH)
82 #define LENGTH_OFFSET          (TYPE_OFFSET + TYPE_LENGTH)
83 #define FIRST_UNUSED_OFFSET    (LENGTH_OFFSET + LENGTH_LENGTH)
84 #define BSN_OFFSET             (FIRST_UNUSED_OFFSET + UNUSED_LENGTH)
85 #define SECOND_UNUSED_OFFSET   (BSN_OFFSET + BSN_LENGTH)
86 #define FSN_OFFSET             (SECOND_UNUSED_OFFSET + UNUSED_LENGTH)
87
88 #define PROTOCOL_VERSION_RELEASE_1        1
89
90 static const value_string protocol_version_values[] = {
91   { PROTOCOL_VERSION_RELEASE_1,  "Release 1" },
92   { 0,                           NULL } };
93
94 #define MESSAGE_CLASS_M2PA                0xb
95
96 static const value_string message_class_values[] = {
97   { MESSAGE_CLASS_M2PA,          "M2PA" },
98   { 0,                           NULL } };
99
100 #define MESSAGE_TYPE_USER_DATA            0x1
101 #define MESSAGE_TYPE_LINK_STATUS          0x2
102
103 static const value_string message_type_values[] = {
104   { MESSAGE_TYPE_USER_DATA,     "User Data" },
105   { MESSAGE_TYPE_LINK_STATUS,   "Link Status" },
106   { 0,                           NULL } };
107
108 static void
109 dissect_m2pa_header(tvbuff_t *header_tvb, proto_tree *m2pa_tree)
110 {
111   if (m2pa_tree) {
112     proto_tree_add_item(m2pa_tree, hf_version, header_tvb, VERSION_OFFSET,       VERSION_LENGTH, NETWORK_BYTE_ORDER);
113     proto_tree_add_item(m2pa_tree, hf_spare,   header_tvb, SPARE_OFFSET,         SPARE_LENGTH,   NETWORK_BYTE_ORDER);
114     proto_tree_add_item(m2pa_tree, hf_class,   header_tvb, CLASS_OFFSET,         CLASS_LENGTH,   NETWORK_BYTE_ORDER);
115     proto_tree_add_item(m2pa_tree, hf_type,    header_tvb, TYPE_OFFSET,          TYPE_LENGTH,    NETWORK_BYTE_ORDER);
116     proto_tree_add_item(m2pa_tree, hf_length,  header_tvb, LENGTH_OFFSET,        LENGTH_LENGTH,  NETWORK_BYTE_ORDER);
117     proto_tree_add_item(m2pa_tree, hf_unused,  header_tvb, FIRST_UNUSED_OFFSET,  UNUSED_LENGTH,  NETWORK_BYTE_ORDER);
118     proto_tree_add_item(m2pa_tree, hf_bsn,     header_tvb, BSN_OFFSET,           BSN_LENGTH,     NETWORK_BYTE_ORDER);
119     proto_tree_add_item(m2pa_tree, hf_unused,  header_tvb, SECOND_UNUSED_OFFSET, UNUSED_LENGTH,  NETWORK_BYTE_ORDER);
120     proto_tree_add_item(m2pa_tree, hf_fsn,     header_tvb, FSN_OFFSET,           FSN_LENGTH,     NETWORK_BYTE_ORDER);
121   }
122 }
123
124 #define LI_OFFSET             0
125 #define LI_LENGTH             1
126 #define MTP3_OFFSET           (LI_OFFSET + LI_LENGTH)
127 #define LI_SPARE_MASK         0x3f
128 #define LI_PRIORITY_MASK      0xc0
129
130 static void
131 dissect_m2pa_user_data_message(tvbuff_t *message_data_tvb, packet_info *pinfo, proto_item *m2pa_item, proto_tree *m2pa_tree, proto_tree *tree)
132 {
133   proto_item *m2pa_li_item;
134   proto_tree *m2pa_li_tree;
135   tvbuff_t *payload_tvb;
136
137   if (tvb_length(message_data_tvb) > 0) {
138     if (m2pa_tree) {
139       m2pa_li_item = proto_tree_add_text(m2pa_tree, message_data_tvb, LI_OFFSET, LI_LENGTH, "Length Indicator");
140       m2pa_li_tree = proto_item_add_subtree(m2pa_li_item, ett_m2pa_li);
141       proto_tree_add_item(m2pa_li_tree, hf_li_prio,  message_data_tvb, LI_OFFSET, LI_LENGTH, NETWORK_BYTE_ORDER);
142       proto_tree_add_item(m2pa_li_tree, hf_li_spare, message_data_tvb, LI_OFFSET, LI_LENGTH, NETWORK_BYTE_ORDER);
143       /* Re-adjust length of M2PA item since it will be dissected as MTP3 */
144       proto_item_set_len(m2pa_item, HEADER_LENGTH + LI_LENGTH);
145     }
146
147     payload_tvb = tvb_new_subset(message_data_tvb, MTP3_OFFSET, -1, -1);
148         call_dissector(mtp3_handle, payload_tvb, pinfo, tree);
149     if ((!(proto_is_protocol_enabled (mtp3_proto_id))) && (check_col(pinfo->cinfo, COL_INFO)))
150         col_append_str(pinfo->cinfo, COL_INFO, "User Data ");
151   } else {
152     if (check_col(pinfo->cinfo, COL_INFO))
153         col_append_str(pinfo->cinfo, COL_INFO, "User Data ");
154   }
155 }
156
157 #define STATUS_LENGTH    4
158 #define STATUS_OFFSET    0
159 #define FILLER_OFFSET    (STATUS_OFFSET + STATUS_LENGTH)
160
161 #define STATUS_ALIGNMENT              1
162 #define STATUS_PROVING_NORMAL         2
163 #define STATUS_PROVING_EMERGENCY      3
164 #define STATUS_READY                  4
165 #define STATUS_PROCESSOR_OUTAGE       5
166 #define STATUS_PROCESSOR_OUTAGE_ENDED 6
167 #define STATUS_BUSY                   7
168 #define STATUS_BUSY_ENDED             8
169 #define STATUS_OUT_OF_SERVICE         9
170
171 static const value_string link_status_values[] = {
172   { STATUS_ALIGNMENT,                "Alignment" },
173   { STATUS_PROVING_NORMAL,           "Proving Normal" },
174   { STATUS_PROVING_EMERGENCY,        "Proving Emergency" },
175   { STATUS_READY,                    "Ready" },
176   { STATUS_PROCESSOR_OUTAGE,         "Processor Outage" },
177   { STATUS_PROCESSOR_OUTAGE_ENDED,   "Processor Outage Ended" },
178   { STATUS_BUSY,                     "Busy" },
179   { STATUS_BUSY_ENDED,               "Busy Ended" },
180   { STATUS_OUT_OF_SERVICE,           "Out of Service" },
181   { 0,                               NULL } };
182
183 static void
184 dissect_m2pa_link_status_message(tvbuff_t *message_data_tvb, packet_info *pinfo, proto_tree *m2pa_tree)
185 {
186   guint16 filler_length;
187
188   if (check_col(pinfo->cinfo, COL_INFO))
189     col_append_str(pinfo->cinfo, COL_INFO, "Link status ");
190   if (m2pa_tree) {
191     filler_length = tvb_length(message_data_tvb) - STATUS_LENGTH;
192     proto_tree_add_item(m2pa_tree, hf_status, message_data_tvb, STATUS_OFFSET, STATUS_LENGTH, NETWORK_BYTE_ORDER);
193     if (filler_length > 0)
194       proto_tree_add_item(m2pa_tree, hf_filler, message_data_tvb, FILLER_OFFSET, filler_length, NETWORK_BYTE_ORDER);
195   }
196 }
197
198 static void
199 dissect_m2pa_unknown_message(tvbuff_t *message_data_tvb, packet_info *pinfo, proto_tree *m2pa_tree)
200 {
201   if (check_col(pinfo->cinfo, COL_INFO))
202     col_append_str(pinfo->cinfo, COL_INFO, "Unknown ");
203   if (m2pa_tree)
204     proto_tree_add_item(m2pa_tree, hf_unknown_data, message_data_tvb, 0, tvb_length(message_data_tvb), NETWORK_BYTE_ORDER);
205 }
206
207 #define MESSAGE_DATA_OFFSET (HEADER_OFFSET + HEADER_LENGTH)
208
209 static void
210 dissect_m2pa_message_data(tvbuff_t *message_tvb, packet_info *pinfo, proto_item *m2pa_item, proto_tree *m2pa_tree, proto_tree *tree)
211 {
212   guint32 message_data_length;
213   guint8 type;
214   tvbuff_t *message_data_tvb;
215
216   message_data_length = tvb_get_ntohl(message_tvb,  LENGTH_OFFSET) - HEADER_LENGTH;
217   message_data_tvb    = tvb_new_subset(message_tvb, MESSAGE_DATA_OFFSET, message_data_length, message_data_length);
218   type                = tvb_get_guint8(message_tvb, TYPE_OFFSET);
219
220   switch(type) {
221   case MESSAGE_TYPE_USER_DATA:
222     dissect_m2pa_user_data_message(message_data_tvb, pinfo, m2pa_item, m2pa_tree, tree);
223     break;
224
225   case MESSAGE_TYPE_LINK_STATUS:
226     dissect_m2pa_link_status_message(message_data_tvb, pinfo, m2pa_tree);
227     break;
228
229   default:
230     dissect_m2pa_unknown_message(message_data_tvb, pinfo, m2pa_tree);
231   }
232
233 }
234 static void
235 dissect_m2pa_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_item *m2pa_item, proto_tree *m2pa_tree, proto_tree *tree)
236 {
237   tvbuff_t *header_tvb;
238
239   header_tvb = tvb_new_subset(message_tvb, HEADER_OFFSET, HEADER_LENGTH, HEADER_LENGTH);
240   dissect_m2pa_header(header_tvb, m2pa_tree);
241   dissect_m2pa_message_data(message_tvb, pinfo, m2pa_item, m2pa_tree, tree);
242 }
243
244 static void
245 dissect_m2pa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
246 {
247   proto_item *m2pa_item;
248   proto_tree *m2pa_tree;
249
250   if (check_col(pinfo->cinfo, COL_PROTOCOL))
251     col_set_str(pinfo->cinfo, COL_PROTOCOL, "M2PA");
252
253   if (tree) {
254     m2pa_item = proto_tree_add_item(tree, proto_m2pa, tvb, 0, -1, FALSE);
255     m2pa_tree = proto_item_add_subtree(m2pa_item, ett_m2pa);
256   } else {
257     m2pa_item = NULL;
258     m2pa_tree = NULL;
259   };
260
261   dissect_m2pa_message(tvb, pinfo, m2pa_item, m2pa_tree, tree);
262 }
263
264 void
265 proto_register_m2pa(void)
266 {
267   static hf_register_info hf[] = {
268     { &hf_version,      { "Version",        "m2pa.version",      FT_UINT8,  BASE_DEC,  VALS(protocol_version_values), 0x0,              "", HFILL} },
269     { &hf_spare,        { "Spare",          "m2pa.spare",        FT_UINT8,  BASE_HEX,  NULL,                          0x0,              "", HFILL} },
270     { &hf_type,         { "Message Type",   "m2pa.type",         FT_UINT8,  BASE_DEC,  VALS(message_type_values),     0x0,              "", HFILL} },
271     { &hf_class,        { "Message Class",  "m2pa.class",        FT_UINT8,  BASE_DEC,  VALS(message_class_values),    0x0,              "", HFILL} },
272     { &hf_length,       { "Message length", "m2pa.length",       FT_UINT32, BASE_DEC,  NULL,                          0x0,              "", HFILL} },
273     { &hf_unused,       { "Unused",         "m2pa.unused",       FT_UINT8,  BASE_DEC,  NULL,                          0x0,              "", HFILL} },
274     { &hf_bsn,          { "BSN",            "m2pa.bsn",          FT_UINT24, BASE_DEC,  NULL,                          0x0,              "", HFILL} },
275     { &hf_fsn,          { "FSN",            "m2pa.fsn",          FT_UINT24, BASE_DEC,  NULL,                          0x0,              "", HFILL} },
276     { &hf_li_spare,     { "Spare",          "m2pa.li_spare",     FT_UINT8,  BASE_HEX,  NULL,                          LI_SPARE_MASK,    "", HFILL} },
277     { &hf_li_prio,      { "Priority",       "m2pa.li_priority",  FT_UINT8,  BASE_HEX,  NULL,                          LI_PRIORITY_MASK, "", HFILL} },
278     { &hf_status,       { "Link Status",    "m2pa.status",       FT_UINT32, BASE_DEC,  VALS(link_status_values),      0x0,              "", HFILL} },
279     { &hf_filler,       { "Filler",         "m2pa.filler",       FT_BYTES,  BASE_NONE, NULL,                          0x0,              "", HFILL } },
280     { &hf_unknown_data, { "Unknown Data",   "m2pa.unknown_data", FT_BYTES,  BASE_NONE, NULL,                          0x0,              "", HFILL } }
281   };
282
283   static gint *ett[] = {
284     &ett_m2pa,
285     &ett_m2pa_li
286   };
287
288   proto_m2pa = proto_register_protocol("MTP2 Peer Adaptation Layer", "M2PA", "m2pa");
289
290   proto_register_field_array(proto_m2pa, hf, array_length(hf));
291   proto_register_subtree_array(ett, array_length(ett));
292 }
293
294 void
295 proto_reg_handoff_m2pa(void)
296 {
297   dissector_handle_t m2pa_handle;
298
299   mtp3_handle   = find_dissector("mtp3");
300   mtp3_proto_id = proto_get_id_by_filter_name("mtp3");
301   m2pa_handle   = create_dissector_handle(dissect_m2pa, proto_m2pa);
302   dissector_add("sctp.ppi",  M2PA_PAYLOAD_PROTOCOL_ID, m2pa_handle);
303   dissector_add("sctp.port", SCTP_PORT_M2PA,           m2pa_handle);
304 }