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>
6 * Using IPDC spec 0.20.2
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
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.
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.
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.
40 #include <epan/packet.h>
41 #include <epan/emem.h>
42 #include "packet-ipdc.h"
43 #include "packet-tcp.h"
44 #include <epan/ipproto.h>
45 #include <epan/prefs.h>
47 static int proto_ipdc = -1;
48 static int hf_ipdc_nr = -1;
49 static int hf_ipdc_ns = -1;
50 static int hf_ipdc_payload_len = -1;
51 static int hf_ipdc_protocol_id = -1;
52 static int hf_ipdc_trans_id_size = -1;
53 static int hf_ipdc_trans_id = -1;
54 static int hf_ipdc_message_code = -1;
56 static gint ett_ipdc = -1;
57 static gint ett_ipdc_tag = -1;
59 static gboolean ipdc_desegment = TRUE;
60 static guint ipdc_port_pref = TCP_PORT_IPDC;
61 static gboolean new_packet = FALSE;
63 static dissector_handle_t q931_handle;
65 void proto_reg_handoff_ipdc(void);
69 get_ipdc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
71 /* lower 10 bits only */
72 guint raw_len = (tvb_get_ntohs(tvb,offset+2) & 0x03FF);
78 dissect_ipdc_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
81 proto_tree *ipdc_tree;
87 const char *enum_val = "";
88 char tmp_tag_text[IPDC_STR_LEN + 1];
89 const value_string *val_ptr;
97 gshort nr = tvb_get_guint8(tvb,0);
98 gshort ns = tvb_get_guint8(tvb,1);
99 guint payload_len = get_ipdc_pdu_len(pinfo,tvb,0);
102 gshort trans_id_size;
104 guint16 message_code;
107 /* display IPDC protocol ID */
108 if (check_col(pinfo->cinfo, COL_PROTOCOL))
109 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPDC");
115 /* clear info column and display send/receive sequence numbers */
116 if (check_col(pinfo->cinfo, COL_INFO)) {
117 if (new_packet == TRUE) {
118 col_clear(pinfo->cinfo, COL_INFO);
121 col_append_fstr(pinfo->cinfo, COL_INFO, "r=%u s=%u ",
125 if (payload_len == 4) {
129 ti = proto_tree_add_item(tree, proto_ipdc, tvb, 0, -1, FALSE);
130 ipdc_tree = proto_item_add_subtree(ti, ett_ipdc);
131 proto_tree_add_item(ipdc_tree, hf_ipdc_nr, tvb, 0, 1, nr);
132 proto_tree_add_item(ipdc_tree, hf_ipdc_ns, tvb, 1, 1, ns);
133 proto_tree_add_uint(ipdc_tree, hf_ipdc_payload_len, tvb, 2, 2,
139 /* IPDC tags present - display message code and trans. ID */
140 protocol_id = tvb_get_guint8(tvb,4);
141 trans_id_size = TRANS_ID_SIZE_IPDC; /* tvb_get_guint8(tvb,5); */
142 trans_id = tvb_get_ntohl(tvb,6);
143 message_code = tvb_get_ntohs(tvb,6+trans_id_size);
144 offset = 6 + trans_id_size + 2; /* past message_code */
146 if (check_col(pinfo->cinfo, COL_INFO))
147 col_append_fstr(pinfo->cinfo, COL_INFO,
150 val_to_str(message_code, message_code_vals,
156 ti = proto_tree_add_item(tree, proto_ipdc, tvb, 0, -1, FALSE);
157 ipdc_tree = proto_item_add_subtree(ti, ett_ipdc);
159 proto_tree_add_item(ipdc_tree, hf_ipdc_nr, tvb, 0, 1, nr);
160 proto_tree_add_item(ipdc_tree, hf_ipdc_ns, tvb, 1, 1, ns);
161 proto_tree_add_uint(ipdc_tree, hf_ipdc_payload_len, tvb,
164 proto_tree_add_item(ipdc_tree, hf_ipdc_protocol_id, tvb,
166 proto_tree_add_item(ipdc_tree, hf_ipdc_trans_id_size, tvb,
167 5, 1, trans_id_size);
168 proto_tree_add_item(ipdc_tree, hf_ipdc_trans_id, tvb,
169 6, trans_id_size, trans_id);
170 proto_tree_add_item(ipdc_tree, hf_ipdc_message_code, tvb,
171 6 + trans_id_size + 1, 1, message_code);
173 ipdc_tag = proto_tree_add_text(ipdc_tree, tvb, offset,
174 payload_len - offset, "IPDC tags");
175 tag_tree = proto_item_add_subtree(ipdc_tag, ett_ipdc_tag);
177 /* iterate through tags. first byte is tag, second is length,
178 in bytes, following is tag data. tag of 0x0 should be
181 tag = tvb_get_guint8(tvb, offset);
184 if (offset == payload_len - 1) {
185 proto_tree_add_text(tag_tree, tvb,
186 offset, 1, "end of tags");
188 proto_tree_add_text(tag_tree, tvb,
189 offset, 1, "data trailing end of tags");
195 len = tvb_get_guint8(tvb,offset+1);
196 des = val_to_str(tag, tag_description, TEXT_UNDEFINED);
197 /* lookup tag type */
198 for (i = 0; (ipdc_tag_types[i].tag != tag &&
199 ipdc_tag_types[i].type != IPDC_UNKNOWN); i++)
201 type = ipdc_tag_types[i].type;
206 /* simple IPDC_ASCII strings */
208 DISSECTOR_ASSERT(len<=IPDC_STR_LEN);
209 tvb_memcpy(tvb, tmp_tag_text, offset+2, len);
210 tmp_tag_text[len] = 0;
211 proto_tree_add_text(tag_tree, tvb, offset,
212 len + 2, "0x%2.2x: %s: %s", tag, des,
216 /* unsigned integers, or bytes */
219 for (i = 0; i < len; i++)
220 tmp_tag += tvb_get_guint8(tvb,
221 offset + 2 + i) * (guint32)
222 pow(256, len - (i + 1));
226 val_to_str(IPDC_TAG(tag) +
228 tag_enum_type, TEXT_UNDEFINED);
231 strcmp(enum_val, TEXT_UNDEFINED) != 0) {
232 proto_tree_add_text(tag_tree, tvb,
237 proto_tree_add_text(tag_tree, tvb,
248 g_snprintf(tmp_tag_text,
251 tvb_get_guint8(tvb, offset + 2),
252 tvb_get_guint8(tvb, offset + 3),
253 tvb_get_guint8(tvb, offset + 4),
254 tvb_get_guint8(tvb, offset + 5)
259 g_snprintf(tmp_tag_text,
262 tvb_get_guint8(tvb, offset + 2),
263 tvb_get_guint8(tvb, offset + 3),
264 tvb_get_guint8(tvb, offset + 4),
265 tvb_get_guint8(tvb, offset + 5),
266 tvb_get_ntohs(tvb, offset + 6));
270 g_snprintf(tmp_tag_text,
272 "Invalid IP address length %u",
276 proto_tree_add_text(tag_tree, tvb,
279 tag, des, tmp_tag_text);
282 /* Line status arrays */
283 case IPDC_LINESTATUS:
284 case IPDC_CHANNELSTATUS:
285 proto_tree_add_text(tag_tree, tvb, offset,
286 len + 2, "0x%2.2x: %s", tag, des);
287 val_ptr = (type == IPDC_LINESTATUS) ?
288 line_status_vals : channel_status_vals;
290 for (i = 0; i < len; i++) {
291 status = tvb_get_guint8(tvb,offset+2+i);
293 proto_tree_add_text(tag_tree, tvb,
305 tvb_new_subset(tvb, offset+2, len, len);
306 call_dissector(q931_handle,q931_tvb,pinfo,tree);
310 proto_tree_add_text(tag_tree, tvb,
313 tag, des, val_to_str(
314 tvb_get_guint8(tvb,offset+2),
319 proto_tree_add_text(tag_tree, tvb,
323 tvb_get_guint8(tvb,offset+3));
329 proto_tree_add_text(tag_tree, tvb, offset,
330 len + 2, "0x%2.2x: %s", tag, des);
338 dissect_ipdc_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
340 dissect_ipdc_common(tvb, pinfo, tree);
344 dissect_ipdc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
347 tcp_dissect_pdus(tvb, pinfo, tree, ipdc_desegment, 4,
348 get_ipdc_pdu_len, dissect_ipdc_tcp_pdu);
352 proto_register_ipdc(void)
355 static hf_register_info hf[] = {
358 FT_UINT8, BASE_DEC, NULL, 0x0,
359 "Receive sequence number", HFILL }
364 FT_UINT8, BASE_DEC, NULL, 0x0,
365 "Transmit sequence number", HFILL }
368 { &hf_ipdc_payload_len,
369 { "Payload length", "ipdc.length",
370 FT_UINT16, BASE_DEC, NULL, 0x0,
371 "Payload length", HFILL }
374 { &hf_ipdc_protocol_id,
375 { "Protocol ID", "ipdc.protocol_id",
376 FT_UINT8, BASE_HEX, NULL, 0x0,
377 "Protocol ID", HFILL }
380 { &hf_ipdc_trans_id_size,
381 { "Transaction ID size", "ipdc.trans_id_size",
382 FT_UINT8, BASE_DEC, NULL, 0x0,
383 "Transaction ID size", HFILL }
387 { "Transaction ID", "ipdc.trans_id",
388 FT_BYTES, BASE_HEX, NULL, 0x0,
389 "Transaction ID", HFILL }
392 { &hf_ipdc_message_code,
393 { "Message code", "ipdc.message_code",
394 FT_UINT16, BASE_HEX, VALS(message_code_vals), 0x0,
395 "Message Code", HFILL }
399 static gint *ett[] = {
404 module_t *ipdc_module;
406 proto_ipdc = proto_register_protocol("IP Device Control (SS7 over IP)",
408 proto_register_field_array(proto_ipdc, hf, array_length(hf));
409 proto_register_subtree_array(ett, array_length(ett));
411 ipdc_module = prefs_register_protocol(proto_ipdc, proto_reg_handoff_ipdc);
412 prefs_register_bool_preference(ipdc_module, "desegment_ipdc_messages",
413 "Reassemble IPDC messages spanning multiple TCP segments",
414 "Whether the IPDC dissector should reassemble messages spanning multiple TCP segments."
415 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
417 prefs_register_uint_preference(ipdc_module, "tcp.port",
418 "IPDC monitoring port",
419 "Set the IPDC monitoring port", 10,
424 proto_reg_handoff_ipdc(void)
426 static guint last_ipdc_port_pref = 0;
427 static dissector_handle_t ipdc_tcp_handle = NULL;
429 if (ipdc_tcp_handle) {
430 dissector_delete("tcp.port", last_ipdc_port_pref,
434 create_dissector_handle(dissect_ipdc_tcp, proto_ipdc);
435 q931_handle = find_dissector("q931");
438 last_ipdc_port_pref = ipdc_port_pref;
439 dissector_add("tcp.port", ipdc_port_pref, ipdc_tcp_handle);