Revert "Fixup: tvb_* -> tvb_captured"
[metze/wireshark/wip.git] / epan / dissectors / packet-rtsp.c
1 /* packet-rtsp.c
2  * Routines for RTSP packet disassembly (RFC 2326)
3  *
4  * Jason Lango <jal@netapp.com>
5  * Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
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  * References:
26  * RTSP is defined in RFC 2326, http://www.ietf.org/rfc/rfc2326.txt?number=2326
27  * http://www.iana.org/assignments/rsvp-parameters
28  */
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35
36 #include <glib.h>
37
38 #include <epan/packet.h>
39 #include <epan/req_resp_hdrs.h>
40 #include <epan/prefs.h>
41 #include <epan/conversation.h>
42 #include <epan/strutil.h>
43 #include <epan/tap.h>
44 #include <epan/tap-voip.h>
45 #include <epan/stats_tree.h>
46 #include <epan/wmem/wmem.h>
47 #include <wsutil/str_util.h>
48
49 #include "packet-rdt.h"
50 #include "packet-rtp.h"
51 #include "packet-rtcp.h"
52 #include "packet-e164.h"
53 #include "packet-rtsp.h"
54
55 void proto_register_rtsp(void);
56
57 static int rtsp_tap = -1;
58 static rtsp_info_value_t *rtsp_stat_info;
59
60 /* http://www.iana.org/assignments/rtsp-parameters/rtsp-parameters.xml */
61
62 const value_string rtsp_status_code_vals[] = {
63     { 100, "Continue" },
64     { 199, "Informational - Others" },
65
66     { 200, "OK"},
67     { 201, "Created"},
68     { 250, "Low on Storage Space"},
69     { 299, "Success - Others"},
70
71     { 300, "Multiple Choices"},
72     { 301, "Moved Permanently"},
73     { 302, "Moved Temporarily"},
74     { 303, "See Other"},
75     { 305, "Use Proxy"},
76     { 399, "Redirection - Others"},
77
78     { 400, "Bad Request"},
79     { 401, "Unauthorized"},
80     { 402, "Payment Required"},
81     { 403, "Forbidden"},
82     { 404, "Not Found"},
83     { 405, "Method Not Allowed"},
84     { 406, "Not Acceptable"},
85     { 407, "Proxy Authentication Required"},
86     { 408, "Request Timeout"},
87     { 410, "Gone"},
88     { 411, "Length Required"},
89     { 412, "Precondition Failed"},
90     { 413, "Request Entity Too Large"},
91     { 414, "Request-URI Too Long"},
92     { 415, "Unsupported Media Type"},
93     { 451, "Invalid Parameter"},
94     { 452, "Illegal Conferenec Identifier"},
95     { 453, "Not Enough Bandwidth"},
96     { 454, "Session Not Found"},
97     { 455, "Method Not Valid In This State"},
98     { 456, "Header Field Not Valid"},
99     { 457, "Invalid Range"},
100     { 458, "Parameter Is Read-Only"},
101     { 459, "Aggregate Operation Not Allowed"},
102     { 460, "Only Aggregate Operation Allowed"},
103     { 461, "Unsupported Transport"},
104     { 462, "Destination Unreachable"},
105     { 499, "Client Error - Others"},
106
107     { 500, "Internal Server Error"},
108     { 501, "Not Implemented"},
109     { 502, "Bad Gateway"},
110     { 503, "Service Unavailable"},
111     { 504, "Gateway Timeout"},
112     { 505, "RTSP Version not supported"},
113     { 551, "Option Not Support"},
114     { 599, "Server Error - Others"},
115
116     { 0,    NULL}
117 };
118
119 static int proto_rtsp       = -1;
120
121 static gint ett_rtsp        = -1;
122 static gint ett_rtspframe   = -1;
123 static gint ett_rtsp_method     = -1;
124
125 static int hf_rtsp_request  = -1;
126 static int hf_rtsp_response = -1;
127 static int hf_rtsp_content_type = -1;
128 static int hf_rtsp_content_length   = -1;
129 static int hf_rtsp_method   = -1;
130 static int hf_rtsp_url      = -1;
131 static int hf_rtsp_status   = -1;
132 static int hf_rtsp_session  = -1;
133 static int hf_rtsp_transport    = -1;
134 static int hf_rtsp_rdtfeaturelevel  = -1;
135 static int hf_rtsp_X_Vig_Msisdn = -1;
136 static int hf_rtsp_magic = -1;
137 static int hf_rtsp_channel = -1;
138 static int hf_rtsp_length = -1;
139
140 static int voip_tap = -1;
141
142 static dissector_handle_t rtp_handle;
143 static dissector_handle_t rtcp_handle;
144 static dissector_handle_t rdt_handle;
145 static dissector_table_t media_type_dissector_table;
146
147 static const gchar *st_str_packets = "Total RTSP Packets";
148 static const gchar *st_str_requests = "RTSP Request Packets";
149 static const gchar *st_str_responses = "RTSP Response Packets";
150 static const gchar *st_str_resp_broken = "???: broken";
151 static const gchar *st_str_resp_100 = "1xx: Informational";
152 static const gchar *st_str_resp_200 = "2xx: Success";
153 static const gchar *st_str_resp_300 = "3xx: Redirection";
154 static const gchar *st_str_resp_400 = "4xx: Client Error";
155 static const gchar *st_str_resp_500 = "5xx: Server Error";
156 static const gchar *st_str_other = "Other RTSP Packets";
157
158 static int st_node_packets = -1;
159 static int st_node_requests = -1;
160 static int st_node_responses = -1;
161 static int st_node_resp_broken = -1;
162 static int st_node_resp_100 = -1;
163 static int st_node_resp_200 = -1;
164 static int st_node_resp_300 = -1;
165 static int st_node_resp_400 = -1;
166 static int st_node_resp_500 = -1;
167 static int st_node_other = -1;
168
169 static void
170 rtsp_stats_tree_init(stats_tree* st)
171 {
172     st_node_packets     = stats_tree_create_node(st, st_str_packets, 0, TRUE);
173     st_node_requests    = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
174     st_node_responses   = stats_tree_create_node(st, st_str_responses, st_node_packets, TRUE);
175     st_node_resp_broken = stats_tree_create_node(st, st_str_resp_broken, st_node_responses, TRUE);
176     st_node_resp_100    = stats_tree_create_node(st, st_str_resp_100,    st_node_responses, TRUE);
177     st_node_resp_200    = stats_tree_create_node(st, st_str_resp_200,    st_node_responses, TRUE);
178     st_node_resp_300    = stats_tree_create_node(st, st_str_resp_300,    st_node_responses, TRUE);
179     st_node_resp_400    = stats_tree_create_node(st, st_str_resp_400,    st_node_responses, TRUE);
180     st_node_resp_500    = stats_tree_create_node(st, st_str_resp_500,    st_node_responses, TRUE);
181     st_node_other       = stats_tree_create_node(st, st_str_other, st_node_packets, FALSE);
182 }
183
184 /* RTSP/Packet Counter stats packet function */
185 static int
186 rtsp_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p)
187 {
188     const rtsp_info_value_t *v = (const rtsp_info_value_t *)p;
189     guint         i = v->response_code;
190     int           resp_grp;
191     const gchar  *resp_str;
192     static gchar  str[64];
193
194     tick_stat_node(st, st_str_packets, 0, FALSE);
195
196     if (i) {
197         tick_stat_node(st, st_str_responses, st_node_packets, FALSE);
198
199         if ( (i<100)||(i>=600) ) {
200             resp_grp = st_node_resp_broken;
201             resp_str = st_str_resp_broken;
202         } else if (i<200) {
203             resp_grp = st_node_resp_100;
204             resp_str = st_str_resp_100;
205         } else if (i<300) {
206             resp_grp = st_node_resp_200;
207             resp_str = st_str_resp_200;
208         } else if (i<400) {
209             resp_grp = st_node_resp_300;
210             resp_str = st_str_resp_300;
211         } else if (i<500) {
212             resp_grp = st_node_resp_400;
213             resp_str = st_str_resp_400;
214         } else {
215             resp_grp = st_node_resp_500;
216             resp_str = st_str_resp_500;
217         }
218
219         tick_stat_node(st, resp_str, st_node_responses, FALSE);
220
221         g_snprintf(str, sizeof(str),"%u %s",i,val_to_str(i,rtsp_status_code_vals, "Unknown (%d)"));
222         tick_stat_node(st, str, resp_grp, FALSE);
223     } else if (v->request_method) {
224         stats_tree_tick_pivot(st,st_node_requests,v->request_method);
225     } else {
226         tick_stat_node(st, st_str_other, st_node_packets, FALSE);
227     }
228
229     return 1;
230 }
231 void proto_reg_handoff_rtsp(void);
232
233 /*
234  * desegmentation of RTSP headers
235  * (when we are over TCP or another protocol providing the desegmentation API)
236  */
237 static gboolean rtsp_desegment_headers = TRUE;
238
239 /*
240  * desegmentation of RTSP bodies
241  * (when we are over TCP or another protocol providing the desegmentation API)
242  * TODO let the user filter on content-type the bodies he wants desegmented
243  */
244 static gboolean rtsp_desegment_body = TRUE;
245
246 /* http://www.iana.org/assignments/port-numbers lists two rtsp ports.
247  * In Addition RTSP uses display port over Wi-Fi Display: 7236.
248  */
249 #define RTSP_TCP_PORT_RANGE           "554,8554,7236"
250
251 static range_t *global_rtsp_tcp_port_range = NULL;
252 static range_t *rtsp_tcp_port_range        = NULL;
253 /*
254  * Takes an array of bytes, assumed to contain a null-terminated
255  * string, as an argument, and returns the length of the string -
256  * i.e., the size of the array, minus 1 for the null terminator.
257  */
258 #define STRLEN_CONST(str)   (sizeof (str) - 1)
259
260 #define RTSP_FRAMEHDR   ('$')
261
262 typedef struct {
263     dissector_handle_t      dissector;
264 } rtsp_interleaved_t;
265
266 #define RTSP_MAX_INTERLEAVED        (256)
267
268 /*
269  * Careful about dynamically allocating memory in this structure (say
270  * for dynamically increasing the size of the 'interleaved' array) -
271  * the containing structure is garbage collected and contained
272  * pointers will not be freed.
273  */
274 typedef struct {
275     rtsp_interleaved_t      interleaved[RTSP_MAX_INTERLEAVED];
276 } rtsp_conversation_data_t;
277
278 static int
279 dissect_rtspinterleaved(tvbuff_t *tvb, int offset, packet_info *pinfo,
280     proto_tree *tree)
281 {
282     guint           length_remaining;
283     proto_item     *ti;
284     proto_tree     *rtspframe_tree = NULL;
285     int             orig_offset;
286     guint8          rf_chan;    /* interleaved channel id */
287     guint16         rf_len;     /* packet length */
288     tvbuff_t       *next_tvb;
289     conversation_t *conv;
290     rtsp_conversation_data_t *data;
291     dissector_handle_t        dissector;
292
293     /*
294      * This will throw an exception if we don't have any data left.
295      * That's what we want.  (See "tcp_dissect_pdus()", which is
296      * similar.)
297      */
298     length_remaining = tvb_ensure_length_remaining(tvb, offset);
299
300     /*
301      * Can we do reassembly?
302      */
303     if (rtsp_desegment_headers && pinfo->can_desegment) {
304         /*
305          * Yes - would an RTSP multiplexed header starting at
306          * this offset be split across segment boundaries?
307          */
308         if (length_remaining < 4) {
309             /*
310              * Yes.  Tell the TCP dissector where the data for
311              * this message starts in the data it handed us and
312              * that we need "some more data."  Don't tell it
313              * exactly how many bytes we need because if/when we
314              * ask for even more (after the header) that will
315              * break reassembly.
316              */
317             pinfo->desegment_offset = offset;
318             pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
319             return -1;
320         }
321     }
322
323     /*
324      * Get the "$", channel, and length from the header.
325      */
326     orig_offset = offset;
327     rf_chan = tvb_get_guint8(tvb, offset+1);
328     rf_len = tvb_get_ntohs(tvb, offset+2);
329
330     /*
331      * Can we do reassembly?
332      */
333     if (rtsp_desegment_body && pinfo->can_desegment) {
334         /*
335          * Yes - is the header + encapsulated packet split
336          * across segment boundaries?
337          */
338         if (length_remaining < 4U + rf_len) {
339             /*
340              * Yes.  Tell the TCP dissector where the data
341              * for this message starts in the data it handed
342              * us, and how many more bytes we need, and return.
343              */
344             pinfo->desegment_offset = offset;
345             pinfo->desegment_len = 4U + rf_len - length_remaining;
346             return -1;
347         }
348     }
349
350     col_add_fstr(pinfo->cinfo, COL_INFO,
351             "Interleaved channel 0x%02x, %u bytes",
352             rf_chan, rf_len);
353
354     ti = proto_tree_add_protocol_format(tree, proto_rtsp, tvb,
355         offset, 4,
356         "RTSP Interleaved Frame, Channel: 0x%02x, %u bytes",
357         rf_chan, rf_len);
358     rtspframe_tree = proto_item_add_subtree(ti, ett_rtspframe);
359
360     proto_tree_add_item(rtspframe_tree, hf_rtsp_magic, tvb, offset, 1, ENC_NA);
361
362     offset += 1;
363
364     proto_tree_add_item(rtspframe_tree, hf_rtsp_channel, tvb, offset, 1, ENC_NA);
365
366     offset += 1;
367
368     proto_tree_add_item(rtspframe_tree, hf_rtsp_length, tvb, offset, 2, ENC_BIG_ENDIAN);
369     offset += 2;
370
371     /*
372      * We set the actual length of the tvbuff for the interleaved
373      * stuff to the minimum of what's left in the tvbuff and the
374      * length in the header.
375      *
376      * XXX - what if there's nothing left in the tvbuff?
377      * We'd want a BoundsError exception to be thrown, so
378      * that a Short Frame would be reported.
379      */
380     if (length_remaining > rf_len)
381         length_remaining = rf_len;
382     next_tvb = tvb_new_subset(tvb, offset, length_remaining, rf_len);
383
384     conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
385         pinfo->srcport, pinfo->destport, 0);
386
387     if (conv &&
388         (data = (rtsp_conversation_data_t *)conversation_get_proto_data(conv, proto_rtsp)) &&
389         /* Add the following condition if it is not always true.
390         rf_chan < RTSP_MAX_INTERLEAVED &&
391         */
392         (dissector = data->interleaved[rf_chan].dissector)) {
393         call_dissector(dissector, next_tvb, pinfo, tree);
394     } else {
395         proto_tree_add_text(rtspframe_tree, tvb, offset, rf_len,
396             "Data (%u bytes)", rf_len);
397     }
398
399     offset += rf_len;
400
401     return offset - orig_offset;
402 }
403
404 static void process_rtsp_request(tvbuff_t *tvb, int offset, const guchar *data,
405                                  size_t linelen, size_t next_line_offset,
406                                  proto_tree *tree);
407
408 static void process_rtsp_reply(tvbuff_t *tvb, int offset, const guchar *data,
409                                size_t linelen, size_t next_line_offset,
410                                proto_tree *tree);
411
412 typedef enum {
413     RTSP_REQUEST,
414     RTSP_REPLY,
415     RTSP_NOT_FIRST_LINE
416 } rtsp_type_t;
417
418 static const char *rtsp_methods[] = {
419     "DESCRIBE",
420     "ANNOUNCE",
421     "GET_PARAMETER",
422     "OPTIONS",
423     "PAUSE",
424     "PLAY",
425     "RECORD",
426     "REDIRECT",
427     "SETUP",
428     "SET_PARAMETER",
429     "TEARDOWN"
430 };
431
432 #define RTSP_NMETHODS   array_length(rtsp_methods)
433
434 static gboolean
435 is_rtsp_request_or_reply(const guchar *line, size_t linelen, rtsp_type_t *type)
436 {
437     guint         ii;
438     const guchar *next_token;
439     int           tokenlen;
440     gchar         response_chars[4];
441
442     /* Is this an RTSP reply? */
443     if (linelen >= 5 && g_ascii_strncasecmp("RTSP/", line, 5) == 0) {
444         /*
445          * Yes.
446          */
447         *type = RTSP_REPLY;
448         /* The first token is the version. */
449         tokenlen = get_token_len(line, line+5, &next_token);
450         if (tokenlen != 0) {
451             /* The next token is the status code. */
452             tokenlen = get_token_len(next_token, line+linelen, &next_token);
453             if (tokenlen >= 3) {
454                 memcpy(response_chars, next_token, 3);
455                 response_chars[3] = '\0';
456                 rtsp_stat_info->response_code = (guint)strtoul(response_chars, NULL, 10);
457             }
458         }
459         return TRUE;
460     }
461
462     /*
463      * Is this an RTSP request?
464      * Check whether the line begins with one of the RTSP request
465      * methods.
466      */
467     for (ii = 0; ii < RTSP_NMETHODS; ii++) {
468         size_t len = strlen(rtsp_methods[ii]);
469         if (linelen >= len &&
470             g_ascii_strncasecmp(rtsp_methods[ii], line, len) == 0 &&
471             (len == linelen || isspace(line[len])))
472         {
473             *type = RTSP_REQUEST;
474             rtsp_stat_info->request_method =
475                wmem_strndup(wmem_packet_scope(), rtsp_methods[ii], len+1);
476             return TRUE;
477         }
478     }
479
480     /* Wasn't a request or a response */
481     *type = RTSP_NOT_FIRST_LINE;
482     return FALSE;
483 }
484
485 static const char rtsp_content_type[]      = "Content-Type:";
486 static const char rtsp_transport[]         = "Transport:";
487 static const char rtsp_sps[]               = "server_port=";
488 static const char rtsp_cps[]               = "client_port=";
489 static const char rtsp_rtp[]               = "rtp/";
490 static const char rtsp_rdt_feature_level[] = "RDTFeatureLevel";
491 static const char rtsp_real_rdt[]          = "x-real-rdt/";
492 static const char rtsp_real_tng[]          = "x-pn-tng/"; /* synonym for x-real-rdt */
493 static const char rtsp_inter[]             = "interleaved=";
494
495 static void
496 rtsp_create_conversation(packet_info *pinfo, const guchar *line_begin,
497                          size_t line_len, gint rdt_feature_level)
498 {
499     conversation_t  *conv;
500     guchar    buf[256];
501     guchar   *tmp;
502     gboolean  rtp_transport = FALSE;
503     gboolean  rdt_transport = FALSE;
504     guint     c_data_port, c_mon_port;
505     guint     s_data_port, s_mon_port;
506     gboolean  is_video      = FALSE; /* FIX ME - need to indicate video or not */
507
508     /* Copy line into buf */
509     if (line_len > sizeof(buf) - 1)
510     {
511         /* Don't overflow the buffer. */
512         line_len = sizeof(buf) - 1;
513     }
514     memcpy(buf, line_begin, line_len);
515     buf[line_len] = '\0';
516
517     /* Get past "Transport:" and spaces */
518     tmp = buf + STRLEN_CONST(rtsp_transport);
519     while (*tmp && isspace(*tmp))
520         tmp++;
521
522     /* Work out which transport type is here */
523     if (g_ascii_strncasecmp(tmp, rtsp_rtp, strlen(rtsp_rtp)) == 0)
524         rtp_transport = TRUE;
525     else
526     if (g_ascii_strncasecmp(tmp, rtsp_real_rdt, strlen(rtsp_real_rdt)) == 0 ||
527         g_ascii_strncasecmp(tmp, rtsp_real_tng, strlen(rtsp_real_tng)) == 0)
528         rdt_transport = TRUE;
529     else
530     {
531         /* Give up on unknown transport types */
532         return;
533     }
534
535     c_data_port = c_mon_port = 0;
536     s_data_port = s_mon_port = 0;
537
538     /* Look for server port */
539     if ((tmp = strstr(buf, rtsp_sps))) {
540         tmp += strlen(rtsp_sps);
541         if (sscanf(tmp, "%u-%u", &s_data_port, &s_mon_port) < 1) {
542             g_warning("Frame %u: rtsp: bad server_port",
543                 pinfo->fd->num);
544             return;
545         }
546     }
547     /* Look for client port */
548     if ((tmp = strstr(buf, rtsp_cps))) {
549         tmp += strlen(rtsp_cps);
550         if (sscanf(tmp, "%u-%u", &c_data_port, &c_mon_port) < 1) {
551             g_warning("Frame %u: rtsp: bad client_port",
552                 pinfo->fd->num);
553             return;
554         }
555     }
556
557
558     /* Deal with RTSP TCP-interleaved conversations. */
559     if (!c_data_port) {
560         rtsp_conversation_data_t    *data;
561         guint               s_data_chan, s_mon_chan;
562         int             i;
563
564         /* Search tranport line for interleaved string */
565         if ((tmp = strstr(buf, rtsp_inter)) == NULL) {
566             /*
567              * No interleaved or server_port - probably a
568              * SETUP request, rather than reply.
569              */
570             return;
571         }
572
573         /* Move tmp to beyone interleaved string */
574         tmp += strlen(rtsp_inter);
575         /* Look for channel number(s) */
576         i = sscanf(tmp, "%u-%u", &s_data_chan, &s_mon_chan);
577         if (i < 1)
578         {
579             g_warning("Frame %u: rtsp: bad interleaved", pinfo->fd->num);
580             return;
581         }
582
583         /* At least data channel present, look for conversation (presumably TCP) */
584         conv = find_or_create_conversation(pinfo);
585
586         /* Look for previous data */
587         data = (rtsp_conversation_data_t *)conversation_get_proto_data(conv, proto_rtsp);
588
589         /* Create new data if necessary */
590         if (!data)
591         {
592             data = wmem_new0(wmem_file_scope(), rtsp_conversation_data_t);
593             conversation_add_proto_data(conv, proto_rtsp, data);
594         }
595
596         /* Now set the dissector handle of the interleaved channel
597            according to the transport protocol used */
598         if (rtp_transport)
599         {
600             if (s_data_chan < RTSP_MAX_INTERLEAVED) {
601                 data->interleaved[s_data_chan].dissector =
602                     rtp_handle;
603             }
604             if (i > 1 && s_mon_chan < RTSP_MAX_INTERLEAVED) {
605                 data->interleaved[s_mon_chan].dissector =
606                     rtcp_handle;
607             }
608         }
609         else if (rdt_transport)
610         {
611             if (s_data_chan < RTSP_MAX_INTERLEAVED) {
612                 data->interleaved[s_data_chan].dissector =
613                     rdt_handle;
614             }
615         }
616         return;
617     }
618
619     /*
620      * We only want to match on the destination address, not the
621      * source address, because the server might send back a packet
622      * from an address other than the address to which its client
623      * sent the packet, so we construct a conversation with no
624      * second address.
625      */
626     if (rtp_transport)
627     {
628         /* There is always data for RTP */
629         rtp_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port,
630                         "RTSP", pinfo->fd->num, is_video, NULL);
631
632         /* RTCP only if indicated */
633         if (c_mon_port)
634         {
635             rtcp_add_address(pinfo, &pinfo->dst, c_mon_port, s_mon_port,
636                              "RTSP", pinfo->fd->num);
637         }
638     }
639     else
640     if (rdt_transport)
641     {
642         /* Real Data Transport */
643         rdt_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port,
644                         "RTSP", rdt_feature_level);
645     }
646 }
647
648 static const char rtsp_content_length[] = "Content-Length:";
649
650 static int
651 rtsp_get_content_length(const guchar *line_begin, size_t line_len)
652 {
653     guchar  buf[256];
654     guchar *tmp;
655     long    content_length;
656     char   *p;
657     guchar *up;
658
659     if (line_len > sizeof(buf) - 1) {
660         /*
661          * Don't overflow the buffer.
662          */
663         line_len = sizeof(buf) - 1;
664     }
665     memcpy(buf, line_begin, line_len);
666     buf[line_len] = '\0';
667
668     tmp = buf + STRLEN_CONST(rtsp_content_length);
669     while (*tmp && isspace(*tmp))
670         tmp++;
671     content_length = strtol(tmp, &p, 10);
672     up = p;
673     if (up == tmp || (*up != '\0' && !isspace(*up)))
674         return -1;  /* not a valid number */
675     return (int)content_length;
676 }
677
678 static const char rtsp_Session[] = "Session:";
679 static const char rtsp_X_Vig_Msisdn[] = "X-Vig-Msisdn";
680
681 static int
682 dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo,
683     proto_tree *tree)
684 {
685     proto_tree   *rtsp_tree = NULL;
686     proto_tree   *sub_tree  = NULL;
687     proto_item   *ti        = NULL;
688     const guchar *line;
689     gint          next_offset;
690     const guchar *linep, *lineend;
691     int           orig_offset;
692     int           first_linelen, linelen;
693     int           line_end_offset;
694     int           colon_offset;
695     gboolean      is_request_or_reply;
696     gboolean      body_requires_content_len;
697     gboolean      saw_req_resp_or_header;
698     guchar        c;
699     rtsp_type_t   rtsp_type;
700     gboolean      is_header;
701     int           datalen;
702     int           content_length;
703     int           reported_datalen;
704     int           value_offset;
705     int           value_len;
706     e164_info_t   e164_info;
707     gint          rdt_feature_level = 0;
708     gchar        *media_type_str_lower_case = NULL;
709     int           semi_colon_offset;
710     int           par_end_offset;
711     gchar        *frame_label = NULL;
712     gchar        *session_id  = NULL;
713     voip_packet_info_t *stat_info = NULL;
714
715     rtsp_stat_info = wmem_new(wmem_packet_scope(), rtsp_info_value_t);
716     rtsp_stat_info->framenum = pinfo->fd->num;
717     rtsp_stat_info->response_code = 0;
718     rtsp_stat_info->request_method = NULL;
719     rtsp_stat_info->request_uri = NULL;
720     rtsp_stat_info->rtsp_host = NULL;
721
722     /*
723      * Is this a request or response?
724      *
725      * Note that "tvb_find_line_end()" will return a value that
726      * is not longer than what's in the buffer, so the
727      * "tvb_get_ptr()" call won't throw an exception.
728      */
729     first_linelen = tvb_find_line_end(tvb, offset,
730         tvb_ensure_length_remaining(tvb, offset), &next_offset,
731         FALSE);
732
733     /*
734      * Is the first line a request or response?
735      */
736     line = tvb_get_ptr(tvb, offset, first_linelen);
737     is_request_or_reply = is_rtsp_request_or_reply(line, first_linelen,
738         &rtsp_type);
739     if (is_request_or_reply) {
740         /*
741          * Yes, it's a request or response.
742          * Do header desegmentation if we've been told to,
743          * and do body desegmentation if we've been told to and
744          * we find a Content-Length header.
745          */
746         if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
747             rtsp_desegment_headers, rtsp_desegment_body)) {
748             /*
749              * More data needed for desegmentation.
750              */
751             return -1;
752         }
753     }
754
755     /*
756      * RFC 2326 says that a content length must be specified
757      * in requests that have a body, although section 4.4 speaks
758      * of a server closing the connection indicating the end of
759      * a reply body.
760      *
761      * We assume that an absent content length in a request means
762      * that we don't have a body, and that an absent content length
763      * in a reply means that the reply body runs to the end of
764      * the connection.  If the first line is neither, we assume
765      * that whatever follows a blank line should be treated as a
766      * body; there's not much else we can do, as we're jumping
767      * into the message in the middle.
768      *
769      * XXX - if there was no Content-Length entity header, we should
770      * accumulate all data until the end of the connection.
771      * That'd require that the TCP dissector call subdissectors
772      * for all frames with FIN, even if they contain no data,
773      * which would require subdissectors to deal intelligently
774      * with empty segments.
775      */
776     if (rtsp_type == RTSP_REQUEST)
777         body_requires_content_len = TRUE;
778     else
779         body_requires_content_len = FALSE;
780
781     line = tvb_get_ptr(tvb, offset, first_linelen);
782     if (is_request_or_reply) {
783         if ( rtsp_type == RTSP_REPLY ) {
784             frame_label = wmem_strdup_printf(wmem_packet_scope(),
785                   "Reply: %s", format_text(line, first_linelen));
786         }
787         else {
788             frame_label = wmem_strdup(wmem_packet_scope(),
789                   format_text(line, first_linelen));
790         }
791     }
792
793     col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTSP");
794     /*
795         * Put the first line from the buffer into the summary
796         * if it's an RTSP request or reply (but leave out the
797         * line terminator).
798         * Otherwise, just call it a continuation.
799         *
800         * Note that "tvb_find_line_end()" will return a value that
801         * is not longer than what's in the buffer, so the
802         * "tvb_get_ptr()" call won't throw an exception.
803         */
804     if (is_request_or_reply)
805         if ( rtsp_type == RTSP_REPLY ) {
806             col_set_str(pinfo->cinfo, COL_INFO, "Reply: ");
807             col_append_str(pinfo->cinfo, COL_INFO,
808                 format_text(line, first_linelen));
809         }
810         else {
811             col_add_str(pinfo->cinfo, COL_INFO,
812                 format_text(line, first_linelen));
813         }
814
815     else
816         col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
817
818     orig_offset = offset;
819     if (tree) {
820         ti = proto_tree_add_item(tree, proto_rtsp, tvb, offset, -1,
821             ENC_NA);
822         rtsp_tree = proto_item_add_subtree(ti, ett_rtsp);
823     }
824
825     /*
826      * We haven't yet seen a Content-Length header.
827      */
828     content_length = -1;
829
830     /*
831      * Process the packet data, a line at a time.
832      */
833     saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
834     while (tvb_reported_length_remaining(tvb, offset) != 0) {
835         /*
836          * We haven't yet concluded that this is a header.
837          */
838         is_header = FALSE;
839
840         /*
841          * Find the end of the line.
842          */
843         linelen = tvb_find_line_end(tvb, offset,
844             tvb_ensure_length_remaining(tvb, offset), &next_offset,
845             FALSE);
846         if (linelen < 0)
847             return -1;
848         line_end_offset = offset + linelen;
849         /*
850          * colon_offset may be -1
851          */
852         colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
853
854
855         /*
856          * Get a buffer that refers to the line.
857          */
858         line = tvb_get_ptr(tvb, offset, linelen);
859         lineend = line + linelen;
860
861         /*
862          * OK, does it look like an RTSP request or response?
863          */
864         is_request_or_reply = is_rtsp_request_or_reply(line, linelen, &rtsp_type);
865         if (is_request_or_reply)
866             goto is_rtsp;
867
868         /*
869          * No.  Does it look like a blank line (as would appear
870          * at the end of an RTSP request)?
871          */
872         if (linelen == 0)
873             goto is_rtsp;   /* Yes. */
874
875         /*
876          * No.  Does it look like a header?
877          */
878         linep = line;
879         while (linep < lineend) {
880             c = *linep++;
881
882             /*
883              * This must be a CHAR to be part of a token; that
884              * means it must be ASCII.
885              */
886             if (!isascii(c))
887                 break;  /* not ASCII, thus not a CHAR */
888
889             /*
890              * This mustn't be a CTL to be part of a token.
891              *
892              * XXX - what about leading LWS on continuation
893              * lines of a header?
894              */
895             if (iscntrl(c))
896                 break;  /* CTL, not part of a header */
897
898             switch (c) {
899
900             case '(':
901             case ')':
902             case '<':
903             case '>':
904             case '@':
905             case ',':
906             case ';':
907             case '\\':
908             case '"':
909             case '/':
910             case '[':
911             case ']':
912             case '?':
913             case '=':
914             case '{':
915             case '}':
916                 /*
917                  * It's a tspecial, so it's not
918                  * part of a token, so it's not
919                  * a field name for the beginning
920                  * of a header.
921                  */
922                 goto not_rtsp;
923
924             case ':':
925                 /*
926                  * This ends the token; we consider
927                  * this to be a header.
928                  */
929                 is_header = TRUE;
930                 goto is_rtsp;
931
932             case ' ':
933             case '\t':
934                 /*
935                  * LWS (RFC-2616, 4.2); continue the previous
936                  * header.
937                  */
938                 goto is_rtsp;
939             }
940         }
941
942         /*
943          * We haven't seen the colon, but everything else looks
944          * OK for a header line.
945          *
946          * If we've already seen an RTSP request or response
947          * line, or a header line, and we're at the end of
948          * the tvbuff, we assume this is an incomplete header
949          * line.  (We quit this loop after seeing a blank line,
950          * so if we've seen a request or response line, or a
951          * header line, this is probably more of the request
952          * or response we're presumably seeing.  There is some
953          * risk of false positives, but the same applies for
954          * full request or response lines or header lines,
955          * although that's less likely.)
956          *
957          * We throw an exception in that case, by checking for
958          * the existence of the next byte after the last one
959          * in the line.  If it exists, "tvb_ensure_bytes_exist()"
960          * throws no exception, and we fall through to the
961          * "not RTSP" case.  If it doesn't exist,
962          * "tvb_ensure_bytes_exist()" will throw the appropriate
963          * exception.
964          */
965         if (saw_req_resp_or_header)
966             tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
967
968     not_rtsp:
969         /*
970          * We don't consider this part of an RTSP request or
971          * reply, so we don't display it.
972          */
973         break;
974
975     is_rtsp:
976         /*
977          * Process this line.
978          */
979         if (linelen == 0) {
980             /*
981              * This is a blank line, which means that
982              * whatever follows it isn't part of this
983              * request or reply.
984              */
985             proto_tree_add_format_text(rtsp_tree, tvb, offset, next_offset - offset);
986             offset = next_offset;
987             break;
988         }
989
990         /*
991          * Not a blank line - either a request, a reply, or a header
992          * line.
993          */
994         saw_req_resp_or_header = TRUE;
995         if (rtsp_tree) {
996
997             switch (rtsp_type)
998             {
999                 case RTSP_REQUEST:
1000                     process_rtsp_request(tvb, offset, line, linelen, next_offset, rtsp_tree);
1001                     break;
1002
1003                 case RTSP_REPLY:
1004                     process_rtsp_reply(tvb, offset, line, linelen, next_offset, rtsp_tree);
1005                     break;
1006
1007                 case RTSP_NOT_FIRST_LINE:
1008                     /* Drop through, it may well be a header line */
1009                     break;
1010             }
1011         }
1012
1013         if (is_header)
1014         {
1015             /* We know that colon_offset must be set */
1016
1017             /* Skip whitespace after the colon. */
1018             value_offset = colon_offset + 1;
1019             while ((value_offset < line_end_offset) &&
1020                    ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t'))
1021             {
1022                 value_offset++;
1023             }
1024             value_len = line_end_offset - value_offset;
1025
1026             /*
1027              * Process some headers specially.
1028              */
1029 #define HDR_MATCHES(header) \
1030     ( (size_t)linelen > STRLEN_CONST(header) && \
1031      g_ascii_strncasecmp(line, (header), STRLEN_CONST(header)) == 0)
1032
1033             if (HDR_MATCHES(rtsp_transport))
1034             {
1035                 proto_tree_add_string(rtsp_tree, hf_rtsp_transport, tvb,
1036                                       offset, linelen,
1037                                       tvb_format_text(tvb, value_offset,
1038                                                       value_len));
1039
1040                 /*
1041                  * Based on the port numbers specified
1042                  * in the Transport: header, set up
1043                  * a conversation that will be dissected
1044                  * with the appropriate dissector.
1045                  */
1046                 rtsp_create_conversation(pinfo, line, linelen, rdt_feature_level);
1047             } else if (HDR_MATCHES(rtsp_content_type))
1048             {
1049                 proto_tree_add_string(rtsp_tree, hf_rtsp_content_type,
1050                                       tvb, offset, linelen,
1051                                       tvb_format_text(tvb, value_offset,
1052                                                       value_len));
1053
1054                 offset = offset + (int)STRLEN_CONST(rtsp_content_type);
1055                 /* Skip wsp */
1056                 offset = tvb_skip_wsp(tvb, offset, value_len);
1057                 semi_colon_offset = tvb_find_guint8(tvb, value_offset, value_len, ';');
1058                 if ( semi_colon_offset != -1) {
1059                     /* m-parameter present */
1060                     par_end_offset = tvb_skip_wsp_return(tvb, semi_colon_offset-1);
1061                     value_len = par_end_offset - offset;
1062                 }
1063
1064                 media_type_str_lower_case = ascii_strdown_inplace(
1065                     (gchar *)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, value_len, ENC_ASCII));
1066
1067             } else if (HDR_MATCHES(rtsp_content_length))
1068             {
1069                 proto_tree_add_uint(rtsp_tree, hf_rtsp_content_length,
1070                                     tvb, offset, linelen,
1071                                     atoi(tvb_format_text(tvb, value_offset,
1072                                                          value_len)));
1073
1074                 /*
1075                  * Only the amount specified by the
1076                  * Content-Length: header should be treated
1077                  * as payload.
1078                  */
1079                 content_length = rtsp_get_content_length(line, linelen);
1080
1081             } else if (HDR_MATCHES(rtsp_Session))
1082             {
1083                 session_id = tvb_format_text(tvb, value_offset, value_len);
1084                 /* Put the value into the protocol tree */
1085                 proto_tree_add_string(rtsp_tree, hf_rtsp_session, tvb,
1086                                       offset, linelen,
1087                                       session_id);
1088
1089             } else if (HDR_MATCHES(rtsp_X_Vig_Msisdn)) {
1090                 /*
1091                  * Extract the X_Vig_Msisdn string
1092                  */
1093                 if (colon_offset != -1)
1094                 {
1095                     /* Put the value into the protocol tree */
1096                     ti = proto_tree_add_string(rtsp_tree, hf_rtsp_X_Vig_Msisdn,tvb,
1097                                                offset, linelen ,
1098                                                tvb_format_text(tvb, value_offset, value_len));
1099                     sub_tree = proto_item_add_subtree(ti, ett_rtsp_method);
1100
1101                     e164_info.e164_number_type = CALLING_PARTY_NUMBER;
1102                     e164_info.nature_of_address = 0;
1103
1104                     e164_info.E164_number_str = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset,
1105                                                                   value_len, ENC_ASCII);
1106                     e164_info.E164_number_length = value_len;
1107                     dissect_e164_number(tvb, sub_tree, value_offset,
1108                                         value_len, e164_info);
1109                 }
1110             } else if (HDR_MATCHES(rtsp_rdt_feature_level))
1111             {
1112                 rdt_feature_level = atoi(tvb_format_text(tvb, value_offset,
1113                                                          value_len));
1114                 proto_tree_add_uint(rtsp_tree, hf_rtsp_rdtfeaturelevel,
1115                                     tvb, offset, linelen,
1116                                     atoi(tvb_format_text(tvb, value_offset,
1117                                                          value_len)));
1118             }
1119             else
1120             {
1121                 /* Default case for headers. Show line as text */
1122                 proto_tree_add_format_text(rtsp_tree, tvb, offset, next_offset - offset);
1123             }
1124         }
1125         else if (rtsp_type == RTSP_NOT_FIRST_LINE)
1126         {
1127             /* Catch-all for all other lines... Show line as text.
1128                TODO: should these be shown as errors? */
1129             proto_tree_add_format_text(rtsp_tree, tvb, offset, next_offset - offset);
1130         }
1131
1132         offset = next_offset;
1133     }
1134
1135     if (session_id) {
1136         stat_info = wmem_new0(wmem_packet_scope(), voip_packet_info_t);
1137         stat_info->protocol_name = wmem_strdup(wmem_packet_scope(), "RTSP");
1138         stat_info->call_id = session_id;
1139         stat_info->frame_label = frame_label;
1140         stat_info->call_state = VOIP_CALL_SETUP;
1141         stat_info->call_active_state = VOIP_ACTIVE;
1142         stat_info->frame_comment = frame_label;
1143         tap_queue_packet(voip_tap, pinfo, stat_info);
1144     }
1145
1146     /*
1147      * Have now read all of the lines of this message.
1148      *
1149      * If a content length was supplied, the amount of data to be
1150      * processed as RTSP payload is the minimum of the content
1151      * length and the amount of data remaining in the frame.
1152      *
1153      * If no content length was supplied (or if a bad content length
1154      * was supplied), the amount of data to be processed is the amount
1155      * of data remaining in the frame.
1156      */
1157     datalen = tvb_length_remaining(tvb, offset);
1158     reported_datalen = tvb_reported_length_remaining(tvb, offset);
1159     if (content_length != -1) {
1160         /*
1161          * Content length specified; display only that amount
1162          * as payload.
1163          */
1164         if (datalen > content_length)
1165             datalen = content_length;
1166
1167         /*
1168          * XXX - limit the reported length in the tvbuff we'll
1169          * hand to a subdissector to be no greater than the
1170          * content length.
1171          *
1172          * We really need both unreassembled and "how long it'd
1173          * be if it were reassembled" lengths for tvbuffs, so
1174          * that we throw the appropriate exceptions for
1175          * "not enough data captured" (running past the length),
1176          * "packet needed reassembly" (within the length but
1177          * running past the unreassembled length), and
1178          * "packet is malformed" (running past the reassembled
1179          * length).
1180          */
1181         if (reported_datalen > content_length)
1182             reported_datalen = content_length;
1183     } else {
1184         /*
1185          * No content length specified; if this message doesn't
1186          * have a body if no content length is specified, process
1187          * nothing as payload.
1188          */
1189         if (body_requires_content_len)
1190             datalen = 0;
1191     }
1192
1193     if (datalen > 0) {
1194         /*
1195          * There's stuff left over; process it.
1196          */
1197         tvbuff_t *new_tvb;
1198
1199         /*
1200          * Now create a tvbuff for the Content-type stuff and
1201          * dissect it.
1202          *
1203          * The amount of data to be processed that's
1204          * available in the tvbuff is "datalen", which
1205          * is the minimum of the amount of data left in
1206          * the tvbuff and any specified content length.
1207          *
1208          * The amount of data to be processed that's in
1209          * this frame, regardless of whether it was
1210          * captured or not, is "reported_datalen",
1211          * which, if no content length was specified,
1212          * is -1, i.e. "to the end of the frame.
1213          */
1214         new_tvb = tvb_new_subset(tvb, offset, datalen,
1215                 reported_datalen);
1216
1217         if (media_type_str_lower_case &&
1218             dissector_try_string(media_type_dissector_table,
1219                 media_type_str_lower_case,
1220                 new_tvb, pinfo, rtsp_tree, NULL)){
1221
1222         }else {
1223             /*
1224              * Fix up the top-level item so that it doesn't
1225              * include the SDP stuff.
1226              */
1227             if (ti != NULL)
1228                 proto_item_set_len(ti, offset);
1229
1230             if (tvb_get_guint8(tvb, offset) == RTSP_FRAMEHDR) {
1231                 /*
1232                  * This is interleaved stuff; don't
1233                  * treat it as raw data - set "datalen"
1234                  * to 0, so we won't skip the offset
1235                  * past it, which will cause our
1236                  * caller to process that stuff itself.
1237                  */
1238                 datalen = 0;
1239             } else {
1240                 proto_tree_add_text(rtsp_tree, tvb, offset,
1241                     datalen, "Data (%d bytes)",
1242                     reported_datalen);
1243             }
1244         }
1245
1246         /*
1247          * We've processed "datalen" bytes worth of data
1248          * (which may be no data at all); advance the
1249          * offset past whatever data we've processed.
1250          */
1251         offset += datalen;
1252     }
1253
1254     tap_queue_packet(rtsp_tap, pinfo, rtsp_stat_info);
1255
1256     return offset - orig_offset;
1257 }
1258
1259 static void
1260 process_rtsp_request(tvbuff_t *tvb, int offset, const guchar *data,
1261                      size_t linelen, size_t next_line_offset, proto_tree *tree)
1262 {
1263     proto_tree   *sub_tree;
1264     proto_item   *ti;
1265     const guchar *lineend  = data + linelen;
1266     guint        ii;
1267     const guchar *url;
1268     const guchar *url_start;
1269     guchar       *tmp_url;
1270
1271     /* Request Methods */
1272     for (ii = 0; ii < RTSP_NMETHODS; ii++) {
1273         size_t len = strlen(rtsp_methods[ii]);
1274         if (linelen >= len &&
1275             g_ascii_strncasecmp(rtsp_methods[ii], data, len) == 0 &&
1276             (len == linelen || isspace(data[len])))
1277             break;
1278     }
1279     if (ii == RTSP_NMETHODS) {
1280         /*
1281          * We got here because "is_rtsp_request_or_reply()" returned
1282          * RTSP_REQUEST, so we know one of the request methods
1283          * matched, so we "can't get here".
1284          */
1285         DISSECTOR_ASSERT_NOT_REACHED();
1286     }
1287
1288     /* Add a tree for this request */
1289     ti = proto_tree_add_string(tree, hf_rtsp_request, tvb, offset,
1290                               (gint) (next_line_offset - offset),
1291                               tvb_format_text(tvb, offset, (gint) (next_line_offset - offset)));
1292     sub_tree = proto_item_add_subtree(ti, ett_rtsp_method);
1293
1294
1295     /* Add method name to tree */
1296     proto_tree_add_string(sub_tree, hf_rtsp_method, tvb, offset,
1297                           (gint) strlen(rtsp_methods[ii]), rtsp_methods[ii]);
1298
1299     /* URL */
1300     url = data;
1301     /* Skip method name again */
1302     while (url < lineend && !isspace(*url))
1303         url++;
1304     /* Skip spaces */
1305     while (url < lineend && isspace(*url))
1306         url++;
1307     /* URL starts here */
1308     url_start = url;
1309     /* Scan to end of URL */
1310     while (url < lineend && !isspace(*url))
1311         url++;
1312     /* Create a URL-sized buffer and copy contents */
1313     tmp_url = wmem_strndup(wmem_packet_scope(), url_start, url - url_start);
1314
1315     /* Add URL to tree */
1316     proto_tree_add_string(sub_tree, hf_rtsp_url, tvb,
1317                           offset + (gint) (url_start - data), (gint) (url - url_start), tmp_url);
1318 }
1319
1320 /* Read first line of a reply message */
1321 static void
1322 process_rtsp_reply(tvbuff_t *tvb, int offset, const guchar *data,
1323     size_t linelen, size_t next_line_offset, proto_tree *tree)
1324 {
1325     proto_tree   *sub_tree;
1326     proto_item   *ti;
1327     const guchar *lineend  = data + linelen;
1328     const guchar *status   = data;
1329     const guchar *status_start;
1330     guint         status_i;
1331
1332     /* Add a tree for this request */
1333     ti = proto_tree_add_string(tree, hf_rtsp_response, tvb, offset,
1334                                (gint) (next_line_offset - offset),
1335                                tvb_format_text(tvb, offset, (gint) (next_line_offset - offset)));
1336     sub_tree = proto_item_add_subtree(ti, ett_rtsp_method);
1337
1338
1339     /* status code */
1340
1341     /* Skip protocol/version */
1342     while (status < lineend && !isspace(*status))
1343         status++;
1344     /* Skip spaces */
1345     while (status < lineend && isspace(*status))
1346         status++;
1347
1348     /* Actual code number now */
1349     status_start = status;
1350     status_i = 0;
1351     while (status < lineend && isdigit(*status))
1352         status_i = status_i * 10 + *status++ - '0';
1353
1354     /* Add field to tree */
1355     proto_tree_add_uint(sub_tree, hf_rtsp_status, tvb,
1356                         offset + (gint) (status_start - data),
1357                         (gint) (status - status_start), status_i);
1358 }
1359
1360 static void
1361 dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1362 {
1363     int offset = 0;
1364     int len;
1365
1366     while (tvb_reported_length_remaining(tvb, offset) != 0) {
1367         len = (tvb_get_guint8(tvb, offset) == RTSP_FRAMEHDR)
1368             ? dissect_rtspinterleaved(tvb, offset, pinfo, tree)
1369             : dissect_rtspmessage(tvb, offset, pinfo, tree);
1370         if (len == -1)
1371             break;
1372         offset += len;
1373
1374         /*
1375          * OK, we've set the Protocol and Info columns for the
1376          * first RTSP message; make the columns non-writable,
1377          * so that we don't change it for subsequent RTSP messages.
1378          */
1379         col_set_writable(pinfo->cinfo, FALSE);
1380     }
1381 }
1382
1383 void
1384 proto_register_rtsp(void)
1385 {
1386     static gint *ett[] = {
1387         &ett_rtspframe,
1388         &ett_rtsp,
1389         &ett_rtsp_method,
1390     };
1391     static hf_register_info hf[] = {
1392         { &hf_rtsp_request,
1393             { "Request", "rtsp.request", FT_STRING, BASE_NONE, NULL, 0,
1394             NULL, HFILL }},
1395         { &hf_rtsp_response,
1396             { "Response", "rtsp.response", FT_STRING, BASE_NONE, NULL, 0,
1397             NULL, HFILL }},
1398         { &hf_rtsp_method,
1399             { "Method", "rtsp.method", FT_STRING, BASE_NONE, NULL, 0,
1400             NULL, HFILL }},
1401         { &hf_rtsp_content_type,
1402             { "Content-type", "rtsp.content-type", FT_STRING, BASE_NONE, NULL, 0,
1403             NULL, HFILL }},
1404         { &hf_rtsp_content_length,
1405             { "Content-length", "rtsp.content-length", FT_UINT32, BASE_DEC, NULL, 0,
1406             NULL, HFILL }},
1407         { &hf_rtsp_url,
1408             { "URL", "rtsp.url", FT_STRING, BASE_NONE, NULL, 0,
1409             NULL, HFILL }},
1410         { &hf_rtsp_status,
1411             { "Status", "rtsp.status", FT_UINT32, BASE_DEC, NULL, 0,
1412             NULL, HFILL }},
1413         { &hf_rtsp_session,
1414             { "Session", "rtsp.session", FT_STRING, BASE_NONE, NULL, 0,
1415             NULL, HFILL }},
1416         { &hf_rtsp_transport,
1417             { "Transport", "rtsp.transport", FT_STRING, BASE_NONE, NULL, 0,
1418             NULL, HFILL }},
1419         { &hf_rtsp_rdtfeaturelevel,
1420             { "RDTFeatureLevel", "rtsp.rdt-feature-level", FT_UINT32, BASE_DEC, NULL, 0,
1421             NULL, HFILL }},
1422         { &hf_rtsp_X_Vig_Msisdn,
1423             { "X-Vig-Msisdn", "rtsp.X_Vig_Msisdn", FT_STRING, BASE_NONE, NULL, 0,
1424             NULL, HFILL }},
1425         { &hf_rtsp_magic,
1426             { "Magic", "rtsp.magic", FT_UINT8, BASE_HEX, NULL, 0x0,
1427             NULL, HFILL }},
1428         { &hf_rtsp_channel,
1429             { "Channel", "rtsp.channel", FT_UINT8, BASE_HEX, NULL, 0x0,
1430             NULL, HFILL }},
1431         { &hf_rtsp_length,
1432             { "Length", "rtsp.length", FT_UINT16, BASE_DEC, NULL, 0x0,
1433             NULL, HFILL }},
1434     };
1435     module_t *rtsp_module;
1436
1437     proto_rtsp = proto_register_protocol("Real Time Streaming Protocol",
1438         "RTSP", "rtsp");
1439
1440     proto_register_field_array(proto_rtsp, hf, array_length(hf));
1441     proto_register_subtree_array(ett, array_length(ett));
1442
1443     /* Make this dissector findable by name */
1444     register_dissector("rtsp", dissect_rtsp, proto_rtsp);
1445
1446     /* Register our configuration options, particularly our ports */
1447
1448     rtsp_module = prefs_register_protocol(proto_rtsp, proto_reg_handoff_rtsp);
1449
1450     prefs_register_obsolete_preference(rtsp_module, "tcp.alternate_port");
1451     prefs_register_obsolete_preference(rtsp_module, "tcp.port");
1452
1453     range_convert_str(&global_rtsp_tcp_port_range, RTSP_TCP_PORT_RANGE, 65535);
1454     rtsp_tcp_port_range = range_empty();
1455     prefs_register_range_preference(rtsp_module, "tcp.port_range", "RTSP TCP Ports",
1456                                     "RTSP TCP Ports range",
1457                                     &global_rtsp_tcp_port_range, 65535);
1458     prefs_register_bool_preference(rtsp_module, "desegment_headers",
1459         "Reassemble RTSP headers spanning multiple TCP segments",
1460         "Whether the RTSP dissector should reassemble headers "
1461         "of a request spanning multiple TCP segments. "
1462         " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1463         &rtsp_desegment_headers);
1464     prefs_register_bool_preference(rtsp_module, "desegment_body",
1465         "Trust the \"Content-length:\" header and\ndesegment RTSP "
1466         "bodies\nspanning multiple TCP segments",
1467         "Whether the RTSP dissector should use the "
1468         "\"Content-length:\" value to desegment the body "
1469         "of a request spanning multiple TCP segments",
1470         &rtsp_desegment_body);
1471
1472     /*
1473      * Register for tapping
1474      */
1475     rtsp_tap = register_tap("rtsp"); /* RTSP statistics tap */
1476 }
1477
1478 void
1479 proto_reg_handoff_rtsp(void)
1480 {
1481     static dissector_handle_t rtsp_handle;
1482     static gboolean rtsp_prefs_initialized = FALSE;
1483
1484     if (!rtsp_prefs_initialized) {
1485         rtsp_handle = find_dissector("rtsp");
1486         rtp_handle = find_dissector("rtp");
1487         rtcp_handle = find_dissector("rtcp");
1488         rdt_handle = find_dissector("rdt");
1489         media_type_dissector_table = find_dissector_table("media_type");
1490         voip_tap = find_tap_id("voip");
1491         rtsp_prefs_initialized = TRUE;
1492     }
1493     else {
1494         dissector_delete_uint_range("tcp.port", rtsp_tcp_port_range, rtsp_handle);
1495         g_free(rtsp_tcp_port_range);
1496     }
1497     /* Set our port number for future use */
1498     rtsp_tcp_port_range = range_copy(global_rtsp_tcp_port_range);
1499     dissector_add_uint_range("tcp.port", rtsp_tcp_port_range, rtsp_handle);
1500
1501     /* XXX: Do the following only once ?? */
1502     stats_tree_register("rtsp","rtsp","RTSP/Packet Counter", 0, rtsp_stats_tree_packet, rtsp_stats_tree_init, NULL );
1503
1504 }