2 * Routines for RTSP packet disassembly (RFC 2326)
4 * Jason Lango <jal@netapp.com>
5 * Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 * RTSP is defined in RFC 2326, https://tools.ietf.org/html/rfc2326
15 * https://www.iana.org/assignments/rsvp-parameters
20 #include <stdio.h> /* for sscanf() */
22 #include <epan/packet.h>
23 #include <epan/req_resp_hdrs.h>
24 #include <epan/prefs.h>
25 #include <epan/conversation.h>
26 #include <epan/expert.h>
27 #include <epan/strutil.h>
28 #include <epan/tap-voip.h>
29 #include <epan/stats_tree.h>
30 #include <epan/addr_resolv.h>
31 #include <wsutil/str_util.h>
32 #include <wsutil/strtoi.h>
33 #include <wsutil/array.h>
35 #include "packet-rdt.h"
36 #include "packet-rtp.h"
37 #include "packet-rtcp.h"
38 #include "packet-e164.h"
39 #include "packet-rtsp.h"
41 void proto_register_rtsp(void);
44 static rtsp_info_value_t
*rtsp_stat_info
;
46 /* http://www.iana.org/assignments/rtsp-parameters/rtsp-parameters.xml */
48 const value_string rtsp_status_code_vals
[] = {
50 { 199, "Informational - Others" },
54 { 250, "Low on Storage Space"},
55 { 299, "Success - Others"},
57 { 300, "Multiple Choices"},
58 { 301, "Moved Permanently"},
59 { 302, "Moved Temporarily"},
62 { 399, "Redirection - Others"},
64 { 400, "Bad Request"},
65 { 401, "Unauthorized"},
66 { 402, "Payment Required"},
69 { 405, "Method Not Allowed"},
70 { 406, "Not Acceptable"},
71 { 407, "Proxy Authentication Required"},
72 { 408, "Request Timeout"},
74 { 411, "Length Required"},
75 { 412, "Precondition Failed"},
76 { 413, "Request Entity Too Large"},
77 { 414, "Request-URI Too Long"},
78 { 415, "Unsupported Media Type"},
79 { 451, "Invalid Parameter"},
80 { 452, "Illegal Conference Identifier"},
81 { 453, "Not Enough Bandwidth"},
82 { 454, "Session Not Found"},
83 { 455, "Method Not Valid In This State"},
84 { 456, "Header Field Not Valid"},
85 { 457, "Invalid Range"},
86 { 458, "Parameter Is Read-Only"},
87 { 459, "Aggregate Operation Not Allowed"},
88 { 460, "Only Aggregate Operation Allowed"},
89 { 461, "Unsupported Transport"},
90 { 462, "Destination Unreachable"},
91 { 499, "Client Error - Others"},
93 { 500, "Internal Server Error"},
94 { 501, "Not Implemented"},
95 { 502, "Bad Gateway"},
96 { 503, "Service Unavailable"},
97 { 504, "Gateway Timeout"},
98 { 505, "RTSP Version not supported"},
99 { 551, "Option Not Support"},
100 { 599, "Server Error - Others"},
105 static int proto_rtsp
;
108 static int ett_rtspframe
;
109 static int ett_rtsp_method
;
111 static int hf_rtsp_request
;
112 static int hf_rtsp_response
;
113 static int hf_rtsp_content_type
;
114 static int hf_rtsp_content_length
;
115 static int hf_rtsp_method
;
116 static int hf_rtsp_url
;
117 static int hf_rtsp_status
;
118 static int hf_rtsp_session
;
119 static int hf_rtsp_transport
;
120 static int hf_rtsp_rdtfeaturelevel
;
121 static int hf_rtsp_X_Vig_Msisdn
;
122 static int hf_rtsp_magic
;
123 static int hf_rtsp_channel
;
124 static int hf_rtsp_length
;
125 static int hf_rtsp_data
;
129 static expert_field ei_rtsp_unknown_transport_type
;
130 static expert_field ei_rtsp_bad_server_port
;
131 static expert_field ei_rtsp_bad_client_port
;
132 static expert_field ei_rtsp_bad_interleaved_channel
;
133 static expert_field ei_rtsp_content_length_invalid
;
134 static expert_field ei_rtsp_rdtfeaturelevel_invalid
;
135 static expert_field ei_rtsp_bad_server_ip_address
;
136 static expert_field ei_rtsp_bad_client_ip_address
;
138 static dissector_handle_t rtsp_handle
;
139 static dissector_handle_t rtp_handle
;
140 static dissector_handle_t rtp_rfc4571_handle
;
141 static dissector_handle_t rtcp_handle
;
142 static dissector_handle_t rdt_handle
;
143 static dissector_table_t media_type_dissector_table
;
144 static heur_dissector_list_t heur_subdissector_list
;
146 static const char *st_str_packets
= "Total RTSP Packets";
147 static const char *st_str_requests
= "RTSP Request Packets";
148 static const char *st_str_responses
= "RTSP Response Packets";
149 static const char *st_str_resp_broken
= "???: broken";
150 static const char *st_str_resp_100
= "1xx: Informational";
151 static const char *st_str_resp_200
= "2xx: Success";
152 static const char *st_str_resp_300
= "3xx: Redirection";
153 static const char *st_str_resp_400
= "4xx: Client Error";
154 static const char *st_str_resp_500
= "5xx: Server Error";
155 static const char *st_str_other
= "Other RTSP Packets";
157 static int st_node_packets
= -1;
158 static int st_node_requests
= -1;
159 static int st_node_responses
= -1;
160 static int st_node_resp_broken
= -1;
161 static int st_node_resp_100
= -1;
162 static int st_node_resp_200
= -1;
163 static int st_node_resp_300
= -1;
164 static int st_node_resp_400
= -1;
165 static int st_node_resp_500
= -1;
166 static int st_node_other
= -1;
169 rtsp_stats_tree_init(stats_tree
* st
)
171 st_node_packets
= stats_tree_create_node(st
, st_str_packets
, 0, STAT_DT_INT
, true);
172 st_node_requests
= stats_tree_create_pivot(st
, st_str_requests
, st_node_packets
);
173 st_node_responses
= stats_tree_create_node(st
, st_str_responses
, st_node_packets
, STAT_DT_INT
, true);
174 st_node_resp_broken
= stats_tree_create_node(st
, st_str_resp_broken
, st_node_responses
, STAT_DT_INT
, true);
175 st_node_resp_100
= stats_tree_create_node(st
, st_str_resp_100
, st_node_responses
, STAT_DT_INT
, true);
176 st_node_resp_200
= stats_tree_create_node(st
, st_str_resp_200
, st_node_responses
, STAT_DT_INT
, true);
177 st_node_resp_300
= stats_tree_create_node(st
, st_str_resp_300
, st_node_responses
, STAT_DT_INT
, true);
178 st_node_resp_400
= stats_tree_create_node(st
, st_str_resp_400
, st_node_responses
, STAT_DT_INT
, true);
179 st_node_resp_500
= stats_tree_create_node(st
, st_str_resp_500
, st_node_responses
, STAT_DT_INT
, true);
180 st_node_other
= stats_tree_create_node(st
, st_str_other
, st_node_packets
, STAT_DT_INT
, false);
183 /* RTSP/Packet Counter stats packet function */
184 static tap_packet_status
185 rtsp_stats_tree_packet(stats_tree
* st
, packet_info
* pinfo _U_
, epan_dissect_t
* edt _U_
, const void* p
, tap_flags_t flags _U_
)
187 const rtsp_info_value_t
*v
= (const rtsp_info_value_t
*)p
;
188 unsigned i
= v
->response_code
;
190 const char *resp_str
;
193 tick_stat_node(st
, st_str_packets
, 0, false);
196 tick_stat_node(st
, st_str_responses
, st_node_packets
, false);
198 if ( (i
<100)||(i
>=600) ) {
199 resp_grp
= st_node_resp_broken
;
200 resp_str
= st_str_resp_broken
;
202 resp_grp
= st_node_resp_100
;
203 resp_str
= st_str_resp_100
;
205 resp_grp
= st_node_resp_200
;
206 resp_str
= st_str_resp_200
;
208 resp_grp
= st_node_resp_300
;
209 resp_str
= st_str_resp_300
;
211 resp_grp
= st_node_resp_400
;
212 resp_str
= st_str_resp_400
;
214 resp_grp
= st_node_resp_500
;
215 resp_str
= st_str_resp_500
;
218 tick_stat_node(st
, resp_str
, st_node_responses
, false);
220 snprintf(str
, sizeof(str
),"%u %s",i
,val_to_str(i
,rtsp_status_code_vals
, "Unknown (%d)"));
221 tick_stat_node(st
, str
, resp_grp
, false);
222 } else if (v
->request_method
) {
223 stats_tree_tick_pivot(st
,st_node_requests
,v
->request_method
);
225 tick_stat_node(st
, st_str_other
, st_node_packets
, false);
228 return TAP_PACKET_REDRAW
;
230 void proto_reg_handoff_rtsp(void);
233 * desegmentation of RTSP headers
234 * (when we are over TCP or another protocol providing the desegmentation API)
236 static bool rtsp_desegment_headers
= true;
239 * desegmentation of RTSP bodies
240 * (when we are over TCP or another protocol providing the desegmentation API)
241 * TODO let the user filter on content-type the bodies he wants desegmented
243 static bool rtsp_desegment_body
= true;
245 /* http://www.iana.org/assignments/port-numbers lists two rtsp ports.
246 * In Addition RTSP uses display port over Wi-Fi Display: 7236.
248 #define RTSP_TCP_PORT_RANGE "554,8554,7236"
251 * Takes an array of bytes, assumed to contain a null-terminated
252 * string, as an argument, and returns the length of the string -
253 * i.e., the size of the array, minus 1 for the null terminator.
255 #define STRLEN_CONST(str) (sizeof (str) - 1)
257 #define RTSP_FRAMEHDR ('$')
260 dissector_handle_t dissector
;
261 } rtsp_interleaved_t
;
263 #define RTSP_MAX_INTERLEAVED (256)
266 * Careful about dynamically allocating memory in this structure (say
267 * for dynamically increasing the size of the 'interleaved' array) -
268 * the containing structure is garbage collected and contained
269 * pointers will not be freed.
272 rtsp_interleaved_t interleaved
[RTSP_MAX_INTERLEAVED
];
273 } rtsp_conversation_data_t
;
276 dissect_rtspinterleaved(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
279 unsigned length_remaining
;
281 proto_tree
*rtspframe_tree
= NULL
;
283 uint8_t rf_chan
; /* interleaved channel id */
284 uint16_t rf_len
; /* packet length */
286 conversation_t
*conv
;
287 rtsp_conversation_data_t
*data
;
288 dissector_handle_t dissector
;
291 * This will throw an exception if we don't have any data left.
292 * That's what we want. (See "tcp_dissect_pdus()", which is
295 length_remaining
= tvb_ensure_captured_length_remaining(tvb
, offset
);
298 * Can we do reassembly?
300 if (rtsp_desegment_headers
&& pinfo
->can_desegment
) {
302 * Yes - would an RTSP multiplexed header starting at
303 * this offset be split across segment boundaries?
305 if (length_remaining
< 4) {
307 * Yes. Tell the TCP dissector where the data for
308 * this message starts in the data it handed us and
309 * that we need "some more data." Don't tell it
310 * exactly how many bytes we need because if/when we
311 * ask for even more (after the header) that will
314 pinfo
->desegment_offset
= offset
;
315 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
321 * Get the "$", channel, and length from the header.
323 orig_offset
= offset
;
324 rf_chan
= tvb_get_uint8(tvb
, offset
+1);
325 rf_len
= tvb_get_ntohs(tvb
, offset
+2);
328 * Can we do reassembly?
330 if (rtsp_desegment_body
&& pinfo
->can_desegment
) {
332 * Yes - is the header + encapsulated packet split
333 * across segment boundaries?
335 if (length_remaining
< 4U + rf_len
) {
337 * Yes. Tell the TCP dissector where the data
338 * for this message starts in the data it handed
339 * us, and how many more bytes we need, and return.
341 pinfo
->desegment_offset
= offset
;
342 pinfo
->desegment_len
= 4U + rf_len
- length_remaining
;
347 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
348 "Interleaved channel 0x%02x, %u bytes",
351 ti
= proto_tree_add_protocol_format(tree
, proto_rtsp
, tvb
,
353 "RTSP Interleaved Frame, Channel: 0x%02x, %u bytes",
355 rtspframe_tree
= proto_item_add_subtree(ti
, ett_rtspframe
);
357 proto_tree_add_item(rtspframe_tree
, hf_rtsp_magic
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
361 proto_tree_add_item(rtspframe_tree
, hf_rtsp_channel
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
365 proto_tree_add_item(rtspframe_tree
, hf_rtsp_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
369 * We set the actual length of the tvbuff for the interleaved
370 * stuff to the minimum of what's left in the tvbuff and the
371 * length in the header.
373 * XXX - what if there's nothing left in the tvbuff?
374 * We'd want a BoundsError exception to be thrown, so
375 * that a Short Frame would be reported.
377 if (length_remaining
> rf_len
)
378 length_remaining
= rf_len
;
379 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length_remaining
, rf_len
);
381 conv
= find_conversation_pinfo(pinfo
, 0);
384 (data
= (rtsp_conversation_data_t
*)conversation_get_proto_data(conv
, proto_rtsp
)) &&
385 /* Add the following condition if it is not always true.
386 rf_chan < RTSP_MAX_INTERLEAVED &&
388 (dissector
= data
->interleaved
[rf_chan
].dissector
)) {
389 call_dissector(dissector
, next_tvb
, pinfo
, tree
);
391 bool dissected
= false;
392 heur_dtbl_entry_t
*hdtbl_entry
= NULL
;
394 dissected
= dissector_try_heuristic(heur_subdissector_list
,
395 next_tvb
, pinfo
, tree
, &hdtbl_entry
, NULL
);
398 proto_tree_add_item(rtspframe_tree
, hf_rtsp_data
, tvb
, offset
, rf_len
, ENC_NA
);
404 return offset
- orig_offset
;
407 static void process_rtsp_request(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
408 size_t linelen
, size_t next_line_offset
,
409 packet_info
*pinfo
, proto_tree
*tree
);
411 static void process_rtsp_reply(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
412 size_t linelen
, size_t next_line_offset
,
413 packet_info
*pinfo
, proto_tree
*tree
);
421 static const char *rtsp_methods
[] = {
435 #define RTSP_NMETHODS array_length(rtsp_methods)
438 is_rtsp_request_or_reply(const unsigned char *line
, size_t linelen
, rtsp_type_t
*type
)
441 const unsigned char *token
, *next_token
;
443 char response_chars
[4];
445 /* Is this an RTSP reply? */
446 if (linelen
>= 5 && g_ascii_strncasecmp("RTSP/", line
, 5) == 0) {
451 /* The first token is the version. */
452 tokenlen
= get_token_len(line
, line
+linelen
, &token
);
454 /* The next token is the status code. */
455 tokenlen
= get_token_len(token
, line
+linelen
, &next_token
);
457 memcpy(response_chars
, token
, 3);
458 response_chars
[3] = '\0';
459 ws_strtou32(response_chars
, NULL
, &rtsp_stat_info
->response_code
);
466 * Is this an RTSP request?
467 * Check whether the line begins with one of the RTSP request
470 for (ii
= 0; ii
< RTSP_NMETHODS
; ii
++) {
471 size_t len
= strlen(rtsp_methods
[ii
]);
472 if (linelen
>= len
&&
473 g_ascii_strncasecmp(rtsp_methods
[ii
], line
, len
) == 0 &&
474 (len
== linelen
|| g_ascii_isspace(line
[len
])))
476 *type
= RTSP_REQUEST
;
477 rtsp_stat_info
->request_method
=
478 wmem_strndup(wmem_packet_scope(), rtsp_methods
[ii
], len
+1);
483 /* Wasn't a request or a response */
484 *type
= RTSP_NOT_FIRST_LINE
;
488 static const char rtsp_content_type
[] = "Content-Type:";
489 static const char rtsp_transport
[] = "Transport:";
490 static const char rtsp_sps_server_port
[] = "server_port=";
491 static const char rtsp_cps_server_port
[] = "client_port=";
492 static const char rtsp_sps_dest_addr
[] = "dest_addr=";
493 static const char rtsp_cps_src_addr
[] = "src_addr=";
494 static const char rtsp_rtp_udp_default
[] = "rtp/avp";
495 static const char rtsp_rtp_udp
[] = "rtp/avp/udp";
496 static const char rtsp_rtp_tcp
[] = "rtp/avp/tcp";
497 static const char rtsp_rdt_feature_level
[] = "RDTFeatureLevel";
498 static const char rtsp_real_rdt
[] = "x-real-rdt/";
499 static const char rtsp_real_tng
[] = "x-pn-tng/"; /* synonym for x-real-rdt */
500 static const char rtsp_inter
[] = "interleaved=";
503 rtsp_create_conversation(packet_info
*pinfo
, proto_item
*ti
,
504 const unsigned char *line_begin
, size_t line_len
,
505 int rdt_feature_level
,
506 rtsp_type_t rtsp_type_packet
)
508 conversation_t
*conv
;
511 bool rtp_udp_transport
= false;
512 bool rtp_tcp_transport
= false;
513 bool rdt_transport
= false;
514 unsigned c_data_port
, c_mon_port
;
515 unsigned s_data_port
, s_mon_port
;
516 unsigned ipv4_1
, ipv4_2
, ipv4_3
, ipv4_4
;
517 bool is_video
= false; /* FIX ME - need to indicate video or not */
522 if (rtsp_type_packet
!= RTSP_REPLY
) {
529 /* Copy line into buf */
530 if (line_len
> sizeof(buf
) - 1)
532 /* Don't overflow the buffer. */
533 line_len
= sizeof(buf
) - 1;
535 memcpy(buf
, line_begin
, line_len
);
536 buf
[line_len
] = '\0';
538 /* Get past "Transport:" and spaces */
539 tmp
= buf
+ STRLEN_CONST(rtsp_transport
);
540 while (*tmp
&& g_ascii_isspace(*tmp
))
543 /* Work out which transport type is here */
544 if (g_ascii_strncasecmp(tmp
, rtsp_rtp_udp
, strlen(rtsp_rtp_udp
)) == 0)
546 rtp_udp_transport
= true;
548 else if (g_ascii_strncasecmp(tmp
, rtsp_rtp_tcp
, strlen(rtsp_rtp_tcp
)) == 0)
550 rtp_tcp_transport
= true;
552 else if (g_ascii_strncasecmp(tmp
, rtsp_rtp_udp_default
, strlen(rtsp_rtp_udp_default
)) == 0)
554 rtp_udp_transport
= true;
556 else if (g_ascii_strncasecmp(tmp
, rtsp_real_rdt
, strlen(rtsp_real_rdt
)) == 0 ||
557 g_ascii_strncasecmp(tmp
, rtsp_real_tng
, strlen(rtsp_real_tng
)) == 0)
559 rdt_transport
= true;
563 /* Give up on unknown transport types */
564 expert_add_info(pinfo
, ti
, &ei_rtsp_unknown_transport_type
);
568 c_data_port
= c_mon_port
= 0;
569 s_data_port
= s_mon_port
= 0;
571 /* Look for server port */
572 if ((tmp
= strstr(buf
, rtsp_sps_server_port
))) {
573 tmp
+= strlen(rtsp_sps_server_port
);
574 if (sscanf(tmp
, "%u-%u", &s_data_port
, &s_mon_port
) < 1) {
575 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_port
);
579 else if ((tmp
= strstr(buf
, rtsp_sps_dest_addr
))) {
580 tmp
+= strlen(rtsp_sps_dest_addr
);
581 if (sscanf(tmp
, "\":%u\"", &s_data_port
) == 1) {
583 if (s_data_port
== 9) {
587 else if (sscanf(tmp
, "\"%u.%u.%u.%u:%u\"", &ipv4_1
, &ipv4_2
, &ipv4_3
, &ipv4_4
, &s_data_port
) == 5) {
593 tmp2
=strstr(tmp
,":");
594 tmp3
=g_strndup(tmp
,tmp2
-tmp
);
595 if (!str_to_ip(tmp3
, &ip4_addr
)) {
597 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_ip_address
);
600 set_address(&dst_addr
, AT_IPv4
, 4, &ip4_addr
);
603 else if (sscanf(tmp
, "\"%u.%u.%u.%u\"", &ipv4_1
, &ipv4_2
, &ipv4_3
, &ipv4_4
) == 4) {
609 tmp2
=strstr(tmp
,"\"");
610 tmp3
=g_strndup(tmp
,tmp2
-tmp
);
611 if (!str_to_ip(tmp3
, &ip4_addr
)) {
613 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_ip_address
);
616 set_address(&dst_addr
, AT_IPv4
, 4, &ip4_addr
);
621 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_port
);
627 /* Look for client port */
628 if ((tmp
= strstr(buf
, rtsp_cps_server_port
))) {
629 tmp
+= strlen(rtsp_cps_server_port
);
630 if (sscanf(tmp
, "%u-%u", &c_data_port
, &c_mon_port
) < 1) {
631 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_client_port
);
635 else if ((tmp
= strstr(buf
, rtsp_cps_src_addr
))) {
636 tmp
+= strlen(rtsp_cps_src_addr
);
637 if (sscanf(tmp
, "\"%u.%u.%u.%u:%u\"", &ipv4_1
, &ipv4_2
, &ipv4_3
, &ipv4_4
, &c_data_port
) == 5) {
643 tmp2
=strstr(tmp
,":");
644 tmp3
=g_strndup(tmp
,tmp2
-tmp
);
645 if (!str_to_ip(tmp3
, &ip4_addr
)) {
647 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_client_ip_address
);
650 set_address(&src_addr
, AT_IPv4
, 4, &ip4_addr
);
655 /* Deal with RTSP TCP-interleaved conversations. */
656 tmp
= strstr(buf
, rtsp_inter
);
658 rtsp_conversation_data_t
*data
;
659 unsigned s_data_chan
, s_mon_chan
;
662 /* Move tmp to beyond interleaved string */
663 tmp
+= strlen(rtsp_inter
);
664 /* Look for channel number(s) */
665 i
= sscanf(tmp
, "%u-%u", &s_data_chan
, &s_mon_chan
);
668 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_interleaved_channel
);
672 /* At least data channel present, look for conversation (presumably TCP) */
673 conv
= find_or_create_conversation(pinfo
);
675 /* Look for previous data */
676 data
= (rtsp_conversation_data_t
*)conversation_get_proto_data(conv
, proto_rtsp
);
678 /* Create new data if necessary */
681 data
= wmem_new0(wmem_file_scope(), rtsp_conversation_data_t
);
682 conversation_add_proto_data(conv
, proto_rtsp
, data
);
685 /* Now set the dissector handle of the interleaved channel
686 according to the transport protocol used */
687 if (rtp_tcp_transport
)
689 if (s_data_chan
< RTSP_MAX_INTERLEAVED
) {
690 data
->interleaved
[s_data_chan
].dissector
=
693 if (i
> 1 && s_mon_chan
< RTSP_MAX_INTERLEAVED
) {
694 data
->interleaved
[s_mon_chan
].dissector
=
698 else if (rdt_transport
)
700 if (s_data_chan
< RTSP_MAX_INTERLEAVED
) {
701 data
->interleaved
[s_data_chan
].dissector
=
707 /* Noninterleaved options follow */
709 * We only want to match on the destination address, not the
710 * source address, because the server might send back a packet
711 * from an address other than the address to which its client
712 * sent the packet, so we construct a conversation with no
715 else if (rtp_udp_transport
)
717 /* RTP only if indicated */
720 rtp_add_address(pinfo
, PT_UDP
, &dst_addr
, c_data_port
, s_data_port
,
721 "RTSP", pinfo
->num
, is_video
, NULL
);
723 else if (s_data_port
)
725 rtp_add_address(pinfo
, PT_UDP
, &src_addr
, s_data_port
, 0,
726 "RTSP", pinfo
->num
, is_video
, NULL
);
729 /* RTCP only if indicated */
732 rtcp_add_address(pinfo
, &pinfo
->dst
, c_mon_port
, s_mon_port
,
736 else if (rtp_tcp_transport
)
738 /* RTP only if indicated */
739 rtp_add_address(pinfo
, PT_TCP
, &src_addr
, c_data_port
, s_data_port
,
740 "RTSP", pinfo
->num
, is_video
, NULL
);
742 else if (rdt_transport
)
744 /* Real Data Transport */
745 rdt_add_address(pinfo
, &pinfo
->dst
, c_data_port
, s_data_port
,
746 "RTSP", rdt_feature_level
);
751 static const char rtsp_content_length
[] = "Content-Length:";
754 rtsp_get_content_length(const unsigned char *line_begin
, size_t line_len
)
758 int32_t content_length
;
762 if (line_len
> sizeof(buf
) - 1) {
764 * Don't overflow the buffer.
766 line_len
= sizeof(buf
) - 1;
768 memcpy(buf
, line_begin
, line_len
);
769 buf
[line_len
] = '\0';
771 tmp
= buf
+ STRLEN_CONST(rtsp_content_length
);
772 while (*tmp
&& g_ascii_isspace(*tmp
))
774 ws_strtoi32(tmp
, &p
, &content_length
);
776 if (up
== tmp
|| (*up
!= '\0' && !g_ascii_isspace(*up
)))
777 return -1; /* not a valid number */
778 return content_length
;
781 static const char rtsp_Session
[] = "Session:";
782 static const char rtsp_X_Vig_Msisdn
[] = "X-Vig-Msisdn";
785 dissect_rtspmessage(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
788 proto_tree
*rtsp_tree
= NULL
;
789 proto_tree
*sub_tree
= NULL
;
790 proto_item
*ti_top
= NULL
;
791 const unsigned char *line
;
793 const unsigned char *linep
, *lineend
;
795 int first_linelen
, linelen
;
798 bool is_request_or_reply
;
799 bool body_requires_content_len
;
800 bool saw_req_resp_or_header
;
802 rtsp_type_t rtsp_type_packet
;
803 rtsp_type_t rtsp_type_line
;
807 int reported_datalen
;
810 e164_info_t e164_info
;
811 int rdt_feature_level
= 0;
812 char *media_type_str_lower_case
= NULL
;
813 int semi_colon_offset
;
815 char *frame_label
= NULL
;
816 char *session_id
= NULL
;
817 voip_packet_info_t
*stat_info
= NULL
;
819 rtsp_stat_info
= wmem_new(pinfo
->pool
, rtsp_info_value_t
);
820 rtsp_stat_info
->framenum
= pinfo
->num
;
821 rtsp_stat_info
->response_code
= 0;
822 rtsp_stat_info
->request_method
= NULL
;
823 rtsp_stat_info
->request_uri
= NULL
;
824 rtsp_stat_info
->rtsp_host
= NULL
;
827 * Is this a request or response?
829 * Note that "tvb_find_line_end()" will return a value that
830 * is not longer than what's in the buffer, so the
831 * "tvb_get_ptr()" call won't throw an exception.
833 first_linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
836 * Is the first line a request or response?
838 line
= tvb_get_ptr(tvb
, offset
, first_linelen
);
839 is_request_or_reply
= is_rtsp_request_or_reply(line
, first_linelen
,
841 if (is_request_or_reply
) {
843 * Yes, it's a request or response.
844 * Do header desegmentation if we've been told to,
845 * and do body desegmentation if we've been told to and
846 * we find a Content-Length header.
848 * RFC 7826, Section 18.17. requires Content-Length and
849 * assumes zero if missing.
851 if (!req_resp_hdrs_do_reassembly(tvb
, offset
, pinfo
,
852 rtsp_desegment_headers
, rtsp_desegment_body
, false, NULL
,
855 * More data needed for desegmentation.
862 * RFC 2326 says that a content length must be specified
863 * in requests that have a body, although section 4.4 speaks
864 * of a server closing the connection indicating the end of
867 * To support pipelining, we check if line behind blank line
868 * looks like RTSP header. If so, we process rest of packet with
871 * If no, we assume that an absent content length in a request means
872 * that we don't have a body, and that an absent content length
873 * in a reply means that the reply body runs to the end of
874 * the connection. If the first line is neither, we assume
875 * that whatever follows a blank line should be treated as a
876 * body; there's not much else we can do, as we're jumping
877 * into the message in the middle.
879 * XXX - if there was no Content-Length entity header, we should
880 * accumulate all data until the end of the connection.
881 * That'd require that the TCP dissector call subdissectors
882 * for all frames with FIN, even if they contain no data,
883 * which would require subdissectors to deal intelligently
884 * with empty segments.
886 if (rtsp_type_packet
== RTSP_REQUEST
)
887 body_requires_content_len
= true;
889 body_requires_content_len
= false;
891 line
= tvb_get_ptr(tvb
, offset
, first_linelen
);
892 if (is_request_or_reply
) {
893 if ( rtsp_type_packet
== RTSP_REPLY
) {
894 frame_label
= wmem_strdup_printf(pinfo
->pool
,
895 "Reply: %s", format_text(pinfo
->pool
, line
, first_linelen
));
898 frame_label
= format_text(pinfo
->pool
, line
, first_linelen
);
902 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RTSP");
904 * Put the first line from the buffer into the summary
905 * if it's an RTSP request or reply (but leave out the
907 * Otherwise, just call it a continuation.
909 * Note that "tvb_find_line_end()" will return a value that
910 * is not longer than what's in the buffer, so the
911 * "tvb_get_ptr()" call won't throw an exception.
913 if (is_request_or_reply
)
914 if ( rtsp_type_packet
== RTSP_REPLY
) {
915 col_set_str(pinfo
->cinfo
, COL_INFO
, "Reply: ");
916 col_append_str(pinfo
->cinfo
, COL_INFO
,
917 format_text(pinfo
->pool
, line
, first_linelen
));
920 col_add_str(pinfo
->cinfo
, COL_INFO
,
921 format_text(pinfo
->pool
, line
, first_linelen
));
925 col_set_str(pinfo
->cinfo
, COL_INFO
, "Continuation");
927 orig_offset
= offset
;
929 ti_top
= proto_tree_add_item(tree
, proto_rtsp
, tvb
, offset
, -1,
931 rtsp_tree
= proto_item_add_subtree(ti_top
, ett_rtsp
);
935 * We haven't yet seen a Content-Length header.
940 * Process the packet data, a line at a time.
942 saw_req_resp_or_header
= false; /* haven't seen anything yet */
943 while (tvb_offset_exists(tvb
, offset
)) {
945 * We haven't yet concluded that this is a header.
950 * Find the end of the line.
952 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
955 line_end_offset
= offset
+ linelen
;
957 * colon_offset may be -1
959 colon_offset
= tvb_find_uint8(tvb
, offset
, linelen
, ':');
963 * Get a buffer that refers to the line.
965 line
= tvb_get_ptr(tvb
, offset
, linelen
);
966 lineend
= line
+ linelen
;
969 * OK, does it look like an RTSP request or response?
971 is_request_or_reply
= is_rtsp_request_or_reply(line
, linelen
, &rtsp_type_line
);
972 if (is_request_or_reply
)
976 * No. Does it look like a blank line (as would appear
977 * at the end of an RTSP request)?
980 goto is_rtsp
; /* Yes. */
983 * No. Does it look like a header?
986 while (linep
< lineend
) {
990 * This must be a CHAR, and must not be a CTL, to be part
991 * of a token; that means it must be printable ASCII.
993 * XXX - what about leading LWS on continuation
996 if (!g_ascii_isprint(c
))
1018 * It's a tspecial, so it's not
1019 * part of a token, so it's not
1020 * a field name for the beginning
1027 * This ends the token; we consider
1028 * this to be a header.
1036 * LWS (RFC-2616, 4.2); continue the previous
1044 * We haven't seen the colon, but everything else looks
1045 * OK for a header line.
1047 * If we've already seen an RTSP request or response
1048 * line, or a header line, and we're at the end of
1049 * the tvbuff, we assume this is an incomplete header
1050 * line. (We quit this loop after seeing a blank line,
1051 * so if we've seen a request or response line, or a
1052 * header line, this is probably more of the request
1053 * or response we're presumably seeing. There is some
1054 * risk of false positives, but the same applies for
1055 * full request or response lines or header lines,
1056 * although that's less likely.)
1058 * We throw an exception in that case, by checking for
1059 * the existence of the next byte after the last one
1060 * in the line. If it exists, "tvb_ensure_bytes_exist()"
1061 * throws no exception, and we fall through to the
1062 * "not RTSP" case. If it doesn't exist,
1063 * "tvb_ensure_bytes_exist()" will throw the appropriate
1066 if (saw_req_resp_or_header
)
1067 tvb_ensure_bytes_exist(tvb
, offset
, linelen
+ 1);
1071 * We don't consider this part of an RTSP request or
1072 * reply, so we don't display it.
1078 * Process this line.
1082 * This is a blank line, which means that
1083 * whatever follows it isn't part of this
1086 proto_tree_add_format_text(rtsp_tree
, tvb
, offset
, next_offset
- offset
);
1087 offset
= next_offset
;
1092 * Not a blank line - either a request, a reply, or a header
1095 saw_req_resp_or_header
= true;
1098 switch (rtsp_type_line
)
1101 process_rtsp_request(tvb
, offset
, line
, linelen
, next_offset
, pinfo
, rtsp_tree
);
1105 process_rtsp_reply(tvb
, offset
, line
, linelen
, next_offset
, pinfo
, rtsp_tree
);
1108 case RTSP_NOT_FIRST_LINE
:
1109 /* Drop through, it may well be a header line */
1116 /* We know that colon_offset must be set */
1118 /* Skip whitespace after the colon. */
1119 value_offset
= colon_offset
+ 1;
1120 while ((value_offset
< line_end_offset
) &&
1121 ((c
= tvb_get_uint8(tvb
, value_offset
)) == ' ' || c
== '\t'))
1125 value_len
= line_end_offset
- value_offset
;
1128 * Process some headers specially.
1130 #define HDR_MATCHES(header) \
1131 ( (size_t)linelen > STRLEN_CONST(header) && \
1132 g_ascii_strncasecmp(line, (header), STRLEN_CONST(header)) == 0)
1134 if (HDR_MATCHES(rtsp_transport
))
1137 ti
= proto_tree_add_string(rtsp_tree
, hf_rtsp_transport
, tvb
,
1139 tvb_format_text(pinfo
->pool
, tvb
, value_offset
,
1143 * Based on the port numbers specified
1144 * in the Transport: header, set up
1145 * a conversation that will be dissected
1146 * with the appropriate dissector.
1148 rtsp_create_conversation(pinfo
, ti
, line
, linelen
, rdt_feature_level
, rtsp_type_packet
);
1149 } else if (HDR_MATCHES(rtsp_content_type
))
1151 proto_tree_add_string(rtsp_tree
, hf_rtsp_content_type
,
1152 tvb
, offset
, linelen
,
1153 tvb_format_text(pinfo
->pool
, tvb
, value_offset
,
1156 offset
= offset
+ (int)STRLEN_CONST(rtsp_content_type
);
1158 offset
= tvb_skip_wsp(tvb
, offset
, value_len
);
1159 semi_colon_offset
= tvb_find_uint8(tvb
, value_offset
, value_len
, ';');
1160 if ( semi_colon_offset
!= -1) {
1161 /* m-parameter present */
1162 par_end_offset
= tvb_skip_wsp_return(tvb
, semi_colon_offset
-1);
1163 value_len
= par_end_offset
- offset
;
1166 media_type_str_lower_case
= ascii_strdown_inplace(
1167 (char *)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, value_len
, ENC_ASCII
));
1169 } else if (HDR_MATCHES(rtsp_content_length
))
1174 clength_valid
= ws_strtou32(tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
),
1176 pi
= proto_tree_add_uint(rtsp_tree
, hf_rtsp_content_length
,
1177 tvb
, offset
, linelen
, clength
);
1179 expert_add_info(pinfo
, pi
, &ei_rtsp_content_length_invalid
);
1182 * Only the amount specified by the
1183 * Content-Length: header should be treated
1186 content_length
= rtsp_get_content_length(line
, linelen
);
1188 } else if (HDR_MATCHES(rtsp_Session
))
1190 session_id
= tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
);
1191 /* Put the value into the protocol tree */
1192 proto_tree_add_string(rtsp_tree
, hf_rtsp_session
, tvb
,
1196 } else if (HDR_MATCHES(rtsp_X_Vig_Msisdn
)) {
1198 * Extract the X_Vig_Msisdn string
1200 if (colon_offset
!= -1)
1203 /* Put the value into the protocol tree */
1204 ti
= proto_tree_add_string(rtsp_tree
, hf_rtsp_X_Vig_Msisdn
,tvb
,
1206 tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
));
1207 sub_tree
= proto_item_add_subtree(ti
, ett_rtsp_method
);
1209 e164_info
.e164_number_type
= CALLING_PARTY_NUMBER
;
1210 e164_info
.nature_of_address
= 0;
1212 e164_info
.E164_number_str
= tvb_get_string_enc(pinfo
->pool
, tvb
, value_offset
,
1213 value_len
, ENC_ASCII
);
1214 e164_info
.E164_number_length
= value_len
;
1215 dissect_e164_number(tvb
, sub_tree
, value_offset
,
1216 value_len
, e164_info
);
1218 } else if (HDR_MATCHES(rtsp_rdt_feature_level
))
1220 bool rdt_feature_level_valid
;
1222 rdt_feature_level_valid
= ws_strtou32(tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
),
1223 NULL
, &rdt_feature_level
);
1224 pi
= proto_tree_add_uint(rtsp_tree
, hf_rtsp_rdtfeaturelevel
,
1225 tvb
, offset
, linelen
, rdt_feature_level
);
1226 if (!rdt_feature_level_valid
)
1227 expert_add_info(pinfo
, pi
, &ei_rtsp_rdtfeaturelevel_invalid
);
1231 /* Default case for headers. Show line as text */
1232 proto_tree_add_format_text(rtsp_tree
, tvb
, offset
, next_offset
- offset
);
1235 else if (rtsp_type_line
== RTSP_NOT_FIRST_LINE
)
1237 /* Catch-all for all other lines... Show line as text.
1238 TODO: should these be shown as errors? */
1239 proto_tree_add_format_text(rtsp_tree
, tvb
, offset
, next_offset
- offset
);
1242 offset
= next_offset
;
1246 stat_info
= wmem_new0(pinfo
->pool
, voip_packet_info_t
);
1247 stat_info
->protocol_name
= wmem_strdup(pinfo
->pool
, "RTSP");
1248 stat_info
->call_id
= session_id
;
1249 stat_info
->frame_label
= frame_label
;
1250 stat_info
->call_state
= VOIP_CALL_SETUP
;
1251 stat_info
->call_active_state
= VOIP_ACTIVE
;
1252 stat_info
->frame_comment
= frame_label
;
1253 tap_queue_packet(voip_tap
, pinfo
, stat_info
);
1257 * Have now read all of the lines of this message.
1259 * If a content length was supplied, the amount of data to be
1260 * processed as RTSP payload is the minimum of the content
1261 * length and the amount of data remaining in the frame.
1263 * If no content length was supplied (or if a bad content length
1264 * was supplied), the amount of data to be processed is the amount
1265 * of data remaining in the frame.
1267 datalen
= tvb_captured_length_remaining(tvb
, offset
);
1268 reported_datalen
= tvb_reported_length_remaining(tvb
, offset
);
1269 if (content_length
!= -1) {
1271 * Content length specified; display only that amount
1274 if (datalen
> content_length
)
1275 datalen
= content_length
;
1278 * XXX - limit the reported length in the tvbuff we'll
1279 * hand to a subdissector to be no greater than the
1282 * We really need both unreassembled and "how long it'd
1283 * be if it were reassembled" lengths for tvbuffs, so
1284 * that we throw the appropriate exceptions for
1285 * "not enough data captured" (running past the length),
1286 * "packet needed reassembly" (within the length but
1287 * running past the unreassembled length), and
1288 * "packet is malformed" (running past the reassembled
1291 if (reported_datalen
> content_length
)
1292 reported_datalen
= content_length
;
1295 * No content length specified; if this message doesn't
1296 * have a body if no content length is specified, process
1297 * nothing as payload.
1299 if (body_requires_content_len
)
1305 * There's stuff left over; process it.
1310 * Now create a tvbuff for the Content-type stuff and
1313 * The amount of data to be processed that's
1314 * available in the tvbuff is "datalen", which
1315 * is the minimum of the amount of data left in
1316 * the tvbuff and any specified content length.
1318 * The amount of data to be processed that's in
1319 * this frame, regardless of whether it was
1320 * captured or not, is "reported_datalen",
1321 * which, if no content length was specified,
1322 * is -1, i.e. "to the end of the frame.
1324 new_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, datalen
,
1328 * Check if next line is RTSP message - pipelining
1329 * If yes, stop processing and start next loop
1330 * If no, process rest of packet with dissectors
1332 first_linelen
= tvb_find_line_end(new_tvb
, 0, -1, &next_offset
, false);
1333 line
= tvb_get_ptr(new_tvb
, 0, first_linelen
);
1334 is_request_or_reply
= is_rtsp_request_or_reply(line
, first_linelen
,
1337 if (!is_request_or_reply
){
1338 if (media_type_str_lower_case
&&
1339 dissector_try_string_with_data(media_type_dissector_table
,
1340 media_type_str_lower_case
,
1341 new_tvb
, pinfo
, rtsp_tree
, true, NULL
)){
1345 * Fix up the top-level item so that it doesn't
1346 * include the SDP stuff.
1349 proto_item_set_len(ti_top
, offset
);
1351 if (tvb_get_uint8(tvb
, offset
) == RTSP_FRAMEHDR
) {
1353 * This is interleaved stuff; don't
1354 * treat it as raw data - set "datalen"
1355 * to 0, so we won't skip the offset
1356 * past it, which will cause our
1357 * caller to process that stuff itself.
1361 proto_tree_add_bytes_format(rtsp_tree
, hf_rtsp_data
, tvb
, offset
,
1362 datalen
, NULL
, "Data (%d bytes)",
1368 * We've processed "datalen" bytes worth of data
1369 * (which may be no data at all); advance the
1370 * offset past whatever data we've processed.
1376 tap_queue_packet(rtsp_tap
, pinfo
, rtsp_stat_info
);
1378 return offset
- orig_offset
;
1382 process_rtsp_request(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
1383 size_t linelen
, size_t next_line_offset
, packet_info
*pinfo
, proto_tree
*tree
)
1385 proto_tree
*sub_tree
;
1387 const unsigned char *lineend
= data
+ linelen
;
1389 const unsigned char *url
;
1390 const unsigned char *url_start
;
1391 unsigned char *tmp_url
;
1393 /* Request Methods */
1394 for (ii
= 0; ii
< RTSP_NMETHODS
; ii
++) {
1395 size_t len
= strlen(rtsp_methods
[ii
]);
1396 if (linelen
>= len
&&
1397 g_ascii_strncasecmp(rtsp_methods
[ii
], data
, len
) == 0 &&
1398 (len
== linelen
|| g_ascii_isspace(data
[len
])))
1401 if (ii
== RTSP_NMETHODS
) {
1403 * We got here because "is_rtsp_request_or_reply()" returned
1404 * RTSP_REQUEST, so we know one of the request methods
1405 * matched, so we "can't get here".
1407 DISSECTOR_ASSERT_NOT_REACHED();
1410 /* Add a tree for this request */
1411 ti
= proto_tree_add_string(tree
, hf_rtsp_request
, tvb
, offset
,
1412 (int) (next_line_offset
- offset
),
1413 tvb_format_text(pinfo
->pool
, tvb
, offset
, (int) (next_line_offset
- offset
)));
1414 sub_tree
= proto_item_add_subtree(ti
, ett_rtsp_method
);
1417 /* Add method name to tree */
1418 proto_tree_add_string(sub_tree
, hf_rtsp_method
, tvb
, offset
,
1419 (int) strlen(rtsp_methods
[ii
]), rtsp_methods
[ii
]);
1423 /* Skip method name again */
1424 while (url
< lineend
&& !g_ascii_isspace(*url
))
1427 while (url
< lineend
&& g_ascii_isspace(*url
))
1429 /* URL starts here */
1431 /* Scan to end of URL */
1432 while (url
< lineend
&& !g_ascii_isspace(*url
))
1434 /* Create a URL-sized buffer and copy contents */
1435 tmp_url
= format_text(pinfo
->pool
, url_start
, url
- url_start
);
1437 /* Add URL to tree */
1438 proto_tree_add_string(sub_tree
, hf_rtsp_url
, tvb
,
1439 offset
+ (int) (url_start
- data
), (int) (url
- url_start
), tmp_url
);
1442 /* Read first line of a reply message */
1444 process_rtsp_reply(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
1445 size_t linelen
, size_t next_line_offset
, packet_info
*pinfo
, proto_tree
*tree
)
1447 proto_tree
*sub_tree
;
1449 const unsigned char *lineend
= data
+ linelen
;
1450 const unsigned char *status
= data
;
1451 const unsigned char *status_start
;
1454 /* Add a tree for this request */
1455 ti
= proto_tree_add_string(tree
, hf_rtsp_response
, tvb
, offset
,
1456 (int) (next_line_offset
- offset
),
1457 tvb_format_text(pinfo
->pool
, tvb
, offset
, (int) (next_line_offset
- offset
)));
1458 sub_tree
= proto_item_add_subtree(ti
, ett_rtsp_method
);
1463 /* Skip protocol/version */
1464 while (status
< lineend
&& !g_ascii_isspace(*status
))
1467 while (status
< lineend
&& g_ascii_isspace(*status
))
1470 /* Actual code number now */
1471 status_start
= status
;
1473 while (status
< lineend
&& g_ascii_isdigit(*status
))
1474 status_i
= status_i
* 10 + *status
++ - '0';
1476 /* Add field to tree */
1477 proto_tree_add_uint(sub_tree
, hf_rtsp_status
, tvb
,
1478 offset
+ (int) (status_start
- data
),
1479 (int) (status
- status_start
), status_i
);
1483 dissect_rtsp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
1488 while (tvb_reported_length_remaining(tvb
, offset
) != 0) {
1490 * Add separator between multiple messages in column info text
1493 col_set_str(pinfo
->cinfo
, COL_INFO
, ", ");
1494 col_set_fence(pinfo
->cinfo
, COL_INFO
);
1496 len
= (tvb_get_uint8(tvb
, offset
) == RTSP_FRAMEHDR
)
1497 ? dissect_rtspinterleaved(tvb
, offset
, pinfo
, tree
)
1498 : dissect_rtspmessage(tvb
, offset
, pinfo
, tree
);
1504 * OK, we've set the Protocol and Info columns for the
1505 * first RTSP message; set fence so changes are kept for
1506 * subsequent RTSP messages.
1508 col_set_fence(pinfo
->cinfo
, COL_INFO
);
1510 return tvb_captured_length(tvb
);
1514 proto_register_rtsp(void)
1516 static int *ett
[] = {
1521 static hf_register_info hf
[] = {
1523 { "Request", "rtsp.request", FT_STRING
, BASE_NONE
, NULL
, 0,
1525 { &hf_rtsp_response
,
1526 { "Response", "rtsp.response", FT_STRING
, BASE_NONE
, NULL
, 0,
1529 { "Method", "rtsp.method", FT_STRING
, BASE_NONE
, NULL
, 0,
1531 { &hf_rtsp_content_type
,
1532 { "Content-type", "rtsp.content-type", FT_STRING
, BASE_NONE
, NULL
, 0,
1534 { &hf_rtsp_content_length
,
1535 { "Content-length", "rtsp.content-length", FT_UINT32
, BASE_DEC
, NULL
, 0,
1538 { "URL", "rtsp.url", FT_STRING
, BASE_NONE
, NULL
, 0,
1541 { "Status", "rtsp.status", FT_UINT32
, BASE_DEC
, NULL
, 0,
1544 { "Session", "rtsp.session", FT_STRING
, BASE_NONE
, NULL
, 0,
1546 { &hf_rtsp_transport
,
1547 { "Transport", "rtsp.transport", FT_STRING
, BASE_NONE
, NULL
, 0,
1549 { &hf_rtsp_rdtfeaturelevel
,
1550 { "RDTFeatureLevel", "rtsp.rdt-feature-level", FT_UINT32
, BASE_DEC
, NULL
, 0,
1552 { &hf_rtsp_X_Vig_Msisdn
,
1553 { "X-Vig-Msisdn", "rtsp.X_Vig_Msisdn", FT_STRING
, BASE_NONE
, NULL
, 0,
1556 { "Magic", "rtsp.magic", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1559 { "Channel", "rtsp.channel", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1562 { "Length", "rtsp.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1565 { "Data", "rtsp.data", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1569 static ei_register_info ei
[] = {
1570 { &ei_rtsp_unknown_transport_type
,
1571 { "rtsp.unknown_transport_type", PI_UNDECODED
, PI_WARN
, "Unknown transport type", EXPFILL
}},
1572 { &ei_rtsp_bad_server_port
,
1573 { "rtsp.bad_server_port", PI_UNDECODED
, PI_WARN
, "Bad server_port", EXPFILL
}},
1574 { &ei_rtsp_bad_client_port
,
1575 { "rtsp.bad_client_port", PI_UNDECODED
, PI_WARN
, "Bad client port", EXPFILL
}},
1576 { &ei_rtsp_bad_interleaved_channel
,
1577 { "rtsp.bad_interleaved_channel", PI_UNDECODED
, PI_WARN
, "Bad interleaved_channel", EXPFILL
}},
1578 { &ei_rtsp_content_length_invalid
,
1579 { "rtsp.content-length.invalid", PI_MALFORMED
, PI_ERROR
, "Invalid content length", EXPFILL
}},
1580 { &ei_rtsp_rdtfeaturelevel_invalid
,
1581 { "rtsp.rdt-feature-level.invalid", PI_MALFORMED
, PI_ERROR
, "Invalid RDTFeatureLevel", EXPFILL
}},
1582 { &ei_rtsp_bad_server_ip_address
,
1583 { "rtsp.bad_server_ip_address", PI_MALFORMED
, PI_ERROR
, "Bad server IP address", EXPFILL
}},
1584 { &ei_rtsp_bad_client_ip_address
,
1585 { "rtsp.bad_client_ip_address", PI_MALFORMED
, PI_ERROR
, "Bad client IP address", EXPFILL
}}
1588 module_t
*rtsp_module
;
1589 expert_module_t
*expert_rtsp
;
1591 proto_rtsp
= proto_register_protocol("Real Time Streaming Protocol", "RTSP", "rtsp");
1593 proto_register_field_array(proto_rtsp
, hf
, array_length(hf
));
1594 proto_register_subtree_array(ett
, array_length(ett
));
1596 expert_rtsp
= expert_register_protocol(proto_rtsp
);
1597 expert_register_field_array(expert_rtsp
, ei
, array_length(ei
));
1599 /* Make this dissector findable by name */
1600 rtsp_handle
= register_dissector("rtsp", dissect_rtsp
, proto_rtsp
);
1602 /* Register our configuration options, particularly our ports */
1604 rtsp_module
= prefs_register_protocol(proto_rtsp
, NULL
);
1606 prefs_register_obsolete_preference(rtsp_module
, "tcp.alternate_port");
1608 prefs_register_bool_preference(rtsp_module
, "desegment_headers",
1609 "Reassemble RTSP headers spanning multiple TCP segments",
1610 "Whether the RTSP dissector should reassemble headers "
1611 "of a request spanning multiple TCP segments. "
1612 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1613 &rtsp_desegment_headers
);
1614 prefs_register_bool_preference(rtsp_module
, "desegment_body",
1615 "Trust the \"Content-length:\" header when desegmenting",
1616 "Whether the RTSP dissector should use the "
1617 "\"Content-length:\" value to desegment the body "
1618 "of a request spanning multiple TCP segments",
1619 &rtsp_desegment_body
);
1622 * Heuristic dissectors SHOULD register themselves in
1623 * this table using the standard heur_dissector_add()
1626 heur_subdissector_list
= register_heur_dissector_list_with_description("rtsp", "RTSP data", proto_rtsp
);
1629 * Register for tapping
1631 rtsp_tap
= register_tap("rtsp"); /* RTSP statistics tap */
1635 proto_reg_handoff_rtsp(void)
1637 rtp_handle
= find_dissector_add_dependency("rtp", proto_rtsp
);
1638 rtp_rfc4571_handle
= find_dissector_add_dependency("rtp.rfc4571", proto_rtsp
);
1639 rtcp_handle
= find_dissector_add_dependency("rtcp", proto_rtsp
);
1640 rdt_handle
= find_dissector_add_dependency("rdt", proto_rtsp
);
1641 media_type_dissector_table
= find_dissector_table("media_type");
1642 voip_tap
= find_tap_id("voip");
1644 /* Set our port number for future use */
1645 dissector_add_uint_range_with_preference("tcp.port", RTSP_TCP_PORT_RANGE
, rtsp_handle
);
1647 /* XXX: Do the following only once ?? */
1648 stats_tree_register("rtsp","rtsp","RTSP" STATS_TREE_MENU_SEPARATOR
"Packet Counter", 0, rtsp_stats_tree_packet
, rtsp_stats_tree_init
, NULL
);
1653 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1658 * indent-tabs-mode: space
1661 * vi: set shiftwidth=4 tabstop=8 expandtab:
1662 * :indentSize=4:tabSize=8:noTabs=true: