M2PA support, from Jeff Morriss.
[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-02.txt
5  *
6  * Copyright 2001, Jeff Morriss <jeff.morriss[AT]ulticom.com>
7  *
8  * $Id: packet-m2pa.c,v 1.1 2001/06/21 22:25:51 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  * 
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * 
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46
47 #include <string.h>
48 #include <glib.h>
49
50 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
52 #endif
53
54 #include "packet.h"
55 #include "prefs.h"
56
57 /* Warning:  Neither of these are standardized yet! */
58 #define SCTP_PORT_M2PA 2904
59 #define M2PA_PAYLOAD_PROTOCOL_ID   5
60
61 #define VERSION_LENGTH         1
62 #define SPARE_LENGTH           1
63 #define MESSAGE_TYPE_LENGTH    2
64 #define MESSAGE_LENGTH_LENGTH  4
65 #define COMMON_HEADER_LENGTH   (VERSION_LENGTH + SPARE_LENGTH + \
66                                 MESSAGE_TYPE_LENGTH + MESSAGE_LENGTH_LENGTH)
67
68 #define VERSION_OFFSET         0
69 #define SPARE_OFFSET           (VERSION_OFFSET + VERSION_LENGTH)
70 #define MESSAGE_TYPE_OFFSET    (SPARE_OFFSET + SPARE_LENGTH)
71 #define MESSAGE_LENGTH_OFFSET  (MESSAGE_TYPE_OFFSET + MESSAGE_TYPE_LENGTH)
72
73
74 #define PROTOCOL_VERSION_RELEASE_1        1
75 static const value_string m2pa_protocol_version_values[] = {
76   { PROTOCOL_VERSION_RELEASE_1,  "Release 1" },
77   { 0,                           NULL } };
78
79
80 #define MESSAGE_TYPE_USER_DATA            0x0601
81 #define MESSAGE_TYPE_LINK_STATUS          0x0602
82 static const value_string m2pa_message_type_values[] = {
83   { MESSAGE_TYPE_USER_DATA,     "User Data" },
84   { MESSAGE_TYPE_LINK_STATUS,   "Link Status" },
85   { 0,                           NULL } };
86
87
88 /* parts of User Data message */
89 #define LI_OFFSET             0
90 #define LI_LENGTH             1
91 #define USER_OFFSET           (LI_OFFSET + LI_LENGTH)
92
93 /* LI is only used for (ITU national) priority in M2PA */
94 #define LI_SPARE_MASK              0xfc
95 #define LI_PRIORITY_MASK           0x3
96
97
98 /* parts of Link Status message */
99 #define STATUS_LENGTH    4
100 #define STATUS_OFFSET    0
101
102 #define STATUS_IS        1
103 #define STATUS_PO        2
104 #define STATUS_POE       3
105 #define STATUS_BUSY      4
106 #define STATUS_BUSY_E    5
107 static const value_string m2pa_link_status_values[] = {
108   { STATUS_IS,      "In Service" },
109   { STATUS_PO,      "Processor Outage" },
110   { STATUS_POE,     "Processor Outage Ended" },
111   { STATUS_BUSY,    "Busy" },
112   { STATUS_BUSY_E,  "Busy Ended" },
113   { 0,              NULL } };
114
115
116 /* Initialize the protocol and registered fields */
117 static int proto_m2pa = -1;
118 static int hf_m2pa_version = -1;
119 static int hf_m2pa_spare = -1;
120 static int hf_m2pa_message_type = -1;
121 static int hf_m2pa_message_length = -1;
122 static int hf_m2pa_ls_status = -1;
123 static int hf_m2pa_data_li = -1;
124 static int hf_m2pa_data_li_spare = -1;
125 static int hf_m2pa_data_li_prio = -1;
126
127 /* Initialize the subtree pointers */
128 static gint ett_m2pa = -1;
129 static gint ett_m2pa_message_ud = -1;
130 static gint ett_m2pa_message_ud_li = -1;
131 static gint ett_m2pa_message_ls = -1;
132
133 static dissector_handle_t mtp3_handle;
134
135 static void
136 dissect_m2pa_unknown_message(tvbuff_t *message_tvb, packet_info *pinfo,
137                              proto_tree *m2pa_tree, guint32 message_length,
138                              guint16 message_type)
139 {
140
141   if (check_col(pinfo->fd, COL_INFO)) {
142     col_set_str(pinfo->fd, COL_INFO,
143                 val_to_str(message_type, m2pa_message_type_values, "Unknown"));
144   };
145
146   if (m2pa_tree) {
147     proto_tree_add_text(m2pa_tree, message_tvb, 0, message_length,
148                         "Unknown message (%u byte%s)",
149                         message_length, plurality(message_length, "", "s"));
150   };
151
152 }
153
154
155 static void
156 dissect_m2pa_link_status_message(tvbuff_t *message_tvb, packet_info *pinfo,
157                                  proto_tree *m2pa_tree, guint16 message_type)
158 {
159   guint32 status;
160   proto_item *m2pa_ls_item;
161   proto_tree *m2pa_ls_tree;
162
163   status = tvb_get_ntohl (message_tvb, STATUS_OFFSET);
164
165   if (check_col(pinfo->fd, COL_INFO)) {
166     col_set_str(pinfo->fd, COL_INFO,
167                 val_to_str(message_type, m2pa_message_type_values, "unknown"));
168
169     col_append_str(pinfo->fd, COL_INFO, " (");
170     col_append_str(pinfo->fd, COL_INFO,
171                    val_to_str(status, m2pa_link_status_values, "unknown"));
172     col_append_str(pinfo->fd, COL_INFO, ")");
173   };
174
175   if (m2pa_tree) {
176     /* create the link status message tree */
177     m2pa_ls_item = proto_tree_add_text(m2pa_tree, message_tvb, 0,
178                                        STATUS_LENGTH,
179                                        val_to_str(message_type,
180                                                   m2pa_message_type_values,
181                                                   "Unknown"));
182     m2pa_ls_tree = proto_item_add_subtree(m2pa_ls_item, ett_m2pa_message_ls);
183
184     /* add the components of the link status message to the protocol tree */
185     proto_tree_add_uint(m2pa_ls_tree, hf_m2pa_ls_status,
186                                           message_tvb, STATUS_OFFSET,
187                                           STATUS_LENGTH, status);
188   };
189
190 }
191
192
193 static void
194 dissect_m2pa_user_data_message(tvbuff_t *message_tvb, packet_info *pinfo,
195                                proto_item *m2pa_item, proto_tree *m2pa_tree,
196                                guint32 message_length, proto_tree *tree,
197                                guint16 message_type)
198 {
199   proto_item *m2pa_ud_item;
200   proto_tree *m2pa_ud_tree;
201   proto_item *m2pa_ud_li_item;
202   proto_tree *m2pa_ud_li_tree;
203   tvbuff_t *payload_tvb;
204   guint8 li;
205   guint32 payload_length;
206
207   li = tvb_get_guint8(message_tvb, LI_OFFSET);
208   payload_length = message_length - LI_LENGTH;
209
210   if (m2pa_tree) {
211     /* create the user data message tree */
212     m2pa_ud_item = proto_tree_add_item(m2pa_tree, proto_m2pa, message_tvb, 0,
213                                        tvb_length(message_tvb), FALSE);
214     m2pa_ud_tree = proto_item_add_subtree(m2pa_ud_item, ett_m2pa_message_ud);
215
216     /* add the components of the user data message to the protocol tree */
217     /* LI */
218     m2pa_ud_li_item = proto_tree_add_uint(m2pa_ud_tree, hf_m2pa_data_li,
219                                           message_tvb, LI_OFFSET, LI_LENGTH,
220                                           li);
221     m2pa_ud_li_tree = proto_item_add_subtree(m2pa_ud_li_item,
222                                              ett_m2pa_message_ud_li);
223     proto_tree_add_uint(m2pa_ud_li_tree, hf_m2pa_data_li_spare, message_tvb,
224                         LI_OFFSET, LI_LENGTH, li);
225     proto_tree_add_uint(m2pa_ud_li_tree, hf_m2pa_data_li_prio, message_tvb,
226                         LI_OFFSET, LI_LENGTH, li);
227
228     proto_item_set_text(m2pa_ud_item, "Protocol data (SS7 message of %u byte%s)",
229                         payload_length, plurality(payload_length, "", "s"));
230
231     /* Re-adjust length of M2PA item since it will be dissected as MTP3 */
232     proto_item_set_len(m2pa_item, COMMON_HEADER_LENGTH + LI_LENGTH);
233
234   };
235
236   payload_tvb = tvb_new_subset(message_tvb, USER_OFFSET, payload_length,
237                                payload_length);
238   call_dissector(mtp3_handle, payload_tvb, pinfo, tree);
239
240 }
241
242 static void
243 dissect_m2pa_message(tvbuff_t *tvb, packet_info *pinfo, proto_item *m2pa_item,
244                      proto_tree *m2pa_tree, proto_tree *tree)
245 {
246   guint8  version, spare;
247   guint16 message_type;
248   guint32 message_length;
249   tvbuff_t *message_tvb;
250
251   /* Extract the common header */
252   version        = tvb_get_guint8(tvb, VERSION_OFFSET);
253   spare          = tvb_get_guint8(tvb, SPARE_OFFSET);
254   message_type   = tvb_get_ntohs(tvb, MESSAGE_TYPE_OFFSET);
255   message_length = tvb_get_ntohl(tvb, MESSAGE_LENGTH_OFFSET);
256
257   if (m2pa_tree) {
258     /* add the components of the common header to the protocol tree */
259     proto_tree_add_uint(m2pa_tree, hf_m2pa_version, tvb, VERSION_OFFSET,
260                         VERSION_LENGTH, version);
261     proto_tree_add_uint(m2pa_tree, hf_m2pa_spare,
262                         tvb, SPARE_OFFSET, SPARE_LENGTH,
263                         spare);
264     proto_tree_add_uint(m2pa_tree, hf_m2pa_message_type, tvb,
265                         MESSAGE_TYPE_OFFSET, MESSAGE_TYPE_LENGTH,
266                         message_type);
267     proto_tree_add_uint(m2pa_tree, hf_m2pa_message_length,
268                         tvb, MESSAGE_LENGTH_OFFSET, MESSAGE_LENGTH_LENGTH,
269                         message_length);
270   };
271
272   /* create a tvb for the message */
273   message_tvb = tvb_new_subset(tvb, COMMON_HEADER_LENGTH, message_length,
274                                message_length);
275
276   switch(message_type) {
277   case MESSAGE_TYPE_USER_DATA:
278     dissect_m2pa_user_data_message(message_tvb, pinfo, m2pa_item, m2pa_tree,
279                                    message_length, tree, message_type);
280       break;
281
282   case MESSAGE_TYPE_LINK_STATUS:
283     dissect_m2pa_link_status_message(message_tvb, pinfo, m2pa_tree,
284                                      message_type);
285     break;
286
287   default:
288     dissect_m2pa_unknown_message(message_tvb, pinfo, m2pa_tree,
289                                  message_length, message_type);
290   }
291
292 }
293
294 static void
295 dissect_m2pa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
296 {
297   proto_item *m2pa_item;
298   proto_tree *m2pa_tree;
299
300   /* make entry in the Protocol column on summary display */
301   if (check_col(pinfo->fd, COL_PROTOCOL))
302     col_set_str(pinfo->fd, COL_PROTOCOL, "M2PA");
303
304   /* Clear entries in Info column on summary display */
305   if (check_col(pinfo->fd, COL_INFO))
306     col_clear(pinfo->fd, COL_INFO);
307
308   /* In the interest of speed, if "tree" is NULL, don't do any work not
309      necessary to generate protocol tree items. */
310   if (tree) {
311     /* create the m2pa protocol tree */
312     m2pa_item = proto_tree_add_item(tree, proto_m2pa, tvb, 0,
313                                     COMMON_HEADER_LENGTH, FALSE);
314     m2pa_tree = proto_item_add_subtree(m2pa_item, ett_m2pa);
315   } else {
316     m2pa_item = NULL;
317     m2pa_tree = NULL;
318   };
319
320   /* dissect the message */
321   dissect_m2pa_message(tvb, pinfo, m2pa_item, m2pa_tree, tree);
322 }
323
324 /* Register the protocol with Ethereal */
325 void
326 proto_register_m2pa(void)
327 {
328
329   /* Setup list of header fields */
330   static hf_register_info hf[] = {
331     { &hf_m2pa_version,
332       { "Version", "m2pa.version",
333         FT_UINT8, BASE_DEC, VALS(m2pa_protocol_version_values), 0x0,
334         "", HFILL}
335     },
336     { &hf_m2pa_spare,
337       { "Spare", "m2pa.spare",
338         FT_UINT8, BASE_HEX, NULL, 0x0,
339         "", HFILL}
340     },
341     { &hf_m2pa_message_type,
342       { "Message Type", "m2pa.message_type",
343         FT_UINT16, BASE_HEX, VALS(m2pa_message_type_values), 0x0,
344         "", HFILL}
345     },
346     { &hf_m2pa_message_length,
347       { "Message length", "m2pa.message_length",
348         FT_UINT32, BASE_DEC, NULL, 0x0,
349         "", HFILL}
350     },
351     { &hf_m2pa_ls_status,
352       { "Link Status Status", "m2pa.status",
353         FT_UINT32, BASE_DEC, VALS(m2pa_link_status_values), 0x0,
354         "", HFILL}
355     },
356     { &hf_m2pa_data_li,
357       { "Length Indicator", "m2pa.li",
358         FT_UINT8, BASE_HEX, NULL, 0x0,
359         "", HFILL}
360     },
361     { &hf_m2pa_data_li_spare,
362       { "Spare", "m2pa.li.spare",
363         FT_UINT8, BASE_HEX, NULL, LI_SPARE_MASK,
364         "", HFILL}
365     },
366     { &hf_m2pa_data_li_prio,
367       { "Priority", "m2pa.li.prio",
368         FT_UINT8, BASE_HEX, NULL, LI_PRIORITY_MASK,
369         "", HFILL}
370     }
371   };
372
373   /* Setup protocol subtree array */
374   static gint *ett[] = {
375     &ett_m2pa,
376     &ett_m2pa_message_ud,
377     &ett_m2pa_message_ud_li,
378     &ett_m2pa_message_ls
379   };
380
381   /* Register the protocol name and description */
382   proto_m2pa = proto_register_protocol("MTP2 Peer Adaptation Layer",
383                                       "M2PA", "m2pa");
384
385   /* Required function calls to register the header fields and subtrees used */
386   proto_register_field_array(proto_m2pa, hf, array_length(hf));
387   proto_register_subtree_array(ett, array_length(ett));
388
389 };
390
391 void
392 proto_reg_handoff_m2pa(void)
393 {
394   /*
395    *  Get a handle for the MTP3 dissector.
396    */
397   mtp3_handle = find_dissector("mtp3");
398
399   dissector_add("sctp.ppi",  M2PA_PAYLOAD_PROTOCOL_ID,
400                 dissect_m2pa, proto_m2pa);
401   dissector_add("sctp.port", SCTP_PORT_M2PA, dissect_m2pa, proto_m2pa);
402 }