Define some fcns & vars as static...
[metze/wireshark/wip.git] / epan / dissectors / packet-rudp.c
1 /* packet-rudp.c
2  * Routines for Reliable UDP Protocol.
3  * Copyright 2004, Duncan Sargeant <dunc-ethereal@rcpt.to>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-data.c, README.developer, and various other files.
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  * Reliable UDP is a lightweight protocol for providing TCP-like flow
29  * control over UDP.  Cisco published an PFC a long time ago, and
30  * their actual implementation is slightly different, having no
31  * checksum field.
32  *
33  * I've cheated here - RUDP could be used for anything, but I've only
34  * seen it used to switched telephony calls, so we just call the Cisco SM
35  * dissector from here.
36  *
37  * Here are some links:
38  * 
39  * http://www.watersprings.org/pub/id/draft-ietf-sigtran-reliable-udp-00.txt
40  * http://www.javvin.com/protocolRUDP.html
41  * http://www.cisco.com/univercd/cc/td/doc/product/access/sc/rel7/omts/omts_apb.htm#30052
42
43  */
44
45 #ifdef HAVE_CONFIG_H
46 # include "config.h"
47 #endif
48
49 #include <glib.h>
50 #include <epan/packet.h>
51 #include <epan/prefs.h>
52
53 /* Disable rudp by default. The previously hardcoded value of
54  * 7000 (used by Cisco) collides with afs and as the draft states:
55  * "RUDP doesn't place any restrictions on which UDP port numbers are used.  
56  *  Valid port numbers are ports not defined in RFC 1700."
57  */
58 /* FIXME: The proper solution would be to convert this dissector into
59  *        heuristic dissector, but it isn't complete anyway.
60  */
61 static guint udp_port = 0;
62
63 void proto_reg_handoff_rudp(void);
64
65 static int proto_rudp = -1;
66
67 static int hf_rudp_flags = -1;
68 static int hf_rudp_flags_syn = -1;
69 static int hf_rudp_flags_ack = -1;
70 static int hf_rudp_flags_eak = -1;
71 static int hf_rudp_flags_rst = -1;
72 static int hf_rudp_flags_nul = -1;
73 static int hf_rudp_flags_chk = -1;
74 static int hf_rudp_flags_tcs = -1;
75 static int hf_rudp_flags_0 = -1;
76 static int hf_rudp_hlen = -1;
77 static int hf_rudp_seq = -1;
78 static int hf_rudp_ack = -1;
79 static int hf_rudp_cksum = -1;
80
81 static gint ett_rudp = -1;
82 static gint ett_rudp_flags = -1;
83
84 static dissector_handle_t sm_handle = NULL;
85 static dissector_handle_t data_handle = NULL;
86
87
88 static void
89 dissect_rudp(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree)
90 {
91         tvbuff_t * next_tvb = NULL;
92         proto_tree *rudp_tree = NULL, *flags_tree;
93         proto_item *ti = NULL;
94         int flags[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
95         int i;
96         guint8 hlen;
97
98         flags[0] = hf_rudp_flags_syn;
99         flags[1] = hf_rudp_flags_ack;
100         flags[2] = hf_rudp_flags_eak;
101         flags[3] = hf_rudp_flags_rst;
102         flags[4] = hf_rudp_flags_nul;
103         flags[5] = hf_rudp_flags_chk;
104         flags[6] = hf_rudp_flags_tcs;
105         flags[7] = hf_rudp_flags_0;
106
107         hlen = tvb_get_guint8(tvb, 1);
108
109         col_set_str(pinfo->cinfo, COL_PROTOCOL, "RUDP");
110         col_clear(pinfo->cinfo, COL_INFO);
111
112         if (tree) {
113                 ti = proto_tree_add_item(tree, proto_rudp, tvb, 0, hlen, FALSE);
114                 rudp_tree = proto_item_add_subtree(ti, ett_rudp);
115
116                 ti = proto_tree_add_item(rudp_tree, hf_rudp_flags, tvb, 0, 1, FALSE);
117                 flags_tree = proto_item_add_subtree(ti, ett_rudp_flags);
118
119                 for (i = 0; i < 8; i++)
120                         proto_tree_add_item(flags_tree, flags[i], tvb, 0, 1, FALSE);
121
122                 proto_tree_add_item(rudp_tree, hf_rudp_hlen, tvb, 1, 1, FALSE);
123                 proto_tree_add_item(rudp_tree, hf_rudp_seq, tvb, 2, 1, FALSE);
124                 proto_tree_add_item(rudp_tree, hf_rudp_ack, tvb, 3, 1, FALSE);
125
126                 /* If the header is more than 4 bytes the next 2 bytes are the checksum */
127                 if (hlen > 4) {
128                         proto_tree_add_item(rudp_tree, hf_rudp_cksum, tvb, 4, 2, FALSE);
129                 }
130
131                 /* If we have even more bytes their meaning is unknown - we have seen this
132                  * in live captures */
133                 if (hlen > 6) {
134                         next_tvb = tvb_new_subset(tvb, 6, hlen-6, hlen-6);
135                         call_dissector(data_handle, next_tvb, pinfo, rudp_tree);
136                 }
137         }
138
139         next_tvb = tvb_new_subset_remaining(tvb, hlen);
140         if (tvb_length(next_tvb) && sm_handle)
141                 call_dissector(sm_handle, next_tvb, pinfo, tree);
142 }
143
144 void
145 proto_register_rudp(void)
146 {
147
148         static hf_register_info hf[] = {
149                 { &hf_rudp_flags,
150                         { "RUDP Header flags",           "rudp.flags",
151                         FT_UINT8, BASE_DEC, NULL, 0x0,
152                         NULL, HFILL }
153                 },
154                 { &hf_rudp_flags_syn,
155                         { "Syn",           "rudp.flags.syn",
156                         FT_BOOLEAN, 8, NULL, 0x80,
157                         NULL, HFILL }
158                 },
159                 { &hf_rudp_flags_ack,
160                         { "Ack",           "rudp.flags.ack",
161                         FT_BOOLEAN, 8, NULL, 0x40,
162                         NULL, HFILL }
163                 },
164                 { &hf_rudp_flags_eak,
165                         { "Eak",           "rudp.flags.eak",
166                         FT_BOOLEAN, 8, NULL, 0x20,
167                         "Extended Ack", HFILL }
168                 },
169                 { &hf_rudp_flags_rst,
170                         { "RST",           "rudp.flags.rst",
171                         FT_BOOLEAN, 8, NULL, 0x10,
172                         "Reset flag", HFILL }
173                 },
174                 { &hf_rudp_flags_nul,
175                         { "NULL",           "rudp.flags.nul",
176                         FT_BOOLEAN, 8, NULL, 0x08,
177                         "Null flag", HFILL }
178                 },
179                 { &hf_rudp_flags_chk,
180                         { "CHK",           "rudp.flags.chk",
181                         FT_BOOLEAN, 8, NULL, 0x04,
182                         "Checksum is on header or body", HFILL }
183                 },
184                 { &hf_rudp_flags_tcs,
185                         { "TCS",           "rudp.flags.tcs",
186                         FT_BOOLEAN, 8, NULL, 0x02,
187                         "Transfer Connection System", HFILL }
188                 },
189                 { &hf_rudp_flags_0,
190                         { "0",           "rudp.flags.0",
191                         FT_BOOLEAN, 8, NULL, 0x01,
192                         NULL, HFILL }
193                 },
194                 { &hf_rudp_hlen,
195                         { "Header Length",           "rudp.hlen",
196                         FT_UINT8, BASE_DEC, NULL, 0x0,
197                         NULL, HFILL }
198                 },
199                 { &hf_rudp_seq,
200                         { "Seq",           "rudp.seq",
201                         FT_UINT8, BASE_DEC, NULL, 0x0,
202                         "Sequence Number", HFILL }
203                 },
204                 { &hf_rudp_ack,
205                         { "Ack",           "rudp.ack",
206                         FT_UINT8, BASE_DEC, NULL, 0x0,
207                         "Acknowledgement Number", HFILL }
208                 },
209                 { &hf_rudp_cksum,
210                         { "Checksum",           "rudp.cksum",
211                         FT_UINT16, BASE_HEX, NULL, 0x0,
212                         NULL, HFILL }
213                 },
214         };
215
216
217 /* Setup protocol subtree array */
218         static gint *ett[] = {
219                 &ett_rudp,
220                 &ett_rudp_flags,
221         };
222
223
224         proto_rudp = proto_register_protocol (
225                 "Reliable UDP",         /* name */
226                 "RUDP",         /* short name */
227                 "rudp"          /* abbrev */
228                 );
229
230         proto_register_field_array(proto_rudp, hf, array_length(hf));
231         proto_register_subtree_array(ett, array_length(ett));
232
233         {
234                 module_t *rudp_module;
235                 rudp_module = prefs_register_protocol(proto_rudp, proto_reg_handoff_rudp);
236                 prefs_register_uint_preference(rudp_module,
237                         "udp.port",
238                         "UDP port for RUDP",
239                         "Set the UDP port for Reliable UDP traffic",
240                         10,
241                         &udp_port);
242         }
243
244 }
245
246 void
247 proto_reg_handoff_rudp(void) {
248
249         static gboolean initialized = FALSE;
250         static dissector_handle_t rudp_handle;
251         static guint saved_udp_port;
252
253         if (!initialized) {
254                 rudp_handle = create_dissector_handle(dissect_rudp, proto_rudp);
255                 dissector_add_handle("udp.port", rudp_handle);  /* for "decode as" */
256                 sm_handle = find_dissector("sm");
257                 data_handle = find_dissector("data");
258                 initialized = TRUE;
259         } else {
260                 if (saved_udp_port != 0) {
261                         dissector_delete("udp.port", saved_udp_port, rudp_handle);
262                 }
263         }
264
265         if (udp_port != 0) {
266                 dissector_add("udp.port", udp_port, rudp_handle);
267         }
268         saved_udp_port = udp_port;
269 }