Support for ANSI flavor of MTP3, from Jeff Morriss.
[obnox/wireshark/wip.git] / packet-mtp3.c
1 /* packet-mtp3.c
2  * Routines for Message Transfer Part Level 3 dissection
3  * Copyright 2001, Michael Tuexen <Michael.Tuexen@icn.siemens.de>
4  *
5  * $Id: packet-mtp3.c,v 1.5 2001/07/07 09:06:40 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from README.developer
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #ifdef HAVE_NETINET_IN_H
41 # include <netinet/in.h>
42 #endif
43
44 #include <glib.h>
45
46 #include "packet.h"
47 #include "prefs.h"
48
49 /* Initialize the protocol and registered fields */
50 static int proto_mtp3  = -1;
51 static module_t *mtp3_module;
52
53 static int hf_mtp3_service_indicator = -1;
54 static int hf_mtp3_network_indicator = -1;
55 static int hf_mtp3_itu_spare = -1;
56 static int hf_mtp3_ansi_priority = -1;
57 static int hf_mtp3_itu_opc = -1;
58 static int hf_mtp3_opc_network = -1;
59 static int hf_mtp3_opc_cluster = -1;
60 static int hf_mtp3_opc_member = -1;
61 static int hf_mtp3_itu_dpc = -1;
62 static int hf_mtp3_dpc_network = -1;
63 static int hf_mtp3_dpc_cluster = -1;
64 static int hf_mtp3_dpc_member = -1;
65 static int hf_mtp3_itu_sls = -1;
66 static int hf_mtp3_ansi_sls = -1;
67
68 /* Initialize the subtree pointers */
69 static gint ett_mtp3 = -1;
70 static gint ett_mtp3_sio = -1;
71 static gint ett_mtp3_label = -1;
72 static gint ett_mtp3_label_dpc = -1;
73 static gint ett_mtp3_label_opc = -1;
74
75 static dissector_table_t mtp3_sio_dissector_table;
76
77 #define ITU_STANDARD   1
78 #define ANSI_STANDARD  2
79
80 static gint mtp3_standard = ITU_STANDARD;
81
82 #define SIO_OFFSET 0
83 #define SIO_LENGTH 1
84 #define ITU_ROUTING_LABEL_OFFSET 1
85 #define ITU_ROUTING_LABEL_LENGTH 4
86 #define ITU_SLS_OFFSET 1
87 #define ITU_SLS_LENGTH 1
88 #define ITU_MTP_PAYLOAD_OFFSET 5
89
90 #define ANSI_ROUTING_LABEL_OFFSET 1
91 #define ANSI_ROUTING_LABEL_LENGTH 7
92 #define ANSI_MTP_PAYLOAD_OFFSET 8
93 #define ANSI_DPC_OFFSET 1
94 #define ANSI_DPC_LENGTH 3
95 #define ANSI_OPC_OFFSET 4
96 #define ANSI_OPC_LENGTH 3
97 #define ANSI_SLS_OFFSET 7
98 #define ANSI_SLS_LENGTH 1
99
100 #define ANSI_NCM_LENGTH 3
101 #define ANSI_DPC_OFFSET 1
102 #define ANSI_OPC_OFFSET 4
103
104 #define SERVICE_INDICATOR_MASK 0x0F
105 #define SPARE_MASK 0x30
106 #define ANSI_PRIORITY_MASK SPARE_MASK
107 #define NETWORK_INDICATOR_MASK 0xC0
108 #define ITU_DPC_MASK 0x00003FFF
109 #define ITU_OPC_MASK 0x0FFFC000
110 #define ITU_SLS_MASK 0xF0000000
111
112 #define ANSI_NETWORK_MASK 0x0000FF
113 #define ANSI_CLUSTER_MASK 0x00FF00
114 #define ANSI_MEMBER_MASK  0xFF0000
115 #define ANSI_5BIT_SLS_MASK 0x1F
116 /* TODO: eventually add support for ANSI 8-bit SLS */
117 #define ANSI_8BIT_SLS_MASK 0xFF
118
119 static const value_string service_indicator_code_vals[] = {
120         { 0x0,  "Signalling Network Management Message (SNM)" },
121         { 0x1,  "Maintenance Regular Message (MTN)" },
122         { 0x2,  "Maintenance Special Message (MTNS)" },
123         { 0x3,  "SCCP" },
124         { 0x4,  "TUP" },
125         { 0x5,  "ISUP" },
126         { 0x6,  "DUP (call and circuit related messages)" },
127         { 0x7,  "DUP (facility registration and cancellation message)" },
128         { 0x8,  "MTP testing user part" },
129         { 0x9,  "Spare" },
130         { 0xa,  "Spare" },
131         { 0xb,  "Spare" },
132         { 0xc,  "Spare" },
133         { 0xd,  "Spare" },
134         { 0xe,  "Spare" },
135         { 0xf,  "Spare" },
136         { 0,    NULL }
137 };
138
139 static const value_string network_indicator_vals[] = {
140         { 0x0,  "International network" },
141         { 0x1,  "Spare (for international use only)" },
142         { 0x2,  "National network" },
143         { 0x3,  "Reserved for national use" },
144         { 0,    NULL }
145 };
146
147 static void
148 dissect_mtp3_sio(tvbuff_t *tvb, proto_tree *mtp3_tree)
149 {
150   guint8 sio;
151   proto_item *sio_item;
152   proto_tree *sio_tree;
153
154   sio_item = proto_tree_add_text(mtp3_tree, tvb, SIO_OFFSET, SIO_LENGTH, "Service information octet");
155   sio_tree = proto_item_add_subtree(sio_item, ett_mtp3_sio);
156
157   sio = tvb_get_guint8(tvb, SIO_OFFSET);
158   proto_tree_add_uint(sio_tree, hf_mtp3_network_indicator,
159                       tvb, SIO_OFFSET, SIO_LENGTH,
160                       sio);
161   if (mtp3_standard == ANSI_STANDARD)
162     proto_tree_add_uint(sio_tree, hf_mtp3_ansi_priority,
163                         tvb, SIO_OFFSET, SIO_LENGTH,
164                         sio);
165   else
166     proto_tree_add_uint(sio_tree, hf_mtp3_itu_spare,
167                         tvb, SIO_OFFSET, SIO_LENGTH,
168                         sio);
169   proto_tree_add_uint(sio_tree, hf_mtp3_service_indicator,
170                       tvb, SIO_OFFSET, SIO_LENGTH,
171                       sio);
172 }
173
174 static void
175 dissect_mtp3_routing_label(tvbuff_t *tvb, proto_tree *mtp3_tree)
176 {
177   guint32 label, dpc, opc;
178   guint8 sls;
179   proto_item *label_item, *label_dpc_item, *label_opc_item;
180   proto_tree *label_tree, *label_dpc_tree, *label_opc_tree;
181
182   switch (mtp3_standard) {
183   case ITU_STANDARD:
184     label_item = proto_tree_add_text(mtp3_tree, tvb, ITU_ROUTING_LABEL_OFFSET,
185                                      ITU_ROUTING_LABEL_LENGTH, "Routing label");
186     label_tree = proto_item_add_subtree(label_item, ett_mtp3_label);
187
188     label = tvb_get_letohl(tvb, ITU_ROUTING_LABEL_OFFSET);
189     sls = tvb_get_guint8(tvb, ITU_ROUTING_LABEL_OFFSET);
190
191     proto_tree_add_uint(label_tree, hf_mtp3_itu_dpc, tvb,
192                         ITU_ROUTING_LABEL_OFFSET, ITU_ROUTING_LABEL_LENGTH,
193                         label);
194     proto_tree_add_uint(label_tree, hf_mtp3_itu_opc, tvb,
195                         ITU_ROUTING_LABEL_OFFSET, ITU_ROUTING_LABEL_LENGTH,
196                         label);
197     proto_tree_add_uint(label_tree, hf_mtp3_itu_sls, tvb,
198                         ITU_SLS_OFFSET, ITU_SLS_LENGTH,
199                         sls);
200     break;
201
202   case ANSI_STANDARD:
203     /* this could be 5 or 8 bits */
204     sls = tvb_get_guint8(tvb, ANSI_SLS_OFFSET);
205
206     /* Create the Routing Label Tree */
207     label_item = proto_tree_add_text(mtp3_tree, tvb, ANSI_ROUTING_LABEL_OFFSET,
208                                      ANSI_ROUTING_LABEL_LENGTH, "Routing label");
209     label_tree = proto_item_add_subtree(label_item, ett_mtp3_label);
210
211     /* create the DPC tree */
212     dpc = tvb_get_ntoh24(tvb, ANSI_DPC_OFFSET);
213     label_dpc_item = proto_tree_add_text(label_tree, tvb, ANSI_DPC_OFFSET,
214                                          ANSI_DPC_LENGTH,
215                                          "DPC (%d-%d-%d)",
216                                          (dpc & ANSI_NETWORK_MASK),
217                                          ((dpc & ANSI_CLUSTER_MASK) >> 8),
218                                          ((dpc & ANSI_MEMBER_MASK) >> 16));
219
220     label_dpc_tree = proto_item_add_subtree(label_dpc_item,
221                                             ett_mtp3_label_dpc);
222
223     proto_tree_add_uint(label_dpc_tree, hf_mtp3_dpc_member,
224                         tvb, ANSI_DPC_OFFSET, ANSI_NCM_LENGTH, dpc);
225     proto_tree_add_uint(label_dpc_tree, hf_mtp3_dpc_cluster,
226                         tvb, ANSI_DPC_OFFSET, ANSI_NCM_LENGTH, dpc);
227     proto_tree_add_uint(label_dpc_tree, hf_mtp3_dpc_network,
228                         tvb, ANSI_DPC_OFFSET, ANSI_NCM_LENGTH, dpc);
229
230   /* create the OPC tree */
231     opc = tvb_get_ntoh24(tvb, ANSI_OPC_OFFSET);
232
233     label_opc_item = proto_tree_add_text(label_tree, tvb, ANSI_OPC_OFFSET,
234                                          ANSI_OPC_LENGTH,
235                                          "OPC (%d-%d-%d)",
236                                          (opc & ANSI_NETWORK_MASK),
237                                          ((opc & ANSI_CLUSTER_MASK) >> 8),
238                                          ((opc & ANSI_MEMBER_MASK) >> 16));
239
240     label_opc_tree = proto_item_add_subtree(label_opc_item,
241                                             ett_mtp3_label_opc);
242
243     proto_tree_add_uint(label_opc_tree, hf_mtp3_opc_member,
244                         tvb, ANSI_OPC_OFFSET, ANSI_NCM_LENGTH, opc);
245     proto_tree_add_uint(label_opc_tree, hf_mtp3_opc_cluster,
246                         tvb, ANSI_OPC_OFFSET, ANSI_NCM_LENGTH, opc);
247     proto_tree_add_uint(label_opc_tree, hf_mtp3_opc_network,
248                         tvb, ANSI_OPC_OFFSET, ANSI_NCM_LENGTH,
249                         opc);
250     /* SLS */
251     /* TODO: separate 5-bit and 8-bit SLS */
252     proto_tree_add_item(label_tree, hf_mtp3_ansi_sls, tvb, ANSI_SLS_OFFSET,
253                         ANSI_SLS_LENGTH, sls);
254     /*    proto_tree_add_uint(label_tree, hf_mtp3_ansi_sls, tvb,
255                         ANSI_SLS_OFFSET, ANSI_SLS_LENGTH,
256                         sls);*/
257     break;
258
259   default:
260     printf("MTP3: unknown standard: %d\n", mtp3_standard);
261   }
262 }
263
264 static void
265 dissect_mtp3_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
266 {
267   guint8 sio;
268   guint8 service_indicator;
269   tvbuff_t *payload_tvb;
270
271   sio = tvb_get_guint8(tvb, SIO_OFFSET);
272   service_indicator = sio & SERVICE_INDICATOR_MASK;
273
274   switch (mtp3_standard) {
275   case ITU_STANDARD:
276     payload_tvb = tvb_new_subset(tvb, ITU_MTP_PAYLOAD_OFFSET, -1, -1);
277     break;
278   case ANSI_STANDARD:
279     payload_tvb = tvb_new_subset(tvb, ANSI_MTP_PAYLOAD_OFFSET, -1, -1);
280     break;
281   default:
282     printf("MTP3: unknown standard: %d\n", mtp3_standard);
283     return;
284   }
285
286   if (!dissector_try_port(mtp3_sio_dissector_table, service_indicator, payload_tvb, pinfo, tree)) {
287     proto_tree_add_text(tree, payload_tvb, 0, tvb_length(payload_tvb),
288                         "Payload (%u byte%s)",
289                         tvb_length(payload_tvb), plurality(tvb_length(payload_tvb), "", "s"));
290   }
291 }
292
293 /* Code to actually dissect the packets */
294 static void
295 dissect_mtp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
296 {
297
298   /* Set up structures needed to add the protocol subtree and manage it */
299   proto_item *mtp3_item;
300   proto_tree *mtp3_tree;
301
302   /* Make entries in Protocol column and Info column on summary display */
303   if (check_col(pinfo->fd, COL_PROTOCOL))
304     col_set_str(pinfo->fd, COL_PROTOCOL, "MTP3");
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
311   if (tree) {
312
313     /* create display subtree for the protocol */
314     mtp3_item = proto_tree_add_item(tree, proto_mtp3, tvb, 0, tvb_length(tvb),
315                                     FALSE);
316     mtp3_tree = proto_item_add_subtree(mtp3_item, ett_mtp3);
317
318     /* dissect the packet */
319     dissect_mtp3_sio(tvb, mtp3_tree);
320     dissect_mtp3_routing_label(tvb, mtp3_tree);
321     dissect_mtp3_payload(tvb, pinfo, mtp3_tree);
322   }
323 }
324
325 void
326 proto_register_mtp3(void)
327 {
328
329   /* Setup list of header fields  See Section 1.6.1 for details*/
330   static hf_register_info hf[] = {
331     { &hf_mtp3_service_indicator,
332       { "Service indicator",
333         "mtp3.service_indicator",
334         FT_UINT8, BASE_HEX, VALS(service_indicator_code_vals), SERVICE_INDICATOR_MASK,
335         "", HFILL }},
336     { &hf_mtp3_network_indicator,
337       { "Network indicator",
338         "mtp3.network_indicator",
339         FT_UINT8, BASE_HEX, VALS(network_indicator_vals), NETWORK_INDICATOR_MASK,
340         "", HFILL }},
341     { &hf_mtp3_itu_spare,
342       { "Spare",
343         "mtp3.spare",
344         FT_UINT8, BASE_HEX, NULL, SPARE_MASK,
345         "", HFILL }},
346     { &hf_mtp3_ansi_priority,
347       { "Priority",
348         "mtp3.priority",
349         FT_UINT8, BASE_HEX, NULL, ANSI_PRIORITY_MASK,
350         "", HFILL }},
351     { &hf_mtp3_itu_opc,
352       { "OPC",
353         "mtp3.opc",
354         FT_UINT32, BASE_DEC, NULL, ITU_OPC_MASK,
355         "", HFILL }},
356     { &hf_mtp3_opc_network,
357      { "OPC Network",
358         "mtp3.opc.network",
359         FT_UINT24, BASE_DEC, NULL, ANSI_NETWORK_MASK,
360         "", HFILL }},
361     { &hf_mtp3_opc_cluster,
362       { "OPC Cluster",
363         "mtp3.opc.cluster",
364         FT_UINT24, BASE_DEC, NULL, ANSI_CLUSTER_MASK,
365         "", HFILL }},
366     { &hf_mtp3_opc_member,
367       { "OPC Member",
368         "mtp3.opc.member",
369         FT_UINT24, BASE_DEC, NULL, ANSI_MEMBER_MASK,
370         "", HFILL }},
371     { &hf_mtp3_itu_dpc,
372       { "DPC",
373         "mtp3.dpc",
374         FT_UINT32, BASE_DEC, NULL, ITU_DPC_MASK,
375         "", HFILL }},
376     { &hf_mtp3_dpc_network,
377       { "DPC Network",
378         "mtp3.dpc.network",
379         FT_UINT24, BASE_DEC, NULL, ANSI_NETWORK_MASK,
380         "", HFILL }},
381     { &hf_mtp3_dpc_cluster,
382       { "DPC Cluster",
383         "mtp3.dpc.cluster",
384         FT_UINT24, BASE_DEC, NULL, ANSI_CLUSTER_MASK,
385         "", HFILL }},
386     { &hf_mtp3_dpc_member,
387       { "DPC Member",
388         "mtp3.dpc.member",
389         FT_UINT24, BASE_DEC, NULL, ANSI_MEMBER_MASK,
390         "", HFILL }},
391     { &hf_mtp3_itu_sls,
392       { "Signalling Link Selector",
393         "mtp3.sls",
394         FT_UINT32, BASE_DEC, NULL, ITU_SLS_MASK,
395         "", HFILL }},
396     { &hf_mtp3_ansi_sls,
397       { "Signalling Link Selector",
398         "mtp3.sls",
399         FT_UINT8, BASE_DEC, NULL, ANSI_5BIT_SLS_MASK,
400         "", HFILL }}
401   };
402
403   /* Setup protocol subtree array */
404   static gint *ett[] = {
405     &ett_mtp3,
406     &ett_mtp3_sio,
407     &ett_mtp3_label,
408     &ett_mtp3_label_dpc,
409     &ett_mtp3_label_opc
410   };
411
412   static enum_val_t mtp3_options[] = {
413     { "ITU",  ITU_STANDARD },
414     { "ANSI", ANSI_STANDARD },
415     { NULL, 0 }
416   };
417
418   /* Register the protocol name and description */
419   proto_mtp3 = proto_register_protocol("Message Transfer Part Level 3",
420                                        "MTP3", "mtp3");
421
422   /* Required function calls to register the header fields and subtrees used */
423   proto_register_field_array(proto_mtp3, hf, array_length(hf));
424   proto_register_subtree_array(ett, array_length(ett));
425
426   /* Register the dissector */
427   register_dissector("mtp3", dissect_mtp3, proto_mtp3);
428
429   mtp3_sio_dissector_table = register_dissector_table("mtp3.service_indicator");
430
431   mtp3_module = prefs_register_protocol(proto_mtp3, NULL);
432
433   prefs_register_enum_preference(mtp3_module,
434                                  "mtp3_standard",
435                                  "MTP3 standard",
436                                  "MTP3 standard",
437                                  &mtp3_standard,
438                                  mtp3_options, FALSE);
439 }