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>
34 #include "packet-rdt.h"
35 #include "packet-rtp.h"
36 #include "packet-rtcp.h"
37 #include "packet-e164.h"
38 #include "packet-rtsp.h"
40 void proto_register_rtsp(void);
43 static rtsp_info_value_t
*rtsp_stat_info
;
45 /* http://www.iana.org/assignments/rtsp-parameters/rtsp-parameters.xml */
47 const value_string rtsp_status_code_vals
[] = {
49 { 199, "Informational - Others" },
53 { 250, "Low on Storage Space"},
54 { 299, "Success - Others"},
56 { 300, "Multiple Choices"},
57 { 301, "Moved Permanently"},
58 { 302, "Moved Temporarily"},
61 { 399, "Redirection - Others"},
63 { 400, "Bad Request"},
64 { 401, "Unauthorized"},
65 { 402, "Payment Required"},
68 { 405, "Method Not Allowed"},
69 { 406, "Not Acceptable"},
70 { 407, "Proxy Authentication Required"},
71 { 408, "Request Timeout"},
73 { 411, "Length Required"},
74 { 412, "Precondition Failed"},
75 { 413, "Request Entity Too Large"},
76 { 414, "Request-URI Too Long"},
77 { 415, "Unsupported Media Type"},
78 { 451, "Invalid Parameter"},
79 { 452, "Illegal Conference Identifier"},
80 { 453, "Not Enough Bandwidth"},
81 { 454, "Session Not Found"},
82 { 455, "Method Not Valid In This State"},
83 { 456, "Header Field Not Valid"},
84 { 457, "Invalid Range"},
85 { 458, "Parameter Is Read-Only"},
86 { 459, "Aggregate Operation Not Allowed"},
87 { 460, "Only Aggregate Operation Allowed"},
88 { 461, "Unsupported Transport"},
89 { 462, "Destination Unreachable"},
90 { 499, "Client Error - Others"},
92 { 500, "Internal Server Error"},
93 { 501, "Not Implemented"},
94 { 502, "Bad Gateway"},
95 { 503, "Service Unavailable"},
96 { 504, "Gateway Timeout"},
97 { 505, "RTSP Version not supported"},
98 { 551, "Option Not Support"},
99 { 599, "Server Error - Others"},
104 static int proto_rtsp
;
107 static int ett_rtspframe
;
108 static int ett_rtsp_method
;
110 static int hf_rtsp_request
;
111 static int hf_rtsp_response
;
112 static int hf_rtsp_content_type
;
113 static int hf_rtsp_content_length
;
114 static int hf_rtsp_method
;
115 static int hf_rtsp_url
;
116 static int hf_rtsp_status
;
117 static int hf_rtsp_session
;
118 static int hf_rtsp_transport
;
119 static int hf_rtsp_rdtfeaturelevel
;
120 static int hf_rtsp_X_Vig_Msisdn
;
121 static int hf_rtsp_magic
;
122 static int hf_rtsp_channel
;
123 static int hf_rtsp_length
;
124 static int hf_rtsp_data
;
128 static expert_field ei_rtsp_unknown_transport_type
;
129 static expert_field ei_rtsp_bad_server_port
;
130 static expert_field ei_rtsp_bad_client_port
;
131 static expert_field ei_rtsp_bad_interleaved_channel
;
132 static expert_field ei_rtsp_content_length_invalid
;
133 static expert_field ei_rtsp_rdtfeaturelevel_invalid
;
134 static expert_field ei_rtsp_bad_server_ip_address
;
135 static expert_field ei_rtsp_bad_client_ip_address
;
137 static dissector_handle_t rtsp_handle
;
138 static dissector_handle_t rtp_handle
;
139 static dissector_handle_t rtp_rfc4571_handle
;
140 static dissector_handle_t rtcp_handle
;
141 static dissector_handle_t rdt_handle
;
142 static dissector_table_t media_type_dissector_table
;
143 static heur_dissector_list_t heur_subdissector_list
;
145 static const char *st_str_packets
= "Total RTSP Packets";
146 static const char *st_str_requests
= "RTSP Request Packets";
147 static const char *st_str_responses
= "RTSP Response Packets";
148 static const char *st_str_resp_broken
= "???: broken";
149 static const char *st_str_resp_100
= "1xx: Informational";
150 static const char *st_str_resp_200
= "2xx: Success";
151 static const char *st_str_resp_300
= "3xx: Redirection";
152 static const char *st_str_resp_400
= "4xx: Client Error";
153 static const char *st_str_resp_500
= "5xx: Server Error";
154 static const char *st_str_other
= "Other RTSP Packets";
156 static int st_node_packets
= -1;
157 static int st_node_requests
= -1;
158 static int st_node_responses
= -1;
159 static int st_node_resp_broken
= -1;
160 static int st_node_resp_100
= -1;
161 static int st_node_resp_200
= -1;
162 static int st_node_resp_300
= -1;
163 static int st_node_resp_400
= -1;
164 static int st_node_resp_500
= -1;
165 static int st_node_other
= -1;
168 rtsp_stats_tree_init(stats_tree
* st
)
170 st_node_packets
= stats_tree_create_node(st
, st_str_packets
, 0, STAT_DT_INT
, true);
171 st_node_requests
= stats_tree_create_pivot(st
, st_str_requests
, st_node_packets
);
172 st_node_responses
= stats_tree_create_node(st
, st_str_responses
, st_node_packets
, STAT_DT_INT
, true);
173 st_node_resp_broken
= stats_tree_create_node(st
, st_str_resp_broken
, st_node_responses
, STAT_DT_INT
, true);
174 st_node_resp_100
= stats_tree_create_node(st
, st_str_resp_100
, st_node_responses
, STAT_DT_INT
, true);
175 st_node_resp_200
= stats_tree_create_node(st
, st_str_resp_200
, st_node_responses
, STAT_DT_INT
, true);
176 st_node_resp_300
= stats_tree_create_node(st
, st_str_resp_300
, st_node_responses
, STAT_DT_INT
, true);
177 st_node_resp_400
= stats_tree_create_node(st
, st_str_resp_400
, st_node_responses
, STAT_DT_INT
, true);
178 st_node_resp_500
= stats_tree_create_node(st
, st_str_resp_500
, st_node_responses
, STAT_DT_INT
, true);
179 st_node_other
= stats_tree_create_node(st
, st_str_other
, st_node_packets
, STAT_DT_INT
, false);
182 /* RTSP/Packet Counter stats packet function */
183 static tap_packet_status
184 rtsp_stats_tree_packet(stats_tree
* st
, packet_info
* pinfo _U_
, epan_dissect_t
* edt _U_
, const void* p
, tap_flags_t flags _U_
)
186 const rtsp_info_value_t
*v
= (const rtsp_info_value_t
*)p
;
187 unsigned i
= v
->response_code
;
189 const char *resp_str
;
192 tick_stat_node(st
, st_str_packets
, 0, false);
195 tick_stat_node(st
, st_str_responses
, st_node_packets
, false);
197 if ( (i
<100)||(i
>=600) ) {
198 resp_grp
= st_node_resp_broken
;
199 resp_str
= st_str_resp_broken
;
201 resp_grp
= st_node_resp_100
;
202 resp_str
= st_str_resp_100
;
204 resp_grp
= st_node_resp_200
;
205 resp_str
= st_str_resp_200
;
207 resp_grp
= st_node_resp_300
;
208 resp_str
= st_str_resp_300
;
210 resp_grp
= st_node_resp_400
;
211 resp_str
= st_str_resp_400
;
213 resp_grp
= st_node_resp_500
;
214 resp_str
= st_str_resp_500
;
217 tick_stat_node(st
, resp_str
, st_node_responses
, false);
219 snprintf(str
, sizeof(str
),"%u %s",i
,val_to_str(i
,rtsp_status_code_vals
, "Unknown (%d)"));
220 tick_stat_node(st
, str
, resp_grp
, false);
221 } else if (v
->request_method
) {
222 stats_tree_tick_pivot(st
,st_node_requests
,v
->request_method
);
224 tick_stat_node(st
, st_str_other
, st_node_packets
, false);
227 return TAP_PACKET_REDRAW
;
229 void proto_reg_handoff_rtsp(void);
232 * desegmentation of RTSP headers
233 * (when we are over TCP or another protocol providing the desegmentation API)
235 static bool rtsp_desegment_headers
= true;
238 * desegmentation of RTSP bodies
239 * (when we are over TCP or another protocol providing the desegmentation API)
240 * TODO let the user filter on content-type the bodies he wants desegmented
242 static bool rtsp_desegment_body
= true;
244 /* http://www.iana.org/assignments/port-numbers lists two rtsp ports.
245 * In Addition RTSP uses display port over Wi-Fi Display: 7236.
247 #define RTSP_TCP_PORT_RANGE "554,8554,7236"
250 * Takes an array of bytes, assumed to contain a null-terminated
251 * string, as an argument, and returns the length of the string -
252 * i.e., the size of the array, minus 1 for the null terminator.
254 #define STRLEN_CONST(str) (sizeof (str) - 1)
256 #define RTSP_FRAMEHDR ('$')
259 dissector_handle_t dissector
;
260 } rtsp_interleaved_t
;
262 #define RTSP_MAX_INTERLEAVED (256)
265 * Careful about dynamically allocating memory in this structure (say
266 * for dynamically increasing the size of the 'interleaved' array) -
267 * the containing structure is garbage collected and contained
268 * pointers will not be freed.
271 rtsp_interleaved_t interleaved
[RTSP_MAX_INTERLEAVED
];
272 } rtsp_conversation_data_t
;
275 dissect_rtspinterleaved(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
278 unsigned length_remaining
;
280 proto_tree
*rtspframe_tree
= NULL
;
282 uint8_t rf_chan
; /* interleaved channel id */
283 uint16_t rf_len
; /* packet length */
285 conversation_t
*conv
;
286 rtsp_conversation_data_t
*data
;
287 dissector_handle_t dissector
;
290 * This will throw an exception if we don't have any data left.
291 * That's what we want. (See "tcp_dissect_pdus()", which is
294 length_remaining
= tvb_ensure_captured_length_remaining(tvb
, offset
);
297 * Can we do reassembly?
299 if (rtsp_desegment_headers
&& pinfo
->can_desegment
) {
301 * Yes - would an RTSP multiplexed header starting at
302 * this offset be split across segment boundaries?
304 if (length_remaining
< 4) {
306 * Yes. Tell the TCP dissector where the data for
307 * this message starts in the data it handed us and
308 * that we need "some more data." Don't tell it
309 * exactly how many bytes we need because if/when we
310 * ask for even more (after the header) that will
313 pinfo
->desegment_offset
= offset
;
314 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
320 * Get the "$", channel, and length from the header.
322 orig_offset
= offset
;
323 rf_chan
= tvb_get_uint8(tvb
, offset
+1);
324 rf_len
= tvb_get_ntohs(tvb
, offset
+2);
327 * Can we do reassembly?
329 if (rtsp_desegment_body
&& pinfo
->can_desegment
) {
331 * Yes - is the header + encapsulated packet split
332 * across segment boundaries?
334 if (length_remaining
< 4U + rf_len
) {
336 * Yes. Tell the TCP dissector where the data
337 * for this message starts in the data it handed
338 * us, and how many more bytes we need, and return.
340 pinfo
->desegment_offset
= offset
;
341 pinfo
->desegment_len
= 4U + rf_len
- length_remaining
;
346 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
347 "Interleaved channel 0x%02x, %u bytes",
350 ti
= proto_tree_add_protocol_format(tree
, proto_rtsp
, tvb
,
352 "RTSP Interleaved Frame, Channel: 0x%02x, %u bytes",
354 rtspframe_tree
= proto_item_add_subtree(ti
, ett_rtspframe
);
356 proto_tree_add_item(rtspframe_tree
, hf_rtsp_magic
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
360 proto_tree_add_item(rtspframe_tree
, hf_rtsp_channel
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
364 proto_tree_add_item(rtspframe_tree
, hf_rtsp_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
368 * We set the actual length of the tvbuff for the interleaved
369 * stuff to the minimum of what's left in the tvbuff and the
370 * length in the header.
372 * XXX - what if there's nothing left in the tvbuff?
373 * We'd want a BoundsError exception to be thrown, so
374 * that a Short Frame would be reported.
376 if (length_remaining
> rf_len
)
377 length_remaining
= rf_len
;
378 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length_remaining
, rf_len
);
380 conv
= find_conversation_pinfo(pinfo
, 0);
383 (data
= (rtsp_conversation_data_t
*)conversation_get_proto_data(conv
, proto_rtsp
)) &&
384 /* Add the following condition if it is not always true.
385 rf_chan < RTSP_MAX_INTERLEAVED &&
387 (dissector
= data
->interleaved
[rf_chan
].dissector
)) {
388 call_dissector(dissector
, next_tvb
, pinfo
, tree
);
390 bool dissected
= false;
391 heur_dtbl_entry_t
*hdtbl_entry
= NULL
;
393 dissected
= dissector_try_heuristic(heur_subdissector_list
,
394 next_tvb
, pinfo
, tree
, &hdtbl_entry
, NULL
);
397 proto_tree_add_item(rtspframe_tree
, hf_rtsp_data
, tvb
, offset
, rf_len
, ENC_NA
);
403 return offset
- orig_offset
;
406 static void process_rtsp_request(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
407 size_t linelen
, size_t next_line_offset
,
408 packet_info
*pinfo
, proto_tree
*tree
);
410 static void process_rtsp_reply(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
411 size_t linelen
, size_t next_line_offset
,
412 packet_info
*pinfo
, proto_tree
*tree
);
420 static const char *rtsp_methods
[] = {
434 #define RTSP_NMETHODS array_length(rtsp_methods)
437 is_rtsp_request_or_reply(const unsigned char *line
, size_t linelen
, rtsp_type_t
*type
)
440 const unsigned char *token
, *next_token
;
442 char response_chars
[4];
444 /* Is this an RTSP reply? */
445 if (linelen
>= 5 && g_ascii_strncasecmp("RTSP/", line
, 5) == 0) {
450 /* The first token is the version. */
451 tokenlen
= get_token_len(line
, line
+linelen
, &token
);
453 /* The next token is the status code. */
454 tokenlen
= get_token_len(token
, line
+linelen
, &next_token
);
456 memcpy(response_chars
, token
, 3);
457 response_chars
[3] = '\0';
458 ws_strtou32(response_chars
, NULL
, &rtsp_stat_info
->response_code
);
465 * Is this an RTSP request?
466 * Check whether the line begins with one of the RTSP request
469 for (ii
= 0; ii
< RTSP_NMETHODS
; ii
++) {
470 size_t len
= strlen(rtsp_methods
[ii
]);
471 if (linelen
>= len
&&
472 g_ascii_strncasecmp(rtsp_methods
[ii
], line
, len
) == 0 &&
473 (len
== linelen
|| g_ascii_isspace(line
[len
])))
475 *type
= RTSP_REQUEST
;
476 rtsp_stat_info
->request_method
=
477 wmem_strndup(wmem_packet_scope(), rtsp_methods
[ii
], len
+1);
482 /* Wasn't a request or a response */
483 *type
= RTSP_NOT_FIRST_LINE
;
487 static const char rtsp_content_type
[] = "Content-Type:";
488 static const char rtsp_transport
[] = "Transport:";
489 static const char rtsp_sps_server_port
[] = "server_port=";
490 static const char rtsp_cps_server_port
[] = "client_port=";
491 static const char rtsp_sps_dest_addr
[] = "dest_addr=";
492 static const char rtsp_cps_src_addr
[] = "src_addr=";
493 static const char rtsp_rtp_udp_default
[] = "rtp/avp";
494 static const char rtsp_rtp_udp
[] = "rtp/avp/udp";
495 static const char rtsp_rtp_tcp
[] = "rtp/avp/tcp";
496 static const char rtsp_rdt_feature_level
[] = "RDTFeatureLevel";
497 static const char rtsp_real_rdt
[] = "x-real-rdt/";
498 static const char rtsp_real_tng
[] = "x-pn-tng/"; /* synonym for x-real-rdt */
499 static const char rtsp_inter
[] = "interleaved=";
502 rtsp_create_conversation(packet_info
*pinfo
, proto_item
*ti
,
503 const unsigned char *line_begin
, size_t line_len
,
504 int rdt_feature_level
,
505 rtsp_type_t rtsp_type_packet
)
507 conversation_t
*conv
;
510 bool rtp_udp_transport
= false;
511 bool rtp_tcp_transport
= false;
512 bool rdt_transport
= false;
513 unsigned c_data_port
, c_mon_port
;
514 unsigned s_data_port
, s_mon_port
;
515 unsigned ipv4_1
, ipv4_2
, ipv4_3
, ipv4_4
;
516 bool is_video
= false; /* FIX ME - need to indicate video or not */
521 if (rtsp_type_packet
!= RTSP_REPLY
) {
528 /* Copy line into buf */
529 if (line_len
> sizeof(buf
) - 1)
531 /* Don't overflow the buffer. */
532 line_len
= sizeof(buf
) - 1;
534 memcpy(buf
, line_begin
, line_len
);
535 buf
[line_len
] = '\0';
537 /* Get past "Transport:" and spaces */
538 tmp
= buf
+ STRLEN_CONST(rtsp_transport
);
539 while (*tmp
&& g_ascii_isspace(*tmp
))
542 /* Work out which transport type is here */
543 if (g_ascii_strncasecmp(tmp
, rtsp_rtp_udp
, strlen(rtsp_rtp_udp
)) == 0)
545 rtp_udp_transport
= true;
547 else if (g_ascii_strncasecmp(tmp
, rtsp_rtp_tcp
, strlen(rtsp_rtp_tcp
)) == 0)
549 rtp_tcp_transport
= true;
551 else if (g_ascii_strncasecmp(tmp
, rtsp_rtp_udp_default
, strlen(rtsp_rtp_udp_default
)) == 0)
553 rtp_udp_transport
= true;
555 else if (g_ascii_strncasecmp(tmp
, rtsp_real_rdt
, strlen(rtsp_real_rdt
)) == 0 ||
556 g_ascii_strncasecmp(tmp
, rtsp_real_tng
, strlen(rtsp_real_tng
)) == 0)
558 rdt_transport
= true;
562 /* Give up on unknown transport types */
563 expert_add_info(pinfo
, ti
, &ei_rtsp_unknown_transport_type
);
567 c_data_port
= c_mon_port
= 0;
568 s_data_port
= s_mon_port
= 0;
570 /* Look for server port */
571 if ((tmp
= strstr(buf
, rtsp_sps_server_port
))) {
572 tmp
+= strlen(rtsp_sps_server_port
);
573 if (sscanf(tmp
, "%u-%u", &s_data_port
, &s_mon_port
) < 1) {
574 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_port
);
578 else if ((tmp
= strstr(buf
, rtsp_sps_dest_addr
))) {
579 tmp
+= strlen(rtsp_sps_dest_addr
);
580 if (sscanf(tmp
, "\":%u\"", &s_data_port
) == 1) {
582 if (s_data_port
== 9) {
586 else if (sscanf(tmp
, "\"%u.%u.%u.%u:%u\"", &ipv4_1
, &ipv4_2
, &ipv4_3
, &ipv4_4
, &s_data_port
) == 5) {
592 tmp2
=strstr(tmp
,":");
593 tmp3
=g_strndup(tmp
,tmp2
-tmp
);
594 if (!str_to_ip(tmp3
, &ip4_addr
)) {
596 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_ip_address
);
599 set_address(&dst_addr
, AT_IPv4
, 4, &ip4_addr
);
602 else if (sscanf(tmp
, "\"%u.%u.%u.%u\"", &ipv4_1
, &ipv4_2
, &ipv4_3
, &ipv4_4
) == 4) {
608 tmp2
=strstr(tmp
,"\"");
609 tmp3
=g_strndup(tmp
,tmp2
-tmp
);
610 if (!str_to_ip(tmp3
, &ip4_addr
)) {
612 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_ip_address
);
615 set_address(&dst_addr
, AT_IPv4
, 4, &ip4_addr
);
620 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_server_port
);
626 /* Look for client port */
627 if ((tmp
= strstr(buf
, rtsp_cps_server_port
))) {
628 tmp
+= strlen(rtsp_cps_server_port
);
629 if (sscanf(tmp
, "%u-%u", &c_data_port
, &c_mon_port
) < 1) {
630 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_client_port
);
634 else if ((tmp
= strstr(buf
, rtsp_cps_src_addr
))) {
635 tmp
+= strlen(rtsp_cps_src_addr
);
636 if (sscanf(tmp
, "\"%u.%u.%u.%u:%u\"", &ipv4_1
, &ipv4_2
, &ipv4_3
, &ipv4_4
, &c_data_port
) == 5) {
642 tmp2
=strstr(tmp
,":");
643 tmp3
=g_strndup(tmp
,tmp2
-tmp
);
644 if (!str_to_ip(tmp3
, &ip4_addr
)) {
646 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_client_ip_address
);
649 set_address(&src_addr
, AT_IPv4
, 4, &ip4_addr
);
654 /* Deal with RTSP TCP-interleaved conversations. */
655 tmp
= strstr(buf
, rtsp_inter
);
657 rtsp_conversation_data_t
*data
;
658 unsigned s_data_chan
, s_mon_chan
;
661 /* Move tmp to beyond interleaved string */
662 tmp
+= strlen(rtsp_inter
);
663 /* Look for channel number(s) */
664 i
= sscanf(tmp
, "%u-%u", &s_data_chan
, &s_mon_chan
);
667 expert_add_info(pinfo
, ti
, &ei_rtsp_bad_interleaved_channel
);
671 /* At least data channel present, look for conversation (presumably TCP) */
672 conv
= find_or_create_conversation(pinfo
);
674 /* Look for previous data */
675 data
= (rtsp_conversation_data_t
*)conversation_get_proto_data(conv
, proto_rtsp
);
677 /* Create new data if necessary */
680 data
= wmem_new0(wmem_file_scope(), rtsp_conversation_data_t
);
681 conversation_add_proto_data(conv
, proto_rtsp
, data
);
684 /* Now set the dissector handle of the interleaved channel
685 according to the transport protocol used */
686 if (rtp_tcp_transport
)
688 if (s_data_chan
< RTSP_MAX_INTERLEAVED
) {
689 data
->interleaved
[s_data_chan
].dissector
=
692 if (i
> 1 && s_mon_chan
< RTSP_MAX_INTERLEAVED
) {
693 data
->interleaved
[s_mon_chan
].dissector
=
697 else if (rdt_transport
)
699 if (s_data_chan
< RTSP_MAX_INTERLEAVED
) {
700 data
->interleaved
[s_data_chan
].dissector
=
706 /* Noninterleaved options follow */
708 * We only want to match on the destination address, not the
709 * source address, because the server might send back a packet
710 * from an address other than the address to which its client
711 * sent the packet, so we construct a conversation with no
714 else if (rtp_udp_transport
)
716 /* RTP only if indicated */
719 rtp_add_address(pinfo
, PT_UDP
, &dst_addr
, c_data_port
, s_data_port
,
720 "RTSP", pinfo
->num
, is_video
, NULL
);
722 else if (s_data_port
)
724 rtp_add_address(pinfo
, PT_UDP
, &src_addr
, s_data_port
, 0,
725 "RTSP", pinfo
->num
, is_video
, NULL
);
728 /* RTCP only if indicated */
731 rtcp_add_address(pinfo
, &pinfo
->dst
, c_mon_port
, s_mon_port
,
735 else if (rtp_tcp_transport
)
737 /* RTP only if indicated */
738 rtp_add_address(pinfo
, PT_TCP
, &src_addr
, c_data_port
, s_data_port
,
739 "RTSP", pinfo
->num
, is_video
, NULL
);
741 else if (rdt_transport
)
743 /* Real Data Transport */
744 rdt_add_address(pinfo
, &pinfo
->dst
, c_data_port
, s_data_port
,
745 "RTSP", rdt_feature_level
);
750 static const char rtsp_content_length
[] = "Content-Length:";
753 rtsp_get_content_length(const unsigned char *line_begin
, size_t line_len
)
757 int32_t content_length
;
761 if (line_len
> sizeof(buf
) - 1) {
763 * Don't overflow the buffer.
765 line_len
= sizeof(buf
) - 1;
767 memcpy(buf
, line_begin
, line_len
);
768 buf
[line_len
] = '\0';
770 tmp
= buf
+ STRLEN_CONST(rtsp_content_length
);
771 while (*tmp
&& g_ascii_isspace(*tmp
))
773 ws_strtoi32(tmp
, &p
, &content_length
);
775 if (up
== tmp
|| (*up
!= '\0' && !g_ascii_isspace(*up
)))
776 return -1; /* not a valid number */
777 return content_length
;
780 static const char rtsp_Session
[] = "Session:";
781 static const char rtsp_X_Vig_Msisdn
[] = "X-Vig-Msisdn";
784 dissect_rtspmessage(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
787 proto_tree
*rtsp_tree
= NULL
;
788 proto_tree
*sub_tree
= NULL
;
789 proto_item
*ti_top
= NULL
;
790 const unsigned char *line
;
792 const unsigned char *linep
, *lineend
;
794 int first_linelen
, linelen
;
797 bool is_request_or_reply
;
798 bool body_requires_content_len
;
799 bool saw_req_resp_or_header
;
801 rtsp_type_t rtsp_type_packet
;
802 rtsp_type_t rtsp_type_line
;
806 int reported_datalen
;
809 e164_info_t e164_info
;
810 int rdt_feature_level
= 0;
811 char *media_type_str_lower_case
= NULL
;
812 int semi_colon_offset
;
814 char *frame_label
= NULL
;
815 char *session_id
= NULL
;
816 voip_packet_info_t
*stat_info
= NULL
;
818 rtsp_stat_info
= wmem_new(pinfo
->pool
, rtsp_info_value_t
);
819 rtsp_stat_info
->framenum
= pinfo
->num
;
820 rtsp_stat_info
->response_code
= 0;
821 rtsp_stat_info
->request_method
= NULL
;
822 rtsp_stat_info
->request_uri
= NULL
;
823 rtsp_stat_info
->rtsp_host
= NULL
;
826 * Is this a request or response?
828 * Note that "tvb_find_line_end()" will return a value that
829 * is not longer than what's in the buffer, so the
830 * "tvb_get_ptr()" call won't throw an exception.
832 first_linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
835 * Is the first line a request or response?
837 line
= tvb_get_ptr(tvb
, offset
, first_linelen
);
838 is_request_or_reply
= is_rtsp_request_or_reply(line
, first_linelen
,
840 if (is_request_or_reply
) {
842 * Yes, it's a request or response.
843 * Do header desegmentation if we've been told to,
844 * and do body desegmentation if we've been told to and
845 * we find a Content-Length header.
847 * RFC 7826, Section 18.17. requires Content-Length and
848 * assumes zero if missing.
850 if (!req_resp_hdrs_do_reassembly(tvb
, offset
, pinfo
,
851 rtsp_desegment_headers
, rtsp_desegment_body
, false, NULL
,
854 * More data needed for desegmentation.
861 * RFC 2326 says that a content length must be specified
862 * in requests that have a body, although section 4.4 speaks
863 * of a server closing the connection indicating the end of
866 * To support pipelining, we check if line behind blank line
867 * looks like RTSP header. If so, we process rest of packet with
870 * If no, we assume that an absent content length in a request means
871 * that we don't have a body, and that an absent content length
872 * in a reply means that the reply body runs to the end of
873 * the connection. If the first line is neither, we assume
874 * that whatever follows a blank line should be treated as a
875 * body; there's not much else we can do, as we're jumping
876 * into the message in the middle.
878 * XXX - if there was no Content-Length entity header, we should
879 * accumulate all data until the end of the connection.
880 * That'd require that the TCP dissector call subdissectors
881 * for all frames with FIN, even if they contain no data,
882 * which would require subdissectors to deal intelligently
883 * with empty segments.
885 if (rtsp_type_packet
== RTSP_REQUEST
)
886 body_requires_content_len
= true;
888 body_requires_content_len
= false;
890 line
= tvb_get_ptr(tvb
, offset
, first_linelen
);
891 if (is_request_or_reply
) {
892 if ( rtsp_type_packet
== RTSP_REPLY
) {
893 frame_label
= wmem_strdup_printf(pinfo
->pool
,
894 "Reply: %s", format_text(pinfo
->pool
, line
, first_linelen
));
897 frame_label
= format_text(pinfo
->pool
, line
, first_linelen
);
901 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RTSP");
903 * Put the first line from the buffer into the summary
904 * if it's an RTSP request or reply (but leave out the
906 * Otherwise, just call it a continuation.
908 * Note that "tvb_find_line_end()" will return a value that
909 * is not longer than what's in the buffer, so the
910 * "tvb_get_ptr()" call won't throw an exception.
912 if (is_request_or_reply
)
913 if ( rtsp_type_packet
== RTSP_REPLY
) {
914 col_set_str(pinfo
->cinfo
, COL_INFO
, "Reply: ");
915 col_append_str(pinfo
->cinfo
, COL_INFO
,
916 format_text(pinfo
->pool
, line
, first_linelen
));
919 col_add_str(pinfo
->cinfo
, COL_INFO
,
920 format_text(pinfo
->pool
, line
, first_linelen
));
924 col_set_str(pinfo
->cinfo
, COL_INFO
, "Continuation");
926 orig_offset
= offset
;
928 ti_top
= proto_tree_add_item(tree
, proto_rtsp
, tvb
, offset
, -1,
930 rtsp_tree
= proto_item_add_subtree(ti_top
, ett_rtsp
);
934 * We haven't yet seen a Content-Length header.
939 * Process the packet data, a line at a time.
941 saw_req_resp_or_header
= false; /* haven't seen anything yet */
942 while (tvb_offset_exists(tvb
, offset
)) {
944 * We haven't yet concluded that this is a header.
949 * Find the end of the line.
951 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
954 line_end_offset
= offset
+ linelen
;
956 * colon_offset may be -1
958 colon_offset
= tvb_find_uint8(tvb
, offset
, linelen
, ':');
962 * Get a buffer that refers to the line.
964 line
= tvb_get_ptr(tvb
, offset
, linelen
);
965 lineend
= line
+ linelen
;
968 * OK, does it look like an RTSP request or response?
970 is_request_or_reply
= is_rtsp_request_or_reply(line
, linelen
, &rtsp_type_line
);
971 if (is_request_or_reply
)
975 * No. Does it look like a blank line (as would appear
976 * at the end of an RTSP request)?
979 goto is_rtsp
; /* Yes. */
982 * No. Does it look like a header?
985 while (linep
< lineend
) {
989 * This must be a CHAR, and must not be a CTL, to be part
990 * of a token; that means it must be printable ASCII.
992 * XXX - what about leading LWS on continuation
995 if (!g_ascii_isprint(c
))
1017 * It's a tspecial, so it's not
1018 * part of a token, so it's not
1019 * a field name for the beginning
1026 * This ends the token; we consider
1027 * this to be a header.
1035 * LWS (RFC-2616, 4.2); continue the previous
1043 * We haven't seen the colon, but everything else looks
1044 * OK for a header line.
1046 * If we've already seen an RTSP request or response
1047 * line, or a header line, and we're at the end of
1048 * the tvbuff, we assume this is an incomplete header
1049 * line. (We quit this loop after seeing a blank line,
1050 * so if we've seen a request or response line, or a
1051 * header line, this is probably more of the request
1052 * or response we're presumably seeing. There is some
1053 * risk of false positives, but the same applies for
1054 * full request or response lines or header lines,
1055 * although that's less likely.)
1057 * We throw an exception in that case, by checking for
1058 * the existence of the next byte after the last one
1059 * in the line. If it exists, "tvb_ensure_bytes_exist()"
1060 * throws no exception, and we fall through to the
1061 * "not RTSP" case. If it doesn't exist,
1062 * "tvb_ensure_bytes_exist()" will throw the appropriate
1065 if (saw_req_resp_or_header
)
1066 tvb_ensure_bytes_exist(tvb
, offset
, linelen
+ 1);
1070 * We don't consider this part of an RTSP request or
1071 * reply, so we don't display it.
1077 * Process this line.
1081 * This is a blank line, which means that
1082 * whatever follows it isn't part of this
1085 proto_tree_add_format_text(rtsp_tree
, tvb
, offset
, next_offset
- offset
);
1086 offset
= next_offset
;
1091 * Not a blank line - either a request, a reply, or a header
1094 saw_req_resp_or_header
= true;
1097 switch (rtsp_type_line
)
1100 process_rtsp_request(tvb
, offset
, line
, linelen
, next_offset
, pinfo
, rtsp_tree
);
1104 process_rtsp_reply(tvb
, offset
, line
, linelen
, next_offset
, pinfo
, rtsp_tree
);
1107 case RTSP_NOT_FIRST_LINE
:
1108 /* Drop through, it may well be a header line */
1115 /* We know that colon_offset must be set */
1117 /* Skip whitespace after the colon. */
1118 value_offset
= colon_offset
+ 1;
1119 while ((value_offset
< line_end_offset
) &&
1120 ((c
= tvb_get_uint8(tvb
, value_offset
)) == ' ' || c
== '\t'))
1124 value_len
= line_end_offset
- value_offset
;
1127 * Process some headers specially.
1129 #define HDR_MATCHES(header) \
1130 ( (size_t)linelen > STRLEN_CONST(header) && \
1131 g_ascii_strncasecmp(line, (header), STRLEN_CONST(header)) == 0)
1133 if (HDR_MATCHES(rtsp_transport
))
1136 ti
= proto_tree_add_string(rtsp_tree
, hf_rtsp_transport
, tvb
,
1138 tvb_format_text(pinfo
->pool
, tvb
, value_offset
,
1142 * Based on the port numbers specified
1143 * in the Transport: header, set up
1144 * a conversation that will be dissected
1145 * with the appropriate dissector.
1147 rtsp_create_conversation(pinfo
, ti
, line
, linelen
, rdt_feature_level
, rtsp_type_packet
);
1148 } else if (HDR_MATCHES(rtsp_content_type
))
1150 proto_tree_add_string(rtsp_tree
, hf_rtsp_content_type
,
1151 tvb
, offset
, linelen
,
1152 tvb_format_text(pinfo
->pool
, tvb
, value_offset
,
1155 offset
= offset
+ (int)STRLEN_CONST(rtsp_content_type
);
1157 offset
= tvb_skip_wsp(tvb
, offset
, value_len
);
1158 semi_colon_offset
= tvb_find_uint8(tvb
, value_offset
, value_len
, ';');
1159 if ( semi_colon_offset
!= -1) {
1160 /* m-parameter present */
1161 par_end_offset
= tvb_skip_wsp_return(tvb
, semi_colon_offset
-1);
1162 value_len
= par_end_offset
- offset
;
1165 media_type_str_lower_case
= ascii_strdown_inplace(
1166 (char *)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, value_len
, ENC_ASCII
));
1168 } else if (HDR_MATCHES(rtsp_content_length
))
1173 clength_valid
= ws_strtou32(tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
),
1175 pi
= proto_tree_add_uint(rtsp_tree
, hf_rtsp_content_length
,
1176 tvb
, offset
, linelen
, clength
);
1178 expert_add_info(pinfo
, pi
, &ei_rtsp_content_length_invalid
);
1181 * Only the amount specified by the
1182 * Content-Length: header should be treated
1185 content_length
= rtsp_get_content_length(line
, linelen
);
1187 } else if (HDR_MATCHES(rtsp_Session
))
1189 session_id
= tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
);
1190 /* Put the value into the protocol tree */
1191 proto_tree_add_string(rtsp_tree
, hf_rtsp_session
, tvb
,
1195 } else if (HDR_MATCHES(rtsp_X_Vig_Msisdn
)) {
1197 * Extract the X_Vig_Msisdn string
1199 if (colon_offset
!= -1)
1202 /* Put the value into the protocol tree */
1203 ti
= proto_tree_add_string(rtsp_tree
, hf_rtsp_X_Vig_Msisdn
,tvb
,
1205 tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
));
1206 sub_tree
= proto_item_add_subtree(ti
, ett_rtsp_method
);
1208 e164_info
.e164_number_type
= CALLING_PARTY_NUMBER
;
1209 e164_info
.nature_of_address
= 0;
1211 e164_info
.E164_number_str
= tvb_get_string_enc(pinfo
->pool
, tvb
, value_offset
,
1212 value_len
, ENC_ASCII
);
1213 e164_info
.E164_number_length
= value_len
;
1214 dissect_e164_number(tvb
, sub_tree
, value_offset
,
1215 value_len
, e164_info
);
1217 } else if (HDR_MATCHES(rtsp_rdt_feature_level
))
1219 bool rdt_feature_level_valid
;
1221 rdt_feature_level_valid
= ws_strtou32(tvb_format_text(pinfo
->pool
, tvb
, value_offset
, value_len
),
1222 NULL
, &rdt_feature_level
);
1223 pi
= proto_tree_add_uint(rtsp_tree
, hf_rtsp_rdtfeaturelevel
,
1224 tvb
, offset
, linelen
, rdt_feature_level
);
1225 if (!rdt_feature_level_valid
)
1226 expert_add_info(pinfo
, pi
, &ei_rtsp_rdtfeaturelevel_invalid
);
1230 /* Default case for headers. Show line as text */
1231 proto_tree_add_format_text(rtsp_tree
, tvb
, offset
, next_offset
- offset
);
1234 else if (rtsp_type_line
== RTSP_NOT_FIRST_LINE
)
1236 /* Catch-all for all other lines... Show line as text.
1237 TODO: should these be shown as errors? */
1238 proto_tree_add_format_text(rtsp_tree
, tvb
, offset
, next_offset
- offset
);
1241 offset
= next_offset
;
1245 stat_info
= wmem_new0(pinfo
->pool
, voip_packet_info_t
);
1246 stat_info
->protocol_name
= wmem_strdup(pinfo
->pool
, "RTSP");
1247 stat_info
->call_id
= session_id
;
1248 stat_info
->frame_label
= frame_label
;
1249 stat_info
->call_state
= VOIP_CALL_SETUP
;
1250 stat_info
->call_active_state
= VOIP_ACTIVE
;
1251 stat_info
->frame_comment
= frame_label
;
1252 tap_queue_packet(voip_tap
, pinfo
, stat_info
);
1256 * Have now read all of the lines of this message.
1258 * If a content length was supplied, the amount of data to be
1259 * processed as RTSP payload is the minimum of the content
1260 * length and the amount of data remaining in the frame.
1262 * If no content length was supplied (or if a bad content length
1263 * was supplied), the amount of data to be processed is the amount
1264 * of data remaining in the frame.
1266 datalen
= tvb_captured_length_remaining(tvb
, offset
);
1267 reported_datalen
= tvb_reported_length_remaining(tvb
, offset
);
1268 if (content_length
!= -1) {
1270 * Content length specified; display only that amount
1273 if (datalen
> content_length
)
1274 datalen
= content_length
;
1277 * XXX - limit the reported length in the tvbuff we'll
1278 * hand to a subdissector to be no greater than the
1281 * We really need both unreassembled and "how long it'd
1282 * be if it were reassembled" lengths for tvbuffs, so
1283 * that we throw the appropriate exceptions for
1284 * "not enough data captured" (running past the length),
1285 * "packet needed reassembly" (within the length but
1286 * running past the unreassembled length), and
1287 * "packet is malformed" (running past the reassembled
1290 if (reported_datalen
> content_length
)
1291 reported_datalen
= content_length
;
1294 * No content length specified; if this message doesn't
1295 * have a body if no content length is specified, process
1296 * nothing as payload.
1298 if (body_requires_content_len
)
1304 * There's stuff left over; process it.
1309 * Now create a tvbuff for the Content-type stuff and
1312 * The amount of data to be processed that's
1313 * available in the tvbuff is "datalen", which
1314 * is the minimum of the amount of data left in
1315 * the tvbuff and any specified content length.
1317 * The amount of data to be processed that's in
1318 * this frame, regardless of whether it was
1319 * captured or not, is "reported_datalen",
1320 * which, if no content length was specified,
1321 * is -1, i.e. "to the end of the frame.
1323 new_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, datalen
,
1327 * Check if next line is RTSP message - pipelining
1328 * If yes, stop processing and start next loop
1329 * If no, process rest of packet with dissectors
1331 first_linelen
= tvb_find_line_end(new_tvb
, 0, -1, &next_offset
, false);
1332 line
= tvb_get_ptr(new_tvb
, 0, first_linelen
);
1333 is_request_or_reply
= is_rtsp_request_or_reply(line
, first_linelen
,
1336 if (!is_request_or_reply
){
1337 if (media_type_str_lower_case
&&
1338 dissector_try_string(media_type_dissector_table
,
1339 media_type_str_lower_case
,
1340 new_tvb
, pinfo
, rtsp_tree
, NULL
)){
1344 * Fix up the top-level item so that it doesn't
1345 * include the SDP stuff.
1348 proto_item_set_len(ti_top
, offset
);
1350 if (tvb_get_uint8(tvb
, offset
) == RTSP_FRAMEHDR
) {
1352 * This is interleaved stuff; don't
1353 * treat it as raw data - set "datalen"
1354 * to 0, so we won't skip the offset
1355 * past it, which will cause our
1356 * caller to process that stuff itself.
1360 proto_tree_add_bytes_format(rtsp_tree
, hf_rtsp_data
, tvb
, offset
,
1361 datalen
, NULL
, "Data (%d bytes)",
1367 * We've processed "datalen" bytes worth of data
1368 * (which may be no data at all); advance the
1369 * offset past whatever data we've processed.
1375 tap_queue_packet(rtsp_tap
, pinfo
, rtsp_stat_info
);
1377 return offset
- orig_offset
;
1381 process_rtsp_request(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
1382 size_t linelen
, size_t next_line_offset
, packet_info
*pinfo
, proto_tree
*tree
)
1384 proto_tree
*sub_tree
;
1386 const unsigned char *lineend
= data
+ linelen
;
1388 const unsigned char *url
;
1389 const unsigned char *url_start
;
1390 unsigned char *tmp_url
;
1392 /* Request Methods */
1393 for (ii
= 0; ii
< RTSP_NMETHODS
; ii
++) {
1394 size_t len
= strlen(rtsp_methods
[ii
]);
1395 if (linelen
>= len
&&
1396 g_ascii_strncasecmp(rtsp_methods
[ii
], data
, len
) == 0 &&
1397 (len
== linelen
|| g_ascii_isspace(data
[len
])))
1400 if (ii
== RTSP_NMETHODS
) {
1402 * We got here because "is_rtsp_request_or_reply()" returned
1403 * RTSP_REQUEST, so we know one of the request methods
1404 * matched, so we "can't get here".
1406 DISSECTOR_ASSERT_NOT_REACHED();
1409 /* Add a tree for this request */
1410 ti
= proto_tree_add_string(tree
, hf_rtsp_request
, tvb
, offset
,
1411 (int) (next_line_offset
- offset
),
1412 tvb_format_text(pinfo
->pool
, tvb
, offset
, (int) (next_line_offset
- offset
)));
1413 sub_tree
= proto_item_add_subtree(ti
, ett_rtsp_method
);
1416 /* Add method name to tree */
1417 proto_tree_add_string(sub_tree
, hf_rtsp_method
, tvb
, offset
,
1418 (int) strlen(rtsp_methods
[ii
]), rtsp_methods
[ii
]);
1422 /* Skip method name again */
1423 while (url
< lineend
&& !g_ascii_isspace(*url
))
1426 while (url
< lineend
&& g_ascii_isspace(*url
))
1428 /* URL starts here */
1430 /* Scan to end of URL */
1431 while (url
< lineend
&& !g_ascii_isspace(*url
))
1433 /* Create a URL-sized buffer and copy contents */
1434 tmp_url
= format_text(pinfo
->pool
, url_start
, url
- url_start
);
1436 /* Add URL to tree */
1437 proto_tree_add_string(sub_tree
, hf_rtsp_url
, tvb
,
1438 offset
+ (int) (url_start
- data
), (int) (url
- url_start
), tmp_url
);
1441 /* Read first line of a reply message */
1443 process_rtsp_reply(tvbuff_t
*tvb
, int offset
, const unsigned char *data
,
1444 size_t linelen
, size_t next_line_offset
, packet_info
*pinfo
, proto_tree
*tree
)
1446 proto_tree
*sub_tree
;
1448 const unsigned char *lineend
= data
+ linelen
;
1449 const unsigned char *status
= data
;
1450 const unsigned char *status_start
;
1453 /* Add a tree for this request */
1454 ti
= proto_tree_add_string(tree
, hf_rtsp_response
, tvb
, offset
,
1455 (int) (next_line_offset
- offset
),
1456 tvb_format_text(pinfo
->pool
, tvb
, offset
, (int) (next_line_offset
- offset
)));
1457 sub_tree
= proto_item_add_subtree(ti
, ett_rtsp_method
);
1462 /* Skip protocol/version */
1463 while (status
< lineend
&& !g_ascii_isspace(*status
))
1466 while (status
< lineend
&& g_ascii_isspace(*status
))
1469 /* Actual code number now */
1470 status_start
= status
;
1472 while (status
< lineend
&& g_ascii_isdigit(*status
))
1473 status_i
= status_i
* 10 + *status
++ - '0';
1475 /* Add field to tree */
1476 proto_tree_add_uint(sub_tree
, hf_rtsp_status
, tvb
,
1477 offset
+ (int) (status_start
- data
),
1478 (int) (status
- status_start
), status_i
);
1482 dissect_rtsp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
1487 while (tvb_reported_length_remaining(tvb
, offset
) != 0) {
1489 * Add separator between multiple messages in column info text
1492 col_set_str(pinfo
->cinfo
, COL_INFO
, ", ");
1493 col_set_fence(pinfo
->cinfo
, COL_INFO
);
1495 len
= (tvb_get_uint8(tvb
, offset
) == RTSP_FRAMEHDR
)
1496 ? dissect_rtspinterleaved(tvb
, offset
, pinfo
, tree
)
1497 : dissect_rtspmessage(tvb
, offset
, pinfo
, tree
);
1503 * OK, we've set the Protocol and Info columns for the
1504 * first RTSP message; set fence so changes are kept for
1505 * subsequent RTSP messages.
1507 col_set_fence(pinfo
->cinfo
, COL_INFO
);
1509 return tvb_captured_length(tvb
);
1513 proto_register_rtsp(void)
1515 static int *ett
[] = {
1520 static hf_register_info hf
[] = {
1522 { "Request", "rtsp.request", FT_STRING
, BASE_NONE
, NULL
, 0,
1524 { &hf_rtsp_response
,
1525 { "Response", "rtsp.response", FT_STRING
, BASE_NONE
, NULL
, 0,
1528 { "Method", "rtsp.method", FT_STRING
, BASE_NONE
, NULL
, 0,
1530 { &hf_rtsp_content_type
,
1531 { "Content-type", "rtsp.content-type", FT_STRING
, BASE_NONE
, NULL
, 0,
1533 { &hf_rtsp_content_length
,
1534 { "Content-length", "rtsp.content-length", FT_UINT32
, BASE_DEC
, NULL
, 0,
1537 { "URL", "rtsp.url", FT_STRING
, BASE_NONE
, NULL
, 0,
1540 { "Status", "rtsp.status", FT_UINT32
, BASE_DEC
, NULL
, 0,
1543 { "Session", "rtsp.session", FT_STRING
, BASE_NONE
, NULL
, 0,
1545 { &hf_rtsp_transport
,
1546 { "Transport", "rtsp.transport", FT_STRING
, BASE_NONE
, NULL
, 0,
1548 { &hf_rtsp_rdtfeaturelevel
,
1549 { "RDTFeatureLevel", "rtsp.rdt-feature-level", FT_UINT32
, BASE_DEC
, NULL
, 0,
1551 { &hf_rtsp_X_Vig_Msisdn
,
1552 { "X-Vig-Msisdn", "rtsp.X_Vig_Msisdn", FT_STRING
, BASE_NONE
, NULL
, 0,
1555 { "Magic", "rtsp.magic", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1558 { "Channel", "rtsp.channel", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1561 { "Length", "rtsp.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1564 { "Data", "rtsp.data", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1568 static ei_register_info ei
[] = {
1569 { &ei_rtsp_unknown_transport_type
,
1570 { "rtsp.unknown_transport_type", PI_UNDECODED
, PI_WARN
, "Unknown transport type", EXPFILL
}},
1571 { &ei_rtsp_bad_server_port
,
1572 { "rtsp.bad_server_port", PI_UNDECODED
, PI_WARN
, "Bad server_port", EXPFILL
}},
1573 { &ei_rtsp_bad_client_port
,
1574 { "rtsp.bad_client_port", PI_UNDECODED
, PI_WARN
, "Bad client port", EXPFILL
}},
1575 { &ei_rtsp_bad_interleaved_channel
,
1576 { "rtsp.bad_interleaved_channel", PI_UNDECODED
, PI_WARN
, "Bad interleaved_channel", EXPFILL
}},
1577 { &ei_rtsp_content_length_invalid
,
1578 { "rtsp.content-length.invalid", PI_MALFORMED
, PI_ERROR
, "Invalid content length", EXPFILL
}},
1579 { &ei_rtsp_rdtfeaturelevel_invalid
,
1580 { "rtsp.rdt-feature-level.invalid", PI_MALFORMED
, PI_ERROR
, "Invalid RDTFeatureLevel", EXPFILL
}},
1581 { &ei_rtsp_bad_server_ip_address
,
1582 { "rtsp.bad_client_ip_address", PI_MALFORMED
, PI_ERROR
, "Bad server IP address", EXPFILL
}},
1583 { &ei_rtsp_bad_client_ip_address
,
1584 { "rtsp.bad_client_ip_address", PI_MALFORMED
, PI_ERROR
, "Bad client IP address", EXPFILL
}}
1587 module_t
*rtsp_module
;
1588 expert_module_t
*expert_rtsp
;
1590 proto_rtsp
= proto_register_protocol("Real Time Streaming Protocol", "RTSP", "rtsp");
1592 proto_register_field_array(proto_rtsp
, hf
, array_length(hf
));
1593 proto_register_subtree_array(ett
, array_length(ett
));
1595 expert_rtsp
= expert_register_protocol(proto_rtsp
);
1596 expert_register_field_array(expert_rtsp
, ei
, array_length(ei
));
1598 /* Make this dissector findable by name */
1599 rtsp_handle
= register_dissector("rtsp", dissect_rtsp
, proto_rtsp
);
1601 /* Register our configuration options, particularly our ports */
1603 rtsp_module
= prefs_register_protocol(proto_rtsp
, NULL
);
1605 prefs_register_obsolete_preference(rtsp_module
, "tcp.alternate_port");
1607 prefs_register_bool_preference(rtsp_module
, "desegment_headers",
1608 "Reassemble RTSP headers spanning multiple TCP segments",
1609 "Whether the RTSP dissector should reassemble headers "
1610 "of a request spanning multiple TCP segments. "
1611 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1612 &rtsp_desegment_headers
);
1613 prefs_register_bool_preference(rtsp_module
, "desegment_body",
1614 "Trust the \"Content-length:\" header when desegmenting",
1615 "Whether the RTSP dissector should use the "
1616 "\"Content-length:\" value to desegment the body "
1617 "of a request spanning multiple TCP segments",
1618 &rtsp_desegment_body
);
1621 * Heuristic dissectors SHOULD register themselves in
1622 * this table using the standard heur_dissector_add()
1625 heur_subdissector_list
= register_heur_dissector_list_with_description("rtsp", "RTSP data", proto_rtsp
);
1628 * Register for tapping
1630 rtsp_tap
= register_tap("rtsp"); /* RTSP statistics tap */
1634 proto_reg_handoff_rtsp(void)
1636 rtp_handle
= find_dissector_add_dependency("rtp", proto_rtsp
);
1637 rtp_rfc4571_handle
= find_dissector_add_dependency("rtp.rfc4571", proto_rtsp
);
1638 rtcp_handle
= find_dissector_add_dependency("rtcp", proto_rtsp
);
1639 rdt_handle
= find_dissector_add_dependency("rdt", proto_rtsp
);
1640 media_type_dissector_table
= find_dissector_table("media_type");
1641 voip_tap
= find_tap_id("voip");
1643 /* Set our port number for future use */
1644 dissector_add_uint_range_with_preference("tcp.port", RTSP_TCP_PORT_RANGE
, rtsp_handle
);
1646 /* XXX: Do the following only once ?? */
1647 stats_tree_register("rtsp","rtsp","RTSP" STATS_TREE_MENU_SEPARATOR
"Packet Counter", 0, rtsp_stats_tree_packet
, rtsp_stats_tree_init
, NULL
);
1652 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1657 * indent-tabs-mode: space
1660 * vi: set shiftwidth=4 tabstop=8 expandtab:
1661 * :indentSize=4:tabSize=8:noTabs=true: