829bf63f98c1a312c05fccf6a4996ab352664fa7
[obnox/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         if (check_col(pinfo->cinfo, COL_INFO)) 
111                 col_clear(pinfo->cinfo, COL_INFO);
112
113         if (tree) {
114                 ti = proto_tree_add_item(tree, proto_rudp, tvb, 0, hlen, FALSE);
115                 rudp_tree = proto_item_add_subtree(ti, ett_rudp);
116
117                 ti = proto_tree_add_item(rudp_tree, hf_rudp_flags, tvb, 0, 1, FALSE);
118                 flags_tree = proto_item_add_subtree(ti, ett_rudp_flags);
119
120                 for (i = 0; i < 8; i++)
121                         proto_tree_add_item(flags_tree, flags[i], tvb, 0, 1, FALSE);
122
123                 proto_tree_add_item(rudp_tree, hf_rudp_hlen, tvb, 1, 1, FALSE);
124                 proto_tree_add_item(rudp_tree, hf_rudp_seq, tvb, 2, 1, FALSE);
125                 proto_tree_add_item(rudp_tree, hf_rudp_ack, tvb, 3, 1, FALSE);
126
127                 /* If the header is more than 4 bytes the next 2 bytes are the checksum */
128                 if (hlen > 4) {
129                         proto_tree_add_item(rudp_tree, hf_rudp_cksum, tvb, 4, 2, FALSE);
130                 }
131
132                 /* If we have even more bytes their meaning is unknown - we have seen this
133                  * in live captures */
134                 if (hlen > 6) {
135                         next_tvb = tvb_new_subset(tvb, 6, hlen-6, hlen-6);
136                         call_dissector(data_handle, next_tvb, pinfo, rudp_tree);
137                 }
138         }
139
140         next_tvb = tvb_new_subset(tvb, hlen, -1, -1);
141         if (tvb_length(next_tvb) && sm_handle)
142                 call_dissector(sm_handle, next_tvb, pinfo, tree);
143 }
144
145 void
146 proto_register_rudp(void)
147 {
148
149         static hf_register_info hf[] = {
150                 { &hf_rudp_flags,
151                         { "RUDP Header flags",           "rudp.flags",
152                         FT_UINT8, BASE_DEC, NULL, 0x0,
153                         NULL, HFILL }
154                 },
155                 { &hf_rudp_flags_syn,
156                         { "Syn",           "rudp.flags.syn",
157                         FT_BOOLEAN, 8, NULL, 0x80,
158                         NULL, HFILL }
159                 },
160                 { &hf_rudp_flags_ack,
161                         { "Ack",           "rudp.flags.ack",
162                         FT_BOOLEAN, 8, NULL, 0x40,
163                         NULL, HFILL }
164                 },
165                 { &hf_rudp_flags_eak,
166                         { "Eak",           "rudp.flags.eak",
167                         FT_BOOLEAN, 8, NULL, 0x20,
168                         "Extended Ack", HFILL }
169                 },
170                 { &hf_rudp_flags_rst,
171                         { "RST",           "rudp.flags.rst",
172                         FT_BOOLEAN, 8, NULL, 0x10,
173                         "Reset flag", HFILL }
174                 },
175                 { &hf_rudp_flags_nul,
176                         { "NULL",           "rudp.flags.nul",
177                         FT_BOOLEAN, 8, NULL, 0x08,
178                         "Null flag", HFILL }
179                 },
180                 { &hf_rudp_flags_chk,
181                         { "CHK",           "rudp.flags.chk",
182                         FT_BOOLEAN, 8, NULL, 0x04,
183                         "Checksum is on header or body", HFILL }
184                 },
185                 { &hf_rudp_flags_tcs,
186                         { "TCS",           "rudp.flags.tcs",
187                         FT_BOOLEAN, 8, NULL, 0x02,
188                         "Transfer Connection System", HFILL }
189                 },
190                 { &hf_rudp_flags_0,
191                         { "0",           "rudp.flags.0",
192                         FT_BOOLEAN, 8, NULL, 0x01,
193                         NULL, HFILL }
194                 },
195                 { &hf_rudp_hlen,
196                         { "Header Length",           "rudp.hlen",
197                         FT_UINT8, BASE_DEC, NULL, 0x0,
198                         NULL, HFILL }
199                 },
200                 { &hf_rudp_seq,
201                         { "Seq",           "rudp.seq",
202                         FT_UINT8, BASE_DEC, NULL, 0x0,
203                         "Sequence Number", HFILL }
204                 },
205                 { &hf_rudp_ack,
206                         { "Ack",           "rudp.ack",
207                         FT_UINT8, BASE_DEC, NULL, 0x0,
208                         "Acknowledgement Number", HFILL }
209                 },
210                 { &hf_rudp_cksum,
211                         { "Checksum",           "rudp.cksum",
212                         FT_UINT16, BASE_HEX, NULL, 0x0,
213                         NULL, HFILL }
214                 },
215         };
216
217
218 /* Setup protocol subtree array */
219         static gint *ett[] = {
220                 &ett_rudp,
221                 &ett_rudp_flags,
222         };
223
224
225         proto_rudp = proto_register_protocol (
226                 "Reliable UDP",         /* name */
227                 "RUDP",         /* short name */
228                 "rudp"          /* abbrev */
229                 );
230
231         proto_register_field_array(proto_rudp, hf, array_length(hf));
232         proto_register_subtree_array(ett, array_length(ett));
233
234         {
235                 module_t *rudp_module;
236                 rudp_module = prefs_register_protocol(proto_rudp, proto_reg_handoff_rudp);
237                 prefs_register_uint_preference(rudp_module,
238                         "udp.port",
239                         "UDP port for RUDP",
240                         "Set the UDP port for Reliable UDP traffic",
241                         10,
242                         &udp_port);
243         }
244
245 }
246
247 void
248 proto_reg_handoff_rudp(void) {
249
250         static gboolean initialized = FALSE;
251         static dissector_handle_t rudp_handle;
252         static guint saved_udp_port;
253
254         if (!initialized) {
255                 rudp_handle = create_dissector_handle(dissect_rudp, proto_rudp);
256                 dissector_add_handle("udp.port", rudp_handle);  /* for "decode as" */
257                 sm_handle = find_dissector("sm");
258                 data_handle = find_dissector("data");
259                 initialized = TRUE;
260         } else {
261                 if (saved_udp_port != 0) {
262                         dissector_delete("udp.port", saved_udp_port, rudp_handle);
263                 }
264         }
265
266         if (udp_port != 0) {
267                 dissector_add("udp.port", udp_port, rudp_handle);
268         }
269         saved_udp_port = udp_port;
270 }