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