For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / epan / dissectors / packet-nb_rtpmux.c
1 /* packet-nb_rtpmux.c
2  * Routines for 3GPP RTP Multiplex dissection, 3GPP TS 29.414
3  * Copyright 2009, ip.access ltd <amp@ipaccess.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31
32 #include <epan/packet.h>
33
34 /* Initialize the protocol and registered fields */
35 static int proto_nb_rtpmux = -1;
36 static int hf_nb_rtpmux_compressed = -1;
37 static int hf_nb_rtpmux_dstport    = -1;
38 static int hf_nb_rtpmux_length     = -1;
39 static int hf_nb_r_bit             = -1;
40 static int hf_nb_rtpmux_srcport    = -1;
41 static int hf_nb_rtpmux_data       = -1;
42 static int hf_nb_rtpmux_cmp_rtp_sequence_no   = -1;
43 static int hf_nb_rtpmux_cmp_rtp_timestamp     = -1;
44 static int hf_nb_rtpmux_cmp_rtp_data          = -1;
45
46 /* Initialize the subtree pointers */
47 static gint ett_nb_rtpmux = -1;
48 static gint ett_nb_rtpmux_cmp_rtp_hdr = -1;
49
50 static dissector_handle_t rtpdissector;
51
52 /* Code to actually dissect the packets */
53 static int
54 dissect_nb_rtpmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
55 {
56     /* Set up structures needed to add the protocol subtree and manage it */
57     proto_item *ti, *cmp_rtp_item;
58     proto_tree *nb_rtpmux_tree, *nb_rtpmux_cmp_rtp_tree;
59     unsigned int offset = 0;
60
61     /*  First, if at all possible, do some heuristics to check if the packet cannot
62      *  possibly belong to your protocol.  This is especially important for
63      *  protocols directly on top of TCP or UDP where port collisions are
64      *  common place (e.g., even though your protocol uses a well known port,
65      *  someone else may set up, for example, a web server on that port which,
66      *  if someone analyzed that web server's traffic in Wireshark, would result
67      *  in Wireshark handing an HTTP packet to your dissector).  For example:
68      */
69
70     /*
71      * XXX - this is *FAR* too weak a heuristic; it could cause all sorts
72      * of stuff to be incorrectly identified as Nb_RTPmux.  Either this
73      * needs a stronger heuristic, or it needs to have a preference to
74      * set the port on which to dissect it, or it needs to be a non-heuristic
75      * dissector and *require* that a user use "Decode As..." to decode
76      * traffic as Nb_RTPmux.
77      *
78      * Look for a payload that looks like an RTP packet, using the
79      * same (weakish) heuristics as RTP uses?
80      */
81
82     /* Check that there's enough data */
83     if (tvb_length(tvb) < 6)
84         return 0;
85
86     /* Make entries in Protocol column and Info column on summary display */
87     col_set_str(pinfo->cinfo, COL_PROTOCOL, "NB_RTPMUX");
88
89     /* NOTE: The offset and length values in the call to
90        "proto_tree_add_item()" define what data bytes to highlight in the hex
91        display window when the line in the protocol tree display
92        corresponding to that item is selected.
93
94        Supplying a length of -1 is the way to highlight all data from the
95        offset to the end of the packet. */
96
97     /* create display subtree for the protocol */
98     while (offset < tvb_reported_length(tvb)-5)
99     {
100         guint16 dstport, srcport;
101         unsigned int length;
102         gint captured_length;
103         tvbuff_t* next_tvb;
104                 gboolean tbit;
105
106         length = tvb_get_guint8(tvb, offset+2);
107         ti = proto_tree_add_item(tree, proto_nb_rtpmux, tvb, offset,
108             length+5, ENC_NA);
109         nb_rtpmux_tree = proto_item_add_subtree(ti, ett_nb_rtpmux);
110
111         /* XXX - what if the T bit is set? */
112         proto_tree_add_item(nb_rtpmux_tree,
113             hf_nb_rtpmux_compressed, tvb, offset, 1, ENC_BIG_ENDIAN);
114                 tbit = tvb_get_guint8(tvb,offset)>>7;
115                 if(tbit == 1){
116                         /* 6.4.2.4 Transport Format for multiplexing with RTP header compression */
117                         dstport = (tvb_get_ntohs(tvb, offset) & 0x7fff) << 1;
118                         proto_tree_add_uint(nb_rtpmux_tree, hf_nb_rtpmux_dstport, tvb, offset, 2, dstport );
119                         proto_tree_add_item(nb_rtpmux_tree,
120                                 hf_nb_rtpmux_length, tvb, offset+2, 1, ENC_BIG_ENDIAN);
121             proto_tree_add_item(nb_rtpmux_tree, hf_nb_r_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
122                         srcport = (tvb_get_ntohs(tvb, offset+3) & 0x7fff) << 1;
123                         proto_tree_add_uint(nb_rtpmux_tree, hf_nb_rtpmux_srcport, tvb, offset+3, 2, srcport );
124                         cmp_rtp_item = proto_tree_add_text( nb_rtpmux_tree, tvb, offset+5, 3, "Compressed RTP header" );
125                         nb_rtpmux_cmp_rtp_tree = proto_item_add_subtree(cmp_rtp_item, ett_nb_rtpmux_cmp_rtp_hdr);
126                         /* Sequence Number (SN) */
127                         proto_tree_add_item(nb_rtpmux_cmp_rtp_tree, hf_nb_rtpmux_cmp_rtp_sequence_no, tvb, offset+5, 1, ENC_BIG_ENDIAN);
128                         /* Timestamp (TS) */
129                         proto_tree_add_item(nb_rtpmux_cmp_rtp_tree, hf_nb_rtpmux_cmp_rtp_timestamp, tvb, offset+6, 2, ENC_BIG_ENDIAN);
130                         if (length != 0)
131                                 proto_tree_add_item(nb_rtpmux_cmp_rtp_tree, hf_nb_rtpmux_cmp_rtp_data,tvb, offset+8, length-3, ENC_NA);
132
133                 }else{
134                         /* 6.4.2.3 Transport Format for multiplexing without RTP Header Compression */
135                         dstport = (tvb_get_ntohs(tvb, offset) & 0x7fff) << 1;
136                         proto_tree_add_uint(nb_rtpmux_tree, hf_nb_rtpmux_dstport, tvb, offset, 2, dstport );
137                         proto_tree_add_item(nb_rtpmux_tree,
138                                 hf_nb_rtpmux_length, tvb, offset+2, 1, ENC_BIG_ENDIAN);
139             proto_tree_add_item(nb_rtpmux_tree, hf_nb_r_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
140                         srcport = (tvb_get_ntohs(tvb, offset+3) & 0x7fff) << 1;
141                         proto_tree_add_uint(nb_rtpmux_tree, hf_nb_rtpmux_srcport, tvb, offset+3, 2, srcport );
142
143                         if (length != 0)
144                         {
145                                 /* We have an RTP payload. */
146                                 if (rtpdissector)
147                                 {
148                                         captured_length = tvb_length_remaining(tvb, offset + 5);
149                                         if (captured_length > (gint)length)
150                                                 captured_length = length;
151                                         next_tvb = tvb_new_subset(tvb, offset+5, captured_length,
152                                                                                           length);
153
154                                         call_dissector(rtpdissector, next_tvb, pinfo, nb_rtpmux_tree);
155                                 }
156                                 else
157                                 {
158                                         proto_tree_add_item(nb_rtpmux_tree,
159                                                 hf_nb_rtpmux_data, tvb, offset+5, length, ENC_NA);
160                                 }
161                         }
162                 } /* if tbit */
163                 offset += 5+length;
164     }
165
166     /* Return the amount of data this dissector was able to dissect */
167     return tvb_length(tvb);
168 }
169
170
171 /* Register the protocol with Wireshark */
172
173 /* this format is require because a script is used to build the C function
174    that calls all the protocol registration.
175 */
176 void
177 proto_register_nb_rtpmux(void)
178 {
179
180     static hf_register_info hf[] = {
181         { &hf_nb_rtpmux_compressed,
182             { "Compressed headers(T bit)", "nb_rtpmux.compressed",
183              FT_BOOLEAN, 8, NULL, 0x80,
184             NULL, HFILL }
185         },
186         { &hf_nb_rtpmux_dstport,
187             { "Dst port", "nb_rtpmux.dstport",
188              FT_UINT16, BASE_DEC, NULL, 0x7FFF,
189             NULL, HFILL }
190         },
191         { &hf_nb_rtpmux_length,
192             { "Length", "nb_rtpmux.length",
193              FT_UINT8, BASE_DEC, NULL, 0x00,
194             NULL, HFILL }
195         },
196         { &hf_nb_r_bit,
197             { "R bit", "nb_rtpmux.r_bit",
198              FT_BOOLEAN, 8, NULL, 0x80,
199             NULL, HFILL }
200         },
201         { &hf_nb_rtpmux_srcport,
202             { "Src port", "nb_rtpmux.srcport",
203              FT_UINT16, BASE_DEC, NULL, 0x7FFF,
204             NULL, HFILL }
205         },
206         { &hf_nb_rtpmux_data,
207             { "RTP Packet", "nb_rtpmux.data",
208              FT_BYTES, BASE_NONE, NULL, 0x00,
209             NULL, HFILL }
210         },
211        { &hf_nb_rtpmux_cmp_rtp_sequence_no,
212             { "Sequence Number", "nb_rtpmux.cmp_rtp.sequence_no",
213              FT_UINT16, BASE_DEC, NULL, 0x00,
214             NULL, HFILL }
215        },
216        { &hf_nb_rtpmux_cmp_rtp_timestamp,
217             { "Timestamp", "nb_rtpmux.cmp_rtp.timestamp",
218              FT_UINT16, BASE_DEC, NULL, 0x00,
219             NULL, HFILL }
220        },
221        { &hf_nb_rtpmux_cmp_rtp_data,
222             { "RTP Data", "nb_rtpmux.cmp_rtp.data",
223              FT_BYTES, BASE_NONE, NULL, 0x00,
224             NULL,HFILL }
225        }
226
227     };
228
229     /* Setup protocol subtree array */
230     static gint *ett[] = {
231         &ett_nb_rtpmux,
232                 &ett_nb_rtpmux_cmp_rtp_hdr
233     };
234
235     /* Register the protocol name and description */
236     proto_nb_rtpmux = proto_register_protocol("3GPP Nb Interface RTP Multiplex",
237         "NB_RTPMUX", "nb_rtpmux");
238
239     /* Required function calls to register the header fields and subtrees used */
240     proto_register_field_array(proto_nb_rtpmux, hf, array_length(hf));
241     proto_register_subtree_array(ett, array_length(ett));
242
243 }
244
245
246 /* If this dissector uses sub-dissector registration add a registration routine.
247    This exact format is required because a script is used to find these
248    routines and create the code that calls these routines.
249
250    This function is also called by preferences whenever "Apply" is pressed
251    (see prefs_register_protocol above) so it should accommodate being called
252    more than once.
253 */
254 void
255 proto_reg_handoff_nb_rtpmux(void)
256 {
257     dissector_handle_t nb_rtpmux_handle;
258
259     /*  Use new_create_dissector_handle() to indicate that dissect_nb_rtpmux()
260      *  returns the number of bytes it dissected (or 0 if it thinks the packet
261      *  does not belong to PROTONAME).
262      */
263     nb_rtpmux_handle = new_create_dissector_handle(dissect_nb_rtpmux,
264                                                    proto_nb_rtpmux);
265
266     dissector_add_handle("udp.port", nb_rtpmux_handle);
267     rtpdissector = find_dissector("rtp");
268 }
269