Replace blurbs that match the name (case insensitive) with NULL.
[obnox/wireshark/wip.git] / epan / dissectors / packet-ipdc.c
1 /* packet-ipdc.c
2  * Routines for IP Device Control (SS7 over IP) dissection
3  * Copyright Lucent Technologies 2004
4  * Josh Bailey <joshbailey@lucent.com> and Ruud Linders <ruud@lucent.com>
5  *
6  * Using IPDC spec 0.20.2
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <glib.h>
37 #include <math.h>
38
39 #include <epan/packet.h>
40 #include "packet-ipdc.h"
41 #include "packet-tcp.h"
42 #include <epan/ipproto.h>
43 #include <epan/prefs.h>
44
45 static int proto_ipdc = -1;
46 static int hf_ipdc_nr = -1;
47 static int hf_ipdc_ns = -1;
48 static int hf_ipdc_payload_len = -1;
49 static int hf_ipdc_protocol_id = -1;
50 static int hf_ipdc_trans_id_size = -1;
51 static int hf_ipdc_trans_id = -1;
52 static int hf_ipdc_message_code = -1;
53
54 static gint ett_ipdc = -1;
55 static gint ett_ipdc_tag = -1;
56
57 static gboolean ipdc_desegment = TRUE;
58 static guint ipdc_port_pref = TCP_PORT_IPDC;
59 static gboolean new_packet = FALSE;
60
61 static dissector_handle_t q931_handle;
62
63 void proto_reg_handoff_ipdc(void);
64
65
66 static guint
67 get_ipdc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
68 {
69         /* lower 10 bits only */
70         guint raw_len = (tvb_get_ntohs(tvb,offset+2) & 0x03FF);
71
72         return raw_len + 4;
73 }
74
75 static void
76 dissect_ipdc_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
77 {
78         proto_item *ti;
79         proto_tree *ipdc_tree;
80         proto_item *ipdc_tag;
81         proto_tree *tag_tree;
82         tvbuff_t *q931_tvb;
83
84         const char *des;
85         const char *enum_val = "";
86         char tmp_tag_text[IPDC_STR_LEN + 1];
87         const value_string *val_ptr;
88         guint32 type;
89         guint len;
90         guint i;
91         guint status;
92         gshort tag;
93         guint32 tmp_tag;
94
95         gshort nr = tvb_get_guint8(tvb,0);
96         gshort ns = tvb_get_guint8(tvb,1);
97         guint payload_len = get_ipdc_pdu_len(pinfo,tvb,0);
98
99         gshort protocol_id;
100         gshort trans_id_size;
101         guint32 trans_id;
102         guint16 message_code;
103         guint16 offset;
104
105         /* display IPDC protocol ID */
106         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPDC");
107
108         /* short frame... */
109         if (payload_len < 4)
110                 return;
111
112         /* clear info column and display send/receive sequence numbers */
113         if (check_col(pinfo->cinfo, COL_INFO)) {
114                 if (new_packet == TRUE) {
115                         col_clear(pinfo->cinfo, COL_INFO);
116                         new_packet = FALSE;
117                 }
118                 col_append_fstr(pinfo->cinfo, COL_INFO, "r=%u s=%u ",
119                 nr, ns);
120         }
121
122         if (payload_len == 4) {
123                 if (!tree)
124                         return;
125
126                 ti = proto_tree_add_item(tree, proto_ipdc, tvb, 0, -1, FALSE);
127                 ipdc_tree = proto_item_add_subtree(ti, ett_ipdc);
128                 proto_tree_add_item(ipdc_tree, hf_ipdc_nr, tvb, 0, 1, nr);
129                 proto_tree_add_item(ipdc_tree, hf_ipdc_ns, tvb, 1, 1, ns);
130                 proto_tree_add_uint(ipdc_tree, hf_ipdc_payload_len, tvb, 2, 2,
131                         payload_len);
132
133                 return;
134         }
135
136         /* IPDC tags present - display message code and trans. ID */
137         protocol_id = tvb_get_guint8(tvb,4);
138         trans_id_size = TRANS_ID_SIZE_IPDC; /* tvb_get_guint8(tvb,5); */
139         trans_id = tvb_get_ntohl(tvb,6);
140         message_code = tvb_get_ntohs(tvb,6+trans_id_size);
141         offset = 6 + trans_id_size + 2; /* past message_code */
142
143         if (check_col(pinfo->cinfo, COL_INFO))
144                 col_append_fstr(pinfo->cinfo, COL_INFO,
145                         "TID=%x %s ",
146                         trans_id,
147                         val_to_str(message_code, message_code_vals,
148                         TEXT_UNDEFINED));
149
150
151         ti = proto_tree_add_item(tree, proto_ipdc, tvb, 0, -1, FALSE);
152         ipdc_tree = proto_item_add_subtree(ti, ett_ipdc);
153
154         proto_tree_add_item(ipdc_tree, hf_ipdc_nr, tvb, 0, 1, nr);
155         proto_tree_add_item(ipdc_tree, hf_ipdc_ns, tvb, 1, 1, ns);
156         proto_tree_add_uint(ipdc_tree, hf_ipdc_payload_len, tvb,
157                 2, 2, payload_len);
158
159         proto_tree_add_item(ipdc_tree, hf_ipdc_protocol_id, tvb,
160                 4, 1, protocol_id);
161         proto_tree_add_item(ipdc_tree, hf_ipdc_trans_id_size, tvb,
162                 5, 1, trans_id_size);
163         proto_tree_add_item(ipdc_tree, hf_ipdc_trans_id, tvb,
164                 6, trans_id_size, trans_id);
165         proto_tree_add_item(ipdc_tree, hf_ipdc_message_code, tvb,
166                 6 + trans_id_size + 1, 1, message_code);
167
168         ipdc_tag = proto_tree_add_text(ipdc_tree, tvb, offset,
169         payload_len - offset, "IPDC tags");
170         tag_tree = proto_item_add_subtree(ipdc_tag, ett_ipdc_tag);
171
172         /* iterate through tags. first byte is tag, second is length,
173            in bytes, following is tag data. tag of 0x0 should be
174            end of tags. */
175         for (;;) {
176                 tag = tvb_get_guint8(tvb, offset);
177
178                 if (tag == 0x0) {
179                         if (offset == payload_len - 1) {
180                                 proto_tree_add_text(tag_tree, tvb,
181                                 offset, 1, "end of tags");
182                         } else {
183                                 proto_tree_add_text(tag_tree, tvb,
184                                 offset, 1, "data trailing end of tags");
185                         }
186
187                         break;
188                 }
189
190                 len = tvb_get_guint8(tvb,offset+1);
191                 des = val_to_str(tag, tag_description, TEXT_UNDEFINED);
192                 /* lookup tag type */
193                 for (i = 0; (ipdc_tag_types[i].tag != tag &&
194                         ipdc_tag_types[i].type != IPDC_UNKNOWN); i++)
195                 ;
196                 type = ipdc_tag_types[i].type;
197
198                 tmp_tag = 0;
199
200                 switch (type) {
201                         /* simple IPDC_ASCII strings */
202                         case IPDC_ASCII:
203                                 DISSECTOR_ASSERT(len<=IPDC_STR_LEN);
204                                 tvb_memcpy(tvb, tmp_tag_text, offset+2, len);
205                                 tmp_tag_text[len] = 0;
206                                 proto_tree_add_text(tag_tree, tvb, offset,
207                                 len + 2, "0x%2.2x: %s: %s", tag, des,
208                                 tmp_tag_text);
209                         break;
210
211                         /* unsigned integers, or bytes */
212                         case IPDC_UINT:
213                         case IPDC_BYTE:
214                                 for (i = 0; i < len; i++)
215                                         tmp_tag += tvb_get_guint8(tvb,
216                                                 offset + 2 + i) * (guint32)
217                                                         pow(256, len - (i + 1));
218
219                                 if (len == 1)
220                                         enum_val =
221                                                 val_to_str(IPDC_TAG(tag) +
222                                                 tmp_tag,
223                                                 tag_enum_type, TEXT_UNDEFINED);
224
225                                 if (len == 1 &&
226                                         strcmp(enum_val, TEXT_UNDEFINED) != 0) {
227                                         proto_tree_add_text(tag_tree, tvb,
228                                                 offset, len + 2,
229                                                 "0x%2.2x: %s: %s",
230                                                 tag, des, enum_val);
231                                 } else {
232                                         proto_tree_add_text(tag_tree, tvb,
233                                                 offset, len + 2,
234                                                 "0x%2.2x: %s: %u",
235                                                 tag, des, tmp_tag);
236                                 }
237                         break;
238
239                         /* IP addresses */
240                         case IPDC_IPA:
241                                 switch (len) {
242                                         case 4:
243                                                 g_snprintf(tmp_tag_text,
244                                                 IPDC_STR_LEN,
245                                                 "%u.%u.%u.%u",
246                                                 tvb_get_guint8(tvb, offset + 2),
247                                                 tvb_get_guint8(tvb, offset + 3),
248                                                 tvb_get_guint8(tvb, offset + 4),
249                                                 tvb_get_guint8(tvb, offset + 5)
250                                                 );
251                                         break;
252
253                                         case 6:
254                                                 g_snprintf(tmp_tag_text,
255                                                 IPDC_STR_LEN,
256                                                 "%u.%u.%u.%u:%u",
257                                                 tvb_get_guint8(tvb, offset + 2),
258                                                 tvb_get_guint8(tvb, offset + 3),
259                                                 tvb_get_guint8(tvb, offset + 4),
260                                                 tvb_get_guint8(tvb, offset + 5),
261                                                 tvb_get_ntohs(tvb, offset + 6));
262                                         break;
263
264                                         default:
265                                                 g_snprintf(tmp_tag_text,
266                                                 IPDC_STR_LEN,
267                                                 "Invalid IP address length %u",
268                                                  len);
269                                 }
270
271                                 proto_tree_add_text(tag_tree, tvb,
272                                         offset, len + 2,
273                                         "0x%2.2x: %s: %s",
274                                         tag, des, tmp_tag_text);
275                         break;
276
277                         /* Line status arrays */
278                         case IPDC_LINESTATUS:
279                         case IPDC_CHANNELSTATUS:
280                                 proto_tree_add_text(tag_tree, tvb, offset,
281                                 len + 2, "0x%2.2x: %s", tag, des);
282                                 val_ptr = (type == IPDC_LINESTATUS) ?
283                                         line_status_vals : channel_status_vals;
284
285                                 for (i = 0; i < len; i++) {
286                                         status = tvb_get_guint8(tvb,offset+2+i);
287
288                                         proto_tree_add_text(tag_tree, tvb,
289                                                 offset + 2 + i, 1,
290                                                 " %.2u: %.2x (%s)",
291                                                 i + 1, status,
292                                                 val_to_str(status,
293                                                 val_ptr,
294                                                 TEXT_UNDEFINED));
295                                 }
296                         break;
297
298                         case IPDC_Q931:
299                                 q931_tvb =
300                                         tvb_new_subset(tvb, offset+2, len, len);
301                                 call_dissector(q931_handle,q931_tvb,pinfo,tree);
302                         break;
303
304                         case IPDC_ENCTYPE:
305                                 proto_tree_add_text(tag_tree, tvb,
306                                         offset, len + 2,
307                                         "0x%2.2x: %s: %s",
308                                         tag, des, val_to_str(
309                                         tvb_get_guint8(tvb,offset+2),
310                                         encoding_type_vals,
311                                         TEXT_UNDEFINED));
312
313                                 if (len == 2) {
314                                         proto_tree_add_text(tag_tree, tvb,
315                                                 offset, len + 2,
316                                                 "0x%2.2x: %s: %u",
317                                                 tag, des,
318                                                 tvb_get_guint8(tvb,offset+3));
319                                 }
320                         break;
321
322                         /* default */
323                         default:
324                                 proto_tree_add_text(tag_tree, tvb, offset,
325                                 len + 2, "0x%2.2x: %s", tag, des);
326                 } /* switch */
327
328                 offset += len + 2;
329         }
330 }
331
332 static void
333 dissect_ipdc_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
334 {
335         dissect_ipdc_common(tvb, pinfo, tree);
336 }
337
338 static void
339 dissect_ipdc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
340 {
341         new_packet = TRUE;
342         tcp_dissect_pdus(tvb, pinfo, tree, ipdc_desegment, 4,
343                 get_ipdc_pdu_len, dissect_ipdc_tcp_pdu);
344 }
345
346 void
347 proto_register_ipdc(void)
348 {
349
350         static hf_register_info hf[] = {
351                 { &hf_ipdc_nr,
352                         { "N(r)",       "ipdc.nr",
353                         FT_UINT8, BASE_DEC, NULL, 0x0,
354                         "Receive sequence number", HFILL }
355                 },
356
357                 { &hf_ipdc_ns,
358                         { "N(s)",       "ipdc.ns",
359                         FT_UINT8, BASE_DEC, NULL, 0x0,
360                         "Transmit sequence number", HFILL }
361                 },
362
363                 { &hf_ipdc_payload_len,
364                         { "Payload length",     "ipdc.length",
365                         FT_UINT16, BASE_DEC, NULL, 0x0,
366                         NULL, HFILL }
367                 },
368
369                 { &hf_ipdc_protocol_id,
370                         { "Protocol ID",        "ipdc.protocol_id",
371                         FT_UINT8, BASE_HEX, NULL, 0x0,
372                         NULL, HFILL }
373                 },
374
375                 { &hf_ipdc_trans_id_size,
376                         { "Transaction ID size",        "ipdc.trans_id_size",
377                         FT_UINT8, BASE_DEC, NULL, 0x0,
378                         NULL, HFILL }
379                 },
380
381                 { &hf_ipdc_trans_id,
382                         { "Transaction ID",     "ipdc.trans_id",
383                         FT_BYTES, BASE_NONE, NULL, 0x0,
384                         NULL, HFILL }
385                 },
386
387                 { &hf_ipdc_message_code,
388                         { "Message code",       "ipdc.message_code",
389                         FT_UINT16, BASE_HEX, VALS(message_code_vals), 0x0,
390                         NULL, HFILL }
391                 },
392         };
393
394         static gint *ett[] = {
395                 &ett_ipdc,
396                 &ett_ipdc_tag,
397         };
398
399         module_t *ipdc_module;
400
401         proto_ipdc = proto_register_protocol("IP Device Control (SS7 over IP)",
402             "IPDC", "ipdc");
403         proto_register_field_array(proto_ipdc, hf, array_length(hf));
404         proto_register_subtree_array(ett, array_length(ett));
405
406         ipdc_module = prefs_register_protocol(proto_ipdc, proto_reg_handoff_ipdc);
407         prefs_register_bool_preference(ipdc_module, "desegment_ipdc_messages",
408                 "Reassemble IPDC messages spanning multiple TCP segments",
409                 "Whether the IPDC dissector should reassemble messages spanning multiple TCP segments."
410                 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
411                 &ipdc_desegment);
412         prefs_register_uint_preference(ipdc_module, "tcp.port",
413                 "IPDC monitoring port",
414                 "Set the IPDC monitoring port", 10,
415                 &ipdc_port_pref);
416 }
417
418 void
419 proto_reg_handoff_ipdc(void)
420 {
421         static guint last_ipdc_port_pref = 0;
422         static dissector_handle_t ipdc_tcp_handle = NULL;
423
424         if (ipdc_tcp_handle) {
425                 dissector_delete("tcp.port", last_ipdc_port_pref,
426                         ipdc_tcp_handle);
427         } else {
428                 ipdc_tcp_handle =
429                         create_dissector_handle(dissect_ipdc_tcp, proto_ipdc);
430                 q931_handle = find_dissector("q931");
431         }
432
433         last_ipdc_port_pref = ipdc_port_pref;
434         dissector_add("tcp.port", ipdc_port_pref, ipdc_tcp_handle);
435 }