2 * Routines for SDP packet disassembly (RFC 2327)
4 * Jason Lango <jal@netapp.com>
5 * Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Ref http://www.ietf.org/rfc/rfc4566.txt?number=4566
35 #ifdef HAVE_SYS_TYPES_H
36 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
44 #ifdef HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
48 #ifdef HAVE_WINSOCK2_H
49 #include <winsock2.h> /* needed to define AF_ values on Windows */
52 #ifdef NEED_INET_V6DEFS_H
53 # include "wsutil/inet_v6defs.h"
57 #include <epan/packet.h>
58 #include <epan/strutil.h>
59 #include <epan/emem.h>
60 #include <epan/base64.h>
61 #include <epan/asn1.h>
64 #include "packet-sdp.h"
66 #include "packet-rtp.h"
67 #include <epan/rtp_pt.h>
69 #include <epan/prefs.h>
70 #include <epan/expert.h>
72 #include "packet-rtcp.h"
73 #include "packet-t38.h"
74 #include "packet-msrp.h"
75 #include "packet-per.h"
76 #include "packet-h245.h"
77 #include "packet-h264.h"
78 #include "packet-mp4ves.h"
80 static dissector_handle_t rtp_handle = NULL;
81 static dissector_handle_t rtcp_handle = NULL;
82 static dissector_handle_t t38_handle = NULL;
83 static dissector_handle_t msrp_handle = NULL;
84 static dissector_handle_t h264_handle = NULL;
85 static dissector_handle_t mp4ves_handle = NULL;
87 static int sdp_tap = -1;
89 static int proto_sdp = -1;
91 /* preference globals */
92 static gboolean global_sdp_establish_conversation = TRUE;
94 /* Top level fields */
95 static int hf_protocol_version = -1;
96 static int hf_owner = -1;
97 static int hf_session_name = -1;
98 static int hf_session_info = -1;
99 static int hf_uri = -1;
100 static int hf_email = -1;
101 static int hf_phone = -1;
102 static int hf_connection_info = -1;
103 static int hf_bandwidth = -1;
104 static int hf_timezone = -1;
105 static int hf_encryption_key = -1;
106 static int hf_session_attribute = -1;
107 static int hf_media_attribute = -1;
108 static int hf_time = -1;
109 static int hf_repeat_time = -1;
110 static int hf_media = -1;
111 static int hf_media_title = -1;
112 static int hf_unknown = -1;
113 static int hf_invalid = -1;
114 static int hf_ipbcp_version = -1;
115 static int hf_ipbcp_type = -1;
117 /* hf_owner subfields*/
118 static int hf_owner_username = -1;
119 static int hf_owner_sessionid = -1;
120 static int hf_owner_version = -1;
121 static int hf_owner_network_type = -1;
122 static int hf_owner_address_type = -1;
123 static int hf_owner_address = -1;
125 /* hf_connection_info subfields */
126 static int hf_connection_info_network_type = -1;
127 static int hf_connection_info_address_type = -1;
128 static int hf_connection_info_connection_address = -1;
129 static int hf_connection_info_ttl = -1;
130 static int hf_connection_info_num_addr = -1;
132 /* hf_bandwidth subfields */
133 static int hf_bandwidth_modifier = -1;
134 static int hf_bandwidth_value = -1;
136 /* hf_time subfields */
137 static int hf_time_start = -1;
138 static int hf_time_stop = -1;
140 /* hf_repeat_time subfield */
141 static int hf_repeat_time_interval = -1;
142 static int hf_repeat_time_duration = -1;
143 static int hf_repeat_time_offset = -1;
145 /* hf_timezone subfields */
146 static int hf_timezone_time = -1;
147 static int hf_timezone_offset = -1;
149 /* hf_encryption_key subfields */
150 static int hf_encryption_key_type = -1;
151 static int hf_encryption_key_data = -1;
153 /* hf_session_attribute subfields */
154 static int hf_session_attribute_field = -1;
155 static int hf_session_attribute_value = -1;
157 /* hf_media subfields */
158 static int hf_media_media = -1;
159 static int hf_media_port = -1;
160 static int hf_media_portcount = -1;
161 static int hf_media_proto = -1;
162 static int hf_media_format = -1;
164 /* hf_session_attribute subfields */
165 static int hf_media_attribute_field = -1;
166 static int hf_media_attribute_value = -1;
167 static int hf_media_encoding_name = -1;
168 static int hf_media_sample_rate = -1;
169 static int hf_media_format_specific_parameter = -1;
170 static int hf_sdp_fmtp_mpeg4_profile_level_id = -1;
171 static int hf_sdp_fmtp_h263_profile = -1;
172 static int hf_sdp_fmtp_h263_level = -1;
173 static int hf_sdp_h264_packetization_mode = -1;
174 static int hf_sdp_h264_sprop_parameter_sets = -1;
175 static int hf_SDPh223LogicalChannelParameters = -1;
177 /* hf_session_attribute hf_media_attribute subfields */
178 static int hf_key_mgmt_att_value = -1;
179 static int hf_key_mgmt_prtcl_id = -1;
180 static int hf_key_mgmt_data = -1;
183 static int ett_sdp = -1;
184 static int ett_sdp_owner = -1;
185 static int ett_sdp_connection_info = -1;
186 static int ett_sdp_bandwidth = -1;
187 static int ett_sdp_time = -1;
188 static int ett_sdp_repeat_time = -1;
189 static int ett_sdp_timezone = -1;
190 static int ett_sdp_encryption_key = -1;
191 static int ett_sdp_session_attribute = -1;
192 static int ett_sdp_media = -1;
193 static int ett_sdp_media_attribute = -1;
194 static int ett_sdp_fmtp = -1;
195 static int ett_sdp_key_mgmt = -1;
198 #define SDP_MAX_RTP_CHANNELS 4
199 #define SDP_MAX_RTP_PAYLOAD_TYPES 20
200 #define SDP_NO_OF_PT 128
202 gint32 pt[SDP_MAX_RTP_PAYLOAD_TYPES];
204 GHashTable *rtp_dyn_payload;
205 } transport_media_pt_t;
208 char *connection_address;
209 char *connection_type;
211 char *encoding_name[SDP_NO_OF_PT];
212 int sample_rate[SDP_NO_OF_PT];
213 char *media_port[SDP_MAX_RTP_CHANNELS];
214 char *media_proto[SDP_MAX_RTP_CHANNELS];
215 transport_media_pt_t media[SDP_MAX_RTP_CHANNELS];
220 /* MSRP transport info (as set while parsing path attribute) */
221 static gboolean msrp_transport_address_set = FALSE;
222 static guint32 msrp_ipaddr[4];
223 static guint16 msrp_port_number;
225 /* key-mgmt dissector
227 * http://www.iana.org/assignments/sdp-parameters
229 static dissector_table_t key_mgmt_dissector_table;
232 /* Protocol registration */
233 void proto_register_sdp(void);
234 void proto_reg_handoff_sdp(void);
237 /* static functions */
239 static void call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, int lenght,
240 transport_info_t *transport_info);
242 /* Subdissector functions */
243 static void dissect_sdp_owner(tvbuff_t *tvb, proto_item* ti);
244 static void dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
245 transport_info_t *transport_info);
246 static void dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti);
247 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti);
248 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti);
249 static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti);
250 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti);
251 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti);
252 static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
253 transport_info_t *transport_info);
254 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti, int length,transport_info_t *transport_info);
256 static void free_encoding_name_str (void *ptr)
258 encoding_name_and_rate_t *encoding_name_and_rate = (encoding_name_and_rate_t *)ptr;
260 if (encoding_name_and_rate->encoding_name) {
261 g_free(encoding_name_and_rate->encoding_name);
266 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
268 proto_tree *sdp_tree;
269 proto_item *ti, *sub_ti;
273 gboolean in_media_description;
283 transport_info_t transport_info;
286 gboolean is_rtp=FALSE;
287 gboolean is_srtp=FALSE;
288 gboolean is_t38=FALSE;
289 gboolean is_msrp=FALSE;
290 gboolean set_rtp=FALSE;
291 gboolean is_ipv4_addr=FALSE;
292 gboolean is_ipv6_addr=FALSE;
293 gboolean is_video=FALSE;
296 sdp_packet_info *sdp_pi;
297 gchar *unknown_encoding = ep_strdup("Unknown");
299 /* Initialise packet info for passing to tap */
300 sdp_pi = ep_alloc(sizeof(sdp_packet_info));
301 sdp_pi->summary_str[0] = '\0';
303 /* Initialise RTP channel info */
304 transport_info.connection_address=NULL;
305 transport_info.connection_type=NULL;
306 transport_info.media_type=NULL;
307 for (n=0; n < SDP_NO_OF_PT; n++){
308 transport_info.encoding_name[n]=unknown_encoding;
309 transport_info.sample_rate[n] = 0;
311 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++)
313 transport_info.media_port[n]=NULL;
314 transport_info.media_proto[n]=NULL;
315 transport_info.media[n].pt_count = 0;
316 transport_info.media[n].rtp_dyn_payload =
317 g_hash_table_new_full( g_int_hash, g_int_equal, g_free, free_encoding_name_str);
319 transport_info.media_count = 0;
322 * As RFC 2327 says, "SDP is purely a format for session
323 * description - it does not incorporate a transport protocol,
324 * and is intended to use different transport protocols as
325 * appropriate including the Session Announcement Protocol,
326 * Session Initiation Protocol, Real-Time Streaming Protocol,
327 * electronic mail using the MIME extensions, and the
328 * Hypertext Transport Protocol."
330 * We therefore don't set the protocol or info columns;
331 * instead, we append to them, so that we don't erase
332 * what the protocol inside which the SDP stuff resides
335 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
337 /* XXX: Needs description. */
338 col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
340 ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
341 sdp_tree = proto_item_add_subtree(ti, ett_sdp);
344 * Show the SDP message a line at a time.
346 in_media_description = FALSE;
348 while (tvb_reported_length_remaining(tvb, offset) > 0) {
350 * Find the end of the line.
352 linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
357 * Line must contain at least e.g. "v=".
362 type = tvb_get_guint8(tvb,offset);
363 delim = tvb_get_guint8(tvb,offset + 1);
365 proto_item *ti2 = proto_tree_add_item(sdp_tree, hf_invalid, tvb, offset, linelen, FALSE);
366 expert_add_info_format(pinfo, ti2, PI_MALFORMED, PI_NOTE,
367 "Invalid SDP line (no '=' delimiter)");
368 offset = next_offset;
377 hf = hf_protocol_version;
383 hf = hf_session_name;
386 if (in_media_description) {
390 hf = hf_session_info;
403 hf = hf_connection_info;
416 in_media_description = TRUE;
419 hf = hf_encryption_key;
422 if (in_media_description) {
423 hf = hf_media_attribute;
426 hf = hf_session_attribute;
437 if (hf == hf_unknown)
439 string = (char*)tvb_get_ephemeral_string(tvb, offset + tokenoffset,
440 linelen - tokenoffset);
441 sub_ti = proto_tree_add_string(sdp_tree, hf, tvb, offset, linelen,
443 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
445 linelen-tokenoffset),
447 hf,sub_ti,linelen-tokenoffset,&transport_info),
448 offset = next_offset;
452 /* Now look, if we have strings collected.
453 * Try to convert ipv4 addresses and ports into binary format,
454 * so we can use them to detect rtp and rtcp streams.
455 * Don't forget to free the strings!
458 for (n = 0; n < transport_info.media_count; n++)
460 if(transport_info.media_port[n]!=NULL) {
461 port = atol(transport_info.media_port[n]);
463 if(transport_info.media_proto[n]!=NULL) {
464 /* Check if media protocol is RTP
465 * and stream decoding is enabled in preferences
467 if(global_sdp_establish_conversation){
468 /* Check if media protocol is RTP */
469 is_rtp = (strcmp(transport_info.media_proto[n],"RTP/AVP")==0);
470 /* Check if media protocol is SRTP */
471 is_srtp = (strcmp(transport_info.media_proto[n],"RTP/SAVP")==0);
472 /* Check if media protocol is T38 */
473 is_t38 = ( (strcmp(transport_info.media_proto[n],"UDPTL")==0) ||
474 (strcmp(transport_info.media_proto[n],"udptl")==0) );
475 /* Check if media protocol is MSRP/TCP */
476 is_msrp = (strcmp(transport_info.media_proto[n],"msrp/tcp")==0);
481 if(transport_info.connection_address!=NULL) {
482 if(transport_info.connection_type!=NULL) {
483 if (strcmp(transport_info.connection_type,"IP4")==0) {
484 if(inet_pton(AF_INET,transport_info.connection_address, &ipaddr)==1 ) {
485 /* connection_address could be converted to a valid ipv4 address*/
487 src_addr.type=AT_IPv4;
491 else if (strcmp(transport_info.connection_type,"IP6")==0){
492 if (inet_pton(AF_INET6, transport_info.connection_address, &ipaddr)==1){
493 /* connection_address could be converted to a valid ipv6 address*/
495 src_addr.type=AT_IPv6;
501 if (strcmp(transport_info.media_type,"video")==0){
505 /* Add (s)rtp and (s)rtcp conversation, if available (overrides t38 if conversation already set) */
506 if((!pinfo->fd->flags.visited) && port!=0 && (is_rtp||is_srtp) && (is_ipv4_addr || is_ipv6_addr)){
507 src_addr.data=(guint8*)&ipaddr;
510 struct srtp_info *dummy_srtp_info = se_alloc0(sizeof(struct srtp_info));
511 srtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num, is_video,
512 transport_info.media[n].rtp_dyn_payload, dummy_srtp_info);
514 rtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num, is_video,
515 transport_info.media[n].rtp_dyn_payload);
521 rtcp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
525 /* Add t38 conversation, if available and only if no rtp */
526 if((!pinfo->fd->flags.visited) && port!=0 && !set_rtp && is_t38 && is_ipv4_addr){
527 src_addr.data=(guint8*)&ipaddr;
529 t38_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
533 /* Add MSRP conversation. Uses addresses discovered in attribute
534 rather than connection information of media session line */
536 if ((!pinfo->fd->flags.visited) && msrp_transport_address_set){
538 src_addr.type=AT_IPv4;
540 src_addr.data=(guint8*)&msrp_ipaddr;
541 msrp_add_address(pinfo, &src_addr, msrp_port_number, "SDP", pinfo->fd->num);
546 /* Create the RTP summary str for the Voip Call analysis */
547 for (i = 0; i < transport_info.media[n].pt_count; i++)
549 /* if the payload type is dynamic (96 to 127), check the hash table to add the desc in the SDP summary */
550 if ( (transport_info.media[n].pt[i] >=96) && (transport_info.media[n].pt[i] <=127) ) {
551 encoding_name_and_rate_t *encoding_name_and_rate_pt = g_hash_table_lookup(transport_info.media[n].rtp_dyn_payload, &transport_info.media[n].pt[i]);
552 if (encoding_name_and_rate_pt)
553 g_snprintf(sdp_pi->summary_str, 50, "%s %s", sdp_pi->summary_str, encoding_name_and_rate_pt->encoding_name);
555 g_snprintf(sdp_pi->summary_str, 50, "%s %d", sdp_pi->summary_str, transport_info.media[n].pt[i]);
557 g_snprintf(sdp_pi->summary_str, 50, "%s %s", sdp_pi->summary_str, val_to_str(transport_info.media[n].pt[i], rtp_payload_type_short_vals, "%u"));
560 /* Free the hash table if we did't assigned it to a conv use it */
561 if (set_rtp == FALSE)
562 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
564 /* Create the T38 summary str for the Voip Call analysis */
565 if (is_t38) g_snprintf(sdp_pi->summary_str, 50, "%s t38", sdp_pi->summary_str);
568 /* Free the remainded hash tables not used */
569 for (n = transport_info.media_count; n < SDP_MAX_RTP_CHANNELS; n++)
571 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
575 datalen = tvb_length_remaining(tvb, offset);
577 proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)",
581 /* Report this packet to the tap */
582 tap_queue_packet(sdp_tap, pinfo, sdp_pi);
586 call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, int length,transport_info_t *transport_info){
588 dissect_sdp_owner(tvb,ti);
589 } else if ( hf == hf_connection_info) {
590 dissect_sdp_connection_info(tvb,ti,transport_info);
591 } else if ( hf == hf_bandwidth) {
592 dissect_sdp_bandwidth(tvb,ti);
593 } else if ( hf == hf_time) {
594 dissect_sdp_time(tvb,ti);
595 } else if ( hf == hf_repeat_time ){
596 dissect_sdp_repeat_time(tvb,ti);
597 } else if ( hf == hf_timezone ) {
598 dissect_sdp_timezone(tvb,ti);
599 } else if ( hf == hf_encryption_key ) {
600 dissect_sdp_encryption_key(tvb,ti);
601 } else if ( hf == hf_session_attribute ){
602 dissect_sdp_session_attribute(tvb,pinfo,ti);
603 } else if ( hf == hf_media ) {
604 dissect_sdp_media(tvb,ti,transport_info);
605 } else if ( hf == hf_media_attribute ){
606 dissect_sdp_media_attribute(tvb,pinfo,ti, length, transport_info);
611 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
612 proto_tree *sdp_owner_tree;
613 gint offset,next_offset,tokenlen;
619 sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
621 /* Find the username */
622 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
623 if( next_offset == -1 )
625 tokenlen = next_offset - offset;
627 proto_tree_add_item(sdp_owner_tree, hf_owner_username, tvb, offset, tokenlen,
629 offset = next_offset + 1;
631 /* Find the session id */
632 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
633 if( next_offset == -1 )
635 tokenlen = next_offset - offset;
637 proto_tree_add_item(sdp_owner_tree, hf_owner_sessionid, tvb, offset,
639 offset = next_offset + 1;
641 /* Find the version */
642 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
643 if( next_offset == -1 )
645 tokenlen = next_offset - offset;
647 proto_tree_add_item(sdp_owner_tree, hf_owner_version, tvb, offset, tokenlen,
649 offset = next_offset + 1;
651 /* Find the network type */
652 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
653 if( next_offset == -1 )
655 tokenlen = next_offset - offset;
657 proto_tree_add_item(sdp_owner_tree, hf_owner_network_type, tvb, offset,
659 offset = next_offset + 1;
661 /* Find the address type */
662 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
663 if( next_offset == -1 )
665 tokenlen = next_offset - offset;
667 proto_tree_add_item(sdp_owner_tree, hf_owner_address_type, tvb, offset,
669 offset = next_offset + 1;
671 /* Find the address */
672 proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
676 * XXX - this can leak memory if an exception is thrown after we've fetched
680 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
681 transport_info_t *transport_info){
682 proto_tree *sdp_connection_info_tree;
683 gint offset,next_offset,tokenlen;
689 sdp_connection_info_tree = proto_item_add_subtree(ti,
690 ett_sdp_connection_info);
692 /* Find the network type */
693 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
694 if( next_offset == -1 )
696 tokenlen = next_offset - offset;
698 proto_tree_add_item(sdp_connection_info_tree,
699 hf_connection_info_network_type, tvb, offset, tokenlen,
701 offset = next_offset + 1;
703 /* Find the address type */
704 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
705 if( next_offset == -1 )
707 tokenlen = next_offset - offset;
708 /* Save connection address type */
709 transport_info->connection_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
712 proto_tree_add_item(sdp_connection_info_tree,
713 hf_connection_info_address_type, tvb, offset, tokenlen,
715 offset = next_offset + 1;
717 /* Find the connection address */
718 /* XXX - what if there's a <number of addresses> value? */
719 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
720 if( next_offset == -1){
721 tokenlen = -1; /* end of tvbuff */
722 /* Save connection address */
723 transport_info->connection_address =
724 (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
726 tokenlen = next_offset - offset;
727 /* Save connection address */
728 transport_info->connection_address = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
731 proto_tree_add_item(sdp_connection_info_tree,
732 hf_connection_info_connection_address, tvb, offset,
734 if(next_offset != -1){
735 offset = next_offset + 1;
736 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
737 if( next_offset == -1){
738 tokenlen = -1; /* end of tvbuff */
740 tokenlen = next_offset - offset;
742 proto_tree_add_item(sdp_connection_info_tree,
743 hf_connection_info_ttl, tvb, offset, tokenlen, FALSE);
744 if(next_offset != -1){
745 offset = next_offset + 1;
746 proto_tree_add_item(sdp_connection_info_tree,
747 hf_connection_info_num_addr, tvb, offset, -1, FALSE);
753 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
754 proto_tree * sdp_bandwidth_tree;
755 gint offset, next_offset, tokenlen;
757 gboolean unit_is_kbs = FALSE;
758 gboolean unit_is_bps = FALSE;
764 sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
766 /* find the modifier */
767 next_offset = tvb_find_guint8(tvb,offset,-1,':');
769 if( next_offset == -1)
772 tokenlen = next_offset - offset;
774 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier, tvb, offset,
776 if (tvb_strneql(tvb, offset, "CT", 2) == 0){
777 proto_item_append_text(item, " [Conference Total(total bandwidth of all RTP sessions)]");
779 }else if (tvb_strneql(tvb, offset, "AS", 2) == 0){
780 proto_item_append_text(item, " [Application Specific (RTP session bandwidth)]");
782 }else if (tvb_strneql(tvb, offset, "TIAS", 4) == 0){
783 proto_item_append_text(item, " [Transport Independent Application Specific maximum]");
788 offset = next_offset + 1;
790 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value, tvb, offset, -1,
792 if (unit_is_kbs == TRUE)
793 proto_item_append_text(item, " kb/s");
794 if (unit_is_bps == TRUE)
795 proto_item_append_text(item, " b/s");
798 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
799 proto_tree *sdp_time_tree;
800 gint offset,next_offset, tokenlen;
806 sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
809 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
810 if( next_offset == -1 )
813 tokenlen = next_offset - offset;
814 proto_tree_add_item(sdp_time_tree, hf_time_start, tvb, offset, tokenlen,
818 offset = next_offset + 1;
819 proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb, offset, -1, FALSE);
822 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
823 proto_tree *sdp_repeat_time_tree;
824 gint offset,next_offset, tokenlen;
830 sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
833 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
834 if( next_offset == -1 )
837 tokenlen = next_offset - offset;
838 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
839 offset, tokenlen, FALSE);
842 offset = next_offset + 1;
843 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
844 if( next_offset == -1 )
847 tokenlen = next_offset - offset;
848 proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
849 offset, tokenlen, FALSE);
853 offset = next_offset +1;
854 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
855 if(next_offset != -1){
856 tokenlen = next_offset - offset;
858 tokenlen = -1; /* end of tvbuff */
860 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
861 tvb, offset, tokenlen, FALSE);
862 } while( next_offset != -1 );
866 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
867 proto_tree* sdp_timezone_tree;
868 gint offset, next_offset, tokenlen;
873 sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
876 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
877 if(next_offset == -1)
879 tokenlen = next_offset - offset;
881 proto_tree_add_item(sdp_timezone_tree, hf_timezone_time, tvb, offset,
883 offset = next_offset + 1;
884 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
885 if(next_offset != -1){
886 tokenlen = next_offset - offset;
888 tokenlen = -1; /* end of tvbuff */
890 proto_tree_add_item(sdp_timezone_tree, hf_timezone_offset, tvb, offset,
892 offset = next_offset + 1;
893 } while (next_offset != -1);
898 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
899 proto_tree *sdp_encryption_key_tree;
900 gint offset, next_offset, tokenlen;
906 sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
908 next_offset = tvb_find_guint8(tvb,offset,-1,':');
910 if(next_offset == -1)
913 tokenlen = next_offset - offset;
915 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
916 tvb, offset, tokenlen, FALSE);
918 offset = next_offset + 1;
919 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
920 tvb, offset, -1, FALSE);
923 static void dissect_key_mgmt(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
924 gchar *data_p = NULL;
925 gchar *prtcl_id = NULL;
927 tvbuff_t *keymgmt_tvb;
928 gboolean found_match = FALSE;
929 proto_tree *key_tree;
934 key_tree = proto_item_add_subtree(ti, ett_sdp_key_mgmt);
936 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
938 if (next_offset == -1)
941 tokenlen = next_offset - offset;
942 prtcl_id = tvb_get_ephemeral_string(tvb, offset, tokenlen);
944 proto_tree_add_item(key_tree, hf_key_mgmt_prtcl_id, tvb, offset, tokenlen, FALSE);
946 offset = next_offset + 1;
948 len = tvb_length_remaining(tvb, offset);
952 data_p = tvb_get_ephemeral_string(tvb, offset, len);
953 keymgmt_tvb = base64_to_tvb(tvb, data_p);
954 add_new_data_source(pinfo, keymgmt_tvb, "Key Management Data");
956 if ( prtcl_id != NULL && key_mgmt_dissector_table != NULL ) {
957 found_match = dissector_try_string(key_mgmt_dissector_table,
964 proto_item *ti2 = proto_tree_add_item(key_tree, hf_key_mgmt_data,
965 keymgmt_tvb, 0, -1, FALSE);
966 PROTO_ITEM_SET_HIDDEN(ti2);
969 proto_tree_add_item(key_tree, hf_key_mgmt_data,
970 keymgmt_tvb, 0, -1, FALSE);
976 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
977 proto_tree *sdp_session_attribute_tree;
978 gint offset, next_offset, tokenlen;
985 sdp_session_attribute_tree = proto_item_add_subtree(ti,
986 ett_sdp_session_attribute);
988 next_offset = tvb_find_guint8(tvb,offset,-1,':');
990 if(next_offset == -1)
993 tokenlen = next_offset - offset;
995 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_field,
996 tvb, offset, tokenlen, FALSE);
998 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1000 offset = next_offset + 1;
1002 if (strcmp((char*)field_name, "ipbcp") == 0) {
1003 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"0123456789", NULL);
1008 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1010 if (next_offset == -1)
1013 tokenlen = next_offset - offset;
1015 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_version,tvb,offset,tokenlen,FALSE);
1017 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", NULL);
1022 tokenlen = tvb_find_line_end(tvb,offset,-1, &next_offset, FALSE);
1027 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE);
1028 } else if (strcmp((char*)field_name, "key-mgmt") == 0) {
1032 key_tvb = tvb_new_subset_remaining(tvb, offset);
1033 key_ti = proto_tree_add_item(sdp_session_attribute_tree, hf_key_mgmt_att_value, key_tvb, 0, -1, FALSE);
1035 dissect_key_mgmt(key_tvb, pinfo, key_ti);
1037 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value,
1038 tvb, offset, -1, FALSE);
1043 /* Dissect media description */
1045 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
1046 transport_info_t *transport_info){
1047 proto_tree *sdp_media_tree;
1048 gint offset, next_offset, tokenlen, idx;
1049 guint8 *media_format;
1055 /* Re-initialise for a new media description */
1056 msrp_transport_address_set = FALSE;
1058 /* Create tree for media session */
1059 sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
1061 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1063 if(next_offset == -1)
1066 tokenlen = next_offset - offset;
1068 /* Type of media session */
1069 proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, offset, tokenlen,
1072 transport_info->media_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1074 offset = next_offset + 1;
1076 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1077 if(next_offset == -1)
1079 tokenlen = next_offset - offset;
1080 next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
1082 if(next_offset != -1){
1083 tokenlen = next_offset - offset;
1084 /* Save port info */
1085 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1087 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1088 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1089 offset = next_offset + 1;
1090 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1091 if(next_offset == -1)
1093 tokenlen = next_offset - offset;
1094 proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb, offset,
1096 offset = next_offset + 1;
1098 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1100 if(next_offset == -1)
1102 tokenlen = next_offset - offset;
1103 /* Save port info */
1104 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1106 /* XXX Remember Port */
1107 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1108 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1109 offset = next_offset + 1;
1112 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1114 if( next_offset == -1)
1117 tokenlen = next_offset - offset;
1118 /* Save port protocol */
1119 transport_info->media_proto[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1121 /* XXX Remember Protocol */
1122 proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb, offset, tokenlen,
1126 offset = next_offset + 1;
1127 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1129 if(next_offset == -1){
1130 tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
1132 break; /* Nothing more left */
1134 tokenlen = next_offset - offset;
1137 if (strcmp(transport_info->media_proto[transport_info->media_count],
1139 media_format = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1140 proto_tree_add_string(sdp_media_tree, hf_media_format, tvb, offset,
1141 tokenlen, val_to_str(atol((char*)media_format), rtp_payload_type_vals, "%u"));
1142 idx = transport_info->media[transport_info->media_count].pt_count;
1143 transport_info->media[transport_info->media_count].pt[idx] = atol((char*)media_format);
1144 if (idx < (SDP_MAX_RTP_PAYLOAD_TYPES-1))
1145 transport_info->media[transport_info->media_count].pt_count++;
1147 proto_tree_add_item(sdp_media_tree, hf_media_format, tvb, offset,
1150 } while (next_offset != -1);
1152 /* Increase the count of media channels, but don't walk off the end
1154 if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
1155 transport_info->media_count++;
1158 /* XXX Dissect traffic to "Port" as "Protocol"
1159 * Remember this Port/Protocol pair so we can tear it down again later
1160 * Actually, it's harder than that:
1161 * We need to find out the address of the other side first and it
1162 * looks like that info can be found in SIP headers only.
1168 ascii_bytes_to_tvb(tvbuff_t *tvb, packet_info *pinfo, gint len, gchar *msg)
1170 guint8 *buf = g_malloc(10240);
1172 /* arbitrary maximum length */
1175 tvbuff_t *bytes_tvb;
1177 /* first, skip to where the encoded pdu starts, this is
1178 the first hex digit after the '=' char.
1181 if((*msg==0)||(*msg=='\n')){
1191 if((*msg==0)||(*msg=='\n')){
1194 if( ((*msg>='0')&&(*msg<='9'))
1195 || ((*msg>='a')&&(*msg<='f'))
1196 || ((*msg>='A')&&(*msg<='F'))){
1202 while( ((*msg>='0')&&(*msg<='9'))
1203 ||((*msg>='a')&&(*msg<='f'))
1204 ||((*msg>='A')&&(*msg<='F')) ){
1206 if((*msg>='0')&&(*msg<='9')){
1208 } else if((*msg>='a')&&(*msg<='f')){
1210 } else if((*msg>='A')&&(*msg<='F')){
1217 if((*msg>='0')&&(*msg<='9')){
1219 } else if((*msg>='a')&&(*msg<='f')){
1221 } else if((*msg>='A')&&(*msg<='F')){
1234 bytes_tvb = tvb_new_child_real_data(tvb, buf,i,i);
1235 tvb_set_free_cb(bytes_tvb, g_free);
1236 add_new_data_source(pinfo, bytes_tvb, "ASCII bytes to tvb");
1242 /* Annex X Profiles and levels definition */
1243 static const value_string h263_profile_vals[] =
1245 { 0, "Baseline Profile" },
1246 { 1, "H.320 Coding Efficiency Version 2 Backward-Compatibility Profile" },
1247 { 2, "Version 1 Backward-Compatibility Profile" },
1248 { 3, "Version 2 Interactive and Streaming Wireless Profile" },
1249 { 4, "Version 3 Interactive and Streaming Wireless Profile" },
1250 { 5, "Conversational High Compression Profile" },
1251 { 6, "Conversational Internet Profile" },
1252 { 7, "Conversational Interlace Profile" },
1253 { 8, "High Latency Profile" },
1258 /* RFC 4629 The level are described in table X.2 of H.263 annex X */
1259 static const value_string h263_level_vals[] =
1261 { 10, "QCIF (176 x 144), 1 x 64Kb/s" },
1262 { 20, "CIF (352 x 288), 2 x 64Kb/s" },
1263 { 30, "CIF (352 x 288), 6 x 64Kb/s" },
1264 { 40, "CIF (352 x 288), 32 x 64Kb/s" },
1265 { 45, "QCIF (176 x144) support of CPFMT, 2 x 64Kb/s" },
1266 { 50, "CIF (352 x 288) support of CPFMT, 64 x 64Kb/s" },
1267 { 60, "CPFMT: 720 x 288 support of CPFMT, 128 x 64Kb/s" },
1268 { 70, "CPFMT: 720 x 576 support of CPFMT, 256 x 64Kb/s" },
1273 static const value_string h264_packetization_mode_vals[] =
1275 { 0, "Single NAL mode" },
1276 { 1, "Non-interleaved mode" },
1277 { 2, "Interleaved mode" },
1282 * TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
1285 decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint tokenlen, char *mime_type){
1289 gchar *format_specific_parameter;
1293 end_offset = offset + tokenlen;
1296 proto_tree_add_text(tree, tvb, offset, tokenlen, "Debug; Analysed string: '%s'",
1297 tvb_get_ephemeral_string(tvb, offset, tokenlen));
1300 /* Look for an '=' within this value - this may indicate that there is a
1301 profile-level-id parameter to find if the MPEG4 media type is in use */
1302 next_offset = tvb_find_guint8(tvb,offset,-1,'=');
1303 if (next_offset == -1)
1305 /* Give up (and avoid exception) if '=' not found */
1309 /* Find the name of the parameter */
1310 tokenlen = next_offset - offset;
1311 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1312 /*proto_tree_add_text(tree, tvb, offset, tokenlen, "Debug; MIMEtype '%s'Parameter name: '%s'", mime_type, field_name); */
1314 offset = next_offset;
1316 /* Dissect the MPEG4 profile-level-id parameter if present */
1317 if (mime_type != NULL && g_ascii_strcasecmp(mime_type, "MP4V-ES") == 0) {
1318 if (strcmp((char*)field_name, "profile-level-id") == 0) {
1320 tokenlen = end_offset - offset;
1321 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1322 item = proto_tree_add_uint(tree, hf_sdp_fmtp_mpeg4_profile_level_id, tvb, offset, tokenlen,
1323 atol((char*)format_specific_parameter));
1324 PROTO_ITEM_SET_GENERATED(item);
1325 } else if (strcmp((char*)field_name, "config") == 0) {
1326 /* String including "=" */
1327 tokenlen = end_offset - offset;
1328 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1329 /* ascii_bytes_to_tvb requires the "=" to be in the buffer */
1330 data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
1331 if(mp4ves_handle && data_tvb){
1332 dissect_mp4ves_config(data_tvb, pinfo, tree);
1337 /* Dissect the H263-2000 profile parameter if present */
1338 if ((mime_type != NULL && g_ascii_strcasecmp(mime_type, "H263-2000") == 0)||(mime_type != NULL && g_ascii_strcasecmp(mime_type, "H263-1998") == 0)) {
1339 if (strcmp((char*)field_name, "profile") == 0) {
1341 tokenlen = end_offset - offset;
1342 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1343 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_profile, tvb, offset, tokenlen,
1344 atol((char*)format_specific_parameter));
1345 PROTO_ITEM_SET_GENERATED(item);
1346 } else if(strcmp((char*)field_name, "level") == 0) {
1348 tokenlen = end_offset - offset;
1349 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1350 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_level, tvb, offset, tokenlen,
1351 atol((char*)format_specific_parameter));
1352 PROTO_ITEM_SET_GENERATED(item);
1357 /* Dissect the H264 profile-level-id parameter
1359 * A base16 [6] (hexadecimal) representation of
1360 * the following three bytes in the sequence
1361 * parameter set NAL unit specified in [1]: 1)
1362 * profile_idc, 2) a byte herein referred to as
1363 * profile-iop, composed of the values of
1364 * constraint_set0_flag, constraint_set1_flag,
1365 * constraint_set2_flag, and reserved_zero_5bits
1366 * in bit-significance order, starting from the
1367 * most significant bit, and 3) level_idc.
1369 if (mime_type != NULL && g_ascii_strcasecmp(mime_type, "H264") == 0) {
1370 if (strcmp(field_name, "profile-level-id") == 0) {
1373 /* Length includes "=" as it's required by ascii_bytes_to_tvb()*/
1374 tokenlen = end_offset - offset;
1375 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1376 data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
1377 length = tvb_length(data_tvb);
1379 if(h264_handle && data_tvb){
1380 dissect_h264_profile(data_tvb, pinfo, tree);
1383 item = proto_tree_add_text(tree, tvb, offset, tokenlen, "Incorrectly coded, must be three bytes");
1384 PROTO_ITEM_SET_GENERATED(item);
1386 }else if (strcmp(field_name, "packetization-mode") == 0) {
1388 tokenlen = end_offset - offset;
1389 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1390 item = proto_tree_add_uint(tree, hf_sdp_h264_packetization_mode, tvb, offset, tokenlen,
1391 atol((char*)format_specific_parameter));
1392 PROTO_ITEM_SET_GENERATED(item);
1394 }else if (strcmp(field_name, "sprop-parameter-sets") == 0) {
1395 /* The value of the parameter is the
1396 base64 [6] representation of the initial
1397 parameter set NAL units as specified in
1398 sections 7.3.2.1 and 7.3.2.2 of [1]. The
1399 parameter sets are conveyed in decoding order,
1400 and no framing of the parameter set NAL units
1401 takes place. A comma is used to separate any
1402 pair of parameter sets in the list.
1404 gchar *data_p = NULL;
1410 comma_offset = tvb_find_guint8(tvb,offset,-1,',');
1411 if (comma_offset != -1){
1412 tokenlen = comma_offset - offset;
1414 tokenlen = end_offset - offset;
1417 data_p = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1418 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 1 string: %s", data_p);
1420 /* proto_tree_add_text(tree, tvb, offset, tokenlen, "String %s",data_p); */
1421 data_tvb = base64_to_tvb(tvb, data_p);
1422 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets");
1424 if(h264_handle && data_tvb){
1425 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1426 if (comma_offset != -1){
1427 /* Second NAL unit */
1428 offset = comma_offset +1;
1429 tokenlen = end_offset - offset;
1430 data_p = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1431 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 2 string: %s", data_p);
1432 data_tvb = base64_to_tvb(tvb, data_p);
1433 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets 2");
1434 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1446 #define SDP_RTPMAP 1
1449 #define SDP_H248_ITEM 4
1451 static const sdp_names_t sdp_media_attribute_names[] = {
1452 { "Unknown-name"}, /* 0 Pad so that the real headers start at index 1 */
1453 { "rtpmap"}, /* 1 */
1456 { "h248item"}, /* 4 */
1459 static gint find_sdp_media_attribute_names(tvbuff_t *tvb, int offset, guint len)
1463 for (i = 1; i < array_length(sdp_media_attribute_names); i++) {
1464 if (len == strlen(sdp_media_attribute_names[i].name) &&
1465 tvb_strncaseeql(tvb, offset, sdp_media_attribute_names[i].name, len) == 0)
1472 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item * ti, int length, transport_info_t *transport_info){
1473 proto_tree *sdp_media_attribute_tree;
1474 proto_item *fmtp_item, *media_format_item;
1475 proto_tree *fmtp_tree;
1476 gint offset, next_offset, tokenlen, n, colon_offset;
1479 guint8 *payload_type;
1480 guint8 *attribute_value;
1483 gint sdp_media_attrbute_code;
1484 const char *msrp_res = "msrp://";
1485 const char *h324ext_h223lcparm = "h324ext/h223lcparm";
1486 gboolean has_more_pars = TRUE;
1488 encoding_name_and_rate_t *encoding_name_and_rate;
1494 /* Create attribute tree */
1495 sdp_media_attribute_tree = proto_item_add_subtree(ti,
1496 ett_sdp_media_attribute);
1497 /* Find end of field */
1498 colon_offset = tvb_find_guint8(tvb,offset,-1,':');
1500 if(colon_offset == -1)
1503 /* Attribute field name is token before ':' */
1504 tokenlen = colon_offset - offset;
1505 proto_tree_add_item(sdp_media_attribute_tree,
1506 hf_media_attribute_field,
1507 tvb, offset, tokenlen, FALSE);
1508 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1509 sdp_media_attrbute_code = find_sdp_media_attribute_names(tvb, offset, tokenlen);
1512 offset = colon_offset + 1;
1513 /* skip leading wsp */
1514 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1516 /* Value is the remainder of the line */
1517 attribute_value = tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
1521 /*********************************************/
1522 /* Special parsing for some field name types */
1524 switch (sdp_media_attrbute_code){
1526 /* decode the rtpmap to see if it is DynamicPayload to dissect them automatic */
1527 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1529 if(next_offset == -1)
1532 tokenlen = next_offset - offset;
1534 proto_tree_add_item(sdp_media_attribute_tree, hf_media_format, tvb,
1535 offset, tokenlen, FALSE);
1537 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1539 offset = next_offset + 1;
1541 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
1543 if(next_offset == -1){
1547 tokenlen = next_offset - offset;
1549 start_offset = offset;
1550 proto_tree_add_item(sdp_media_attribute_tree, hf_media_encoding_name, tvb,
1551 offset, tokenlen, FALSE);
1553 key=g_malloc( sizeof(gint) );
1554 *key=atol((char*)payload_type);
1555 pt = atoi((char*)payload_type);
1556 if (pt >= SDP_NO_OF_PT) {
1557 return; /* Invalid */
1559 transport_info->encoding_name[pt] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1561 next_offset = next_offset + 1;
1562 offset = next_offset;
1563 while (length-1 >= next_offset){
1564 if(!isdigit(tvb_get_guint8(tvb, next_offset)))
1568 tokenlen = next_offset - offset;
1569 proto_tree_add_item(sdp_media_attribute_tree, hf_media_sample_rate, tvb,
1570 offset, tokenlen, FALSE);
1571 transport_info->sample_rate[pt] = atoi(tvb_get_ephemeral_string(tvb, offset, tokenlen));
1572 /* As per RFC2327 it is possible to have multiple Media Descriptions ("m=").
1575 a=rtpmap:101 G726-32/8000
1576 m=audio 49170 RTP/AVP 0 97
1577 a=rtpmap:97 telephone-event/8000
1578 m=audio 49172 RTP/AVP 97 101
1579 a=rtpmap:97 G726-24/8000
1581 The Media attributes ("a="s) after the "m=" only apply for that "m=".
1582 If there is an "a=" before the first "m=", that attribute applies for
1583 all the session (all the "m="s).
1586 /* so, if this "a=" appear before any "m=", we add it to all the dynamic
1589 if (transport_info->media_count == 0) {
1590 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++) {
1591 encoding_name_and_rate = g_malloc( sizeof(encoding_name_and_rate_t));
1592 encoding_name_and_rate->encoding_name = g_strdup(transport_info->encoding_name[pt]);
1593 encoding_name_and_rate->sample_rate = transport_info->sample_rate[pt];
1595 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1596 key, encoding_name_and_rate);
1598 else { /* we create a new key and encoding_name to assign to the other hash tables */
1600 key2=g_malloc( sizeof(gint) );
1601 *key2=atol((char*)payload_type);
1602 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1603 key2, encoding_name_and_rate);
1607 /* if the "a=" is after an "m=", only apply to this "m=" */
1609 /* in case there is an overflow in SDP_MAX_RTP_CHANNELS, we keep always the last "m=" */
1610 encoding_name_and_rate = g_malloc( sizeof(encoding_name_and_rate_t));
1612 encoding_name_and_rate->encoding_name = g_strdup(transport_info->encoding_name[pt]);
1613 encoding_name_and_rate->sample_rate = transport_info->sample_rate[pt];
1614 if (transport_info->media_count == SDP_MAX_RTP_CHANNELS-1)
1615 g_hash_table_insert(transport_info->media[ transport_info->media_count ].rtp_dyn_payload,
1616 key, encoding_name_and_rate);
1618 g_hash_table_insert(transport_info->media[ transport_info->media_count-1 ].rtp_dyn_payload,
1619 key, encoding_name_and_rate);
1622 if(sdp_media_attribute_tree){
1623 guint8 media_format;
1624 /* Reading the Format parameter(fmtp) */
1625 /* Skip leading space, if any */
1626 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1627 /* Media format extends to the next space */
1628 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1630 if(next_offset == -1)
1633 tokenlen = next_offset - offset;
1636 media_format_item = proto_tree_add_item(sdp_media_attribute_tree,
1637 hf_media_format, tvb, offset,
1639 media_format = atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen));
1640 if (media_format >= SDP_NO_OF_PT) {
1641 return; /* Invalid */
1644 /* Append encoding name to format if known */
1645 proto_item_append_text(media_format_item, " [%s]",
1646 transport_info->encoding_name[media_format]);
1648 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1649 /* Move offset past the payload type */
1650 offset = next_offset + 1;
1652 while(has_more_pars==TRUE){
1653 next_offset = tvb_find_guint8(tvb,offset,-1,';');
1654 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1656 if(next_offset == -1){
1657 has_more_pars = FALSE;
1658 next_offset= tvb_length(tvb);
1663 /* There are at least 2 - add the first parameter */
1664 tokenlen = next_offset - offset;
1665 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1666 hf_media_format_specific_parameter, tvb,
1667 offset, tokenlen, FALSE);
1669 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1671 decode_sdp_fmtp(fmtp_tree, tvb, pinfo, offset, tokenlen,
1672 transport_info->encoding_name[media_format]);
1674 /* Move offset past "; " and onto firts char */
1675 offset = next_offset + 1;
1680 /* msrp attributes that contain address needed for conversation */
1682 * path = path-label ":" path-list
1683 * path-label = "path"
1684 * path-list= MSRP-URI *(SP MSRP-URI)
1685 * MSRP-URI = msrp-scheme "://" authority
1686 * ["/" session-id] ";" transport *( ";" URI-parameter)
1687 * ; authority as defined in RFC3986
1689 * msrp-scheme = "msrp" / "msrps"
1691 * The authority component is preceded by a double slash ("//") and is terminated by
1692 * the next slash ("/"), question mark ("?"), or number sign ("#") character, or by
1693 * the end of the URI.
1696 /* Check for "msrp://" */
1697 if (strncmp((char*)attribute_value, msrp_res, strlen(msrp_res)) == 0){
1698 int address_offset, port_offset, port_end_offset;
1700 /* Address starts here */
1701 address_offset = offset + (int)strlen(msrp_res);
1703 /* Port is after next ':' */
1704 port_offset = tvb_find_guint8(tvb, address_offset, -1, ':');
1705 /* Check if port is present if not skipp */
1706 if(port_offset!= -1){
1707 /* Port ends with '/' */
1708 port_end_offset = tvb_find_guint8(tvb, port_offset, -1, '/');
1710 /* Attempt to convert address */
1711 if (inet_pton(AF_INET, (char*)tvb_get_ephemeral_string(tvb, address_offset, port_offset-address_offset), &msrp_ipaddr) > 0) {
1712 /* Get port number */
1713 msrp_port_number = atoi((char*)tvb_get_ephemeral_string(tvb, port_offset+1, port_end_offset-port_offset-1));
1714 /* Set flag so this info can be used */
1715 msrp_transport_address_set = TRUE;
1721 /* Decode h248 item ITU-T Rec. H.248.12 (2001)/Amd.1 (11/2002)*/
1722 if (strncmp((char*)attribute_value, h324ext_h223lcparm, strlen(msrp_res)) == 0){
1723 /* A.5.1.3 H.223 Logical channel parameters
1724 * This property indicates the H.245
1725 * H223LogicalChannelsParameters structure encoded by applying the PER specified in
1726 * ITU-T Rec. X.691. Value encoded as per A.5.1.2. For text encoding the mechanism defined
1727 * in ITU-T Rec. H.248.15 is used.
1732 len = (gint)strlen(attribute_value);
1733 h245_tvb = ascii_bytes_to_tvb(tvb, pinfo, len, attribute_value);
1734 /* arbitrary maximum length */
1735 /* should go through a handle, however, the two h245 entry
1736 points are different, one is over tpkt and the other is raw
1739 asn1_ctx_init(&actx, ASN1_ENC_PER, TRUE, pinfo);
1740 dissect_h245_H223LogicalChannelParameters(h245_tvb, 0, &actx, sdp_media_attribute_tree, hf_SDPh223LogicalChannelParameters);
1745 /* No special treatment for values of this attribute type, just add as one item. */
1746 proto_tree_add_item(sdp_media_attribute_tree, hf_media_attribute_value,
1747 tvb, offset, -1, FALSE);
1753 proto_register_sdp(void)
1755 static hf_register_info hf[] = {
1756 { &hf_protocol_version,
1757 { "Session Description Protocol Version (v)",
1758 "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
1761 { "Owner/Creator, Session Id (o)",
1762 "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
1765 { "Session Name (s)",
1766 "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
1769 { "Session Information (i)",
1770 "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
1773 { "URI of Description (u)",
1774 "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
1777 { "E-mail Address (e)",
1778 "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
1779 "E-mail Address", HFILL }},
1781 { "Phone Number (p)",
1782 "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
1784 { &hf_connection_info,
1785 { "Connection Information (c)",
1786 "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
1789 { "Bandwidth Information (b)",
1790 "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
1793 { "Time Zone Adjustments (z)",
1794 "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
1796 { &hf_encryption_key,
1797 { "Encryption Key (k)",
1798 "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
1800 { &hf_session_attribute,
1801 { "Session Attribute (a)",
1802 "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1804 { &hf_media_attribute,
1805 { "Media Attribute (a)",
1806 "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1809 { "Time Description, active time (t)",
1810 "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
1813 { "Repeat Time (r)",
1814 "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
1817 { "Media Description, name and address (m)",
1818 "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
1821 { "Media Title (i)",
1822 "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
1823 "Media Title", HFILL }},
1826 "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
1830 "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
1832 { &hf_owner_username,
1834 "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
1836 { &hf_owner_sessionid,
1838 "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
1840 { &hf_owner_version,
1841 { "Session Version",
1842 "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
1844 { &hf_owner_network_type,
1845 { "Owner Network Type",
1846 "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1848 { &hf_owner_address_type,
1849 { "Owner Address Type",
1850 "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1852 { &hf_owner_address,
1854 "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
1856 { &hf_connection_info_network_type,
1857 { "Connection Network Type",
1858 "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1860 { &hf_connection_info_address_type,
1861 { "Connection Address Type",
1862 "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1864 { &hf_connection_info_connection_address,
1865 { "Connection Address",
1866 "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
1868 { &hf_connection_info_ttl,
1870 "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
1872 { &hf_connection_info_num_addr,
1873 { "Connection Number of Addresses",
1874 "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
1876 { &hf_bandwidth_modifier,
1877 { "Bandwidth Modifier",
1878 "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
1880 { &hf_bandwidth_value,
1881 { "Bandwidth Value",
1882 "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
1883 "Bandwidth Value (in kbits/s)", HFILL }},
1885 { "Session Start Time",
1886 "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
1889 { "Session Stop Time",
1890 "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
1892 { &hf_repeat_time_interval,
1893 { "Repeat Interval",
1894 "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
1896 { &hf_repeat_time_duration,
1897 { "Repeat Duration",
1898 "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
1900 { &hf_repeat_time_offset,
1902 "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1904 { &hf_timezone_time,
1906 "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
1908 { &hf_timezone_offset,
1909 { "Timezone Offset",
1910 "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1912 { &hf_encryption_key_type,
1914 "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
1916 { &hf_encryption_key_data,
1918 "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
1920 { &hf_session_attribute_field,
1921 { "Session Attribute Fieldname",
1922 "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
1924 { &hf_session_attribute_value,
1925 { "Session Attribute Value",
1926 "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
1930 "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
1934 "sdp.media.port",FT_UINT16, BASE_DEC, NULL, 0x0,
1936 { &hf_media_portcount,
1937 { "Media Port Count",
1938 "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
1942 "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
1946 "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
1948 { &hf_media_attribute_field,
1949 { "Media Attribute Fieldname",
1950 "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
1952 { &hf_media_attribute_value,
1953 { "Media Attribute Value",
1954 "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
1956 { &hf_media_encoding_name,
1958 "sdp.mime.type",FT_STRING, BASE_NONE, NULL, 0x0,
1959 "SDP MIME Type", HFILL }},
1960 { &hf_media_sample_rate,
1962 "sdp.sample_rate",FT_STRING, BASE_NONE, NULL, 0x0,
1964 { &hf_media_format_specific_parameter,
1965 { "Media format specific parameters",
1966 "sdp.fmtp.parameter",FT_STRING, BASE_NONE, NULL, 0x0,
1967 "Format specific parameter(fmtp)", HFILL }},
1968 { &hf_ipbcp_version,
1969 { "IPBCP Protocol Version",
1970 "ipbcp.version",FT_STRING, BASE_NONE, NULL, 0x0,
1973 { "IPBCP Command Type",
1974 "ipbcp.command",FT_STRING, BASE_NONE, NULL, 0x0,
1976 {&hf_sdp_fmtp_mpeg4_profile_level_id,
1978 "sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mp4ves_level_indication_vals), 0x0,
1980 { &hf_sdp_fmtp_h263_profile,
1982 "sdp.fmtp.h263profile",FT_UINT32, BASE_DEC,VALS(h263_profile_vals), 0x0,
1984 { &hf_sdp_fmtp_h263_level,
1986 "sdp.fmtp.h263level",FT_UINT32, BASE_DEC,VALS(h263_level_vals), 0x0,
1988 { &hf_sdp_h264_packetization_mode,
1989 { "Packetization mode",
1990 "sdp.fmtp.h264_packetization_mode",FT_UINT32, BASE_DEC,VALS(h264_packetization_mode_vals), 0x0,
1992 { &hf_sdp_h264_sprop_parameter_sets,
1993 { "Sprop_parameter_sets",
1994 "sdp.h264.sprop_parameter_sets", FT_BYTES, BASE_NONE, NULL, 0x0,
1996 { &hf_SDPh223LogicalChannelParameters,
1997 { "h223LogicalChannelParameters", "sdp.h223LogicalChannelParameters",
1998 FT_NONE, BASE_NONE, NULL, 0,
2000 { &hf_key_mgmt_att_value,
2002 "sdp.key_mgmt", FT_STRING, BASE_NONE, NULL, 0x0,
2004 { &hf_key_mgmt_prtcl_id,
2005 { "Key Management Protocol (kmpid)",
2006 "sdp.key_mgmt.kmpid", FT_STRING, BASE_NONE, NULL, 0x0,
2008 { &hf_key_mgmt_data,
2009 { "Key Management Data",
2010 "sdp.key_mgmt.data", FT_BYTES, BASE_NONE, NULL, 0x0,
2013 static gint *ett[] = {
2016 &ett_sdp_connection_info,
2019 &ett_sdp_repeat_time,
2021 &ett_sdp_encryption_key,
2022 &ett_sdp_session_attribute,
2024 &ett_sdp_media_attribute,
2029 module_t *sdp_module;
2031 proto_sdp = proto_register_protocol("Session Description Protocol",
2033 proto_register_field_array(proto_sdp, hf, array_length(hf));
2034 proto_register_subtree_array(ett, array_length(ett));
2036 key_mgmt_dissector_table = register_dissector_table("key_mgmt",
2037 "Key Management", FT_STRING, BASE_NONE);
2040 * Preferences registration
2042 sdp_module = prefs_register_protocol(proto_sdp, NULL);
2043 prefs_register_bool_preference(sdp_module, "establish_conversation",
2044 "Establish Media Conversation",
2045 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
2046 "upon port numbers found in SDP payload",
2047 &global_sdp_establish_conversation);
2050 * Register the dissector by name, so other dissectors can
2051 * grab it by name rather than just referring to it directly.
2053 register_dissector("sdp", dissect_sdp, proto_sdp);
2055 /* Register for tapping */
2056 sdp_tap = register_tap("sdp");
2060 proto_reg_handoff_sdp(void)
2062 dissector_handle_t sdp_handle;
2064 rtp_handle = find_dissector("rtp");
2065 rtcp_handle = find_dissector("rtcp");
2066 msrp_handle = find_dissector("msrp");
2067 t38_handle = find_dissector("t38");
2068 h264_handle = find_dissector("h264");
2069 mp4ves_handle = find_dissector("mp4ves");
2071 sdp_handle = find_dissector("sdp");
2072 dissector_add_string("media_type", "application/sdp", sdp_handle);
2073 dissector_add("bctp.tpi", 0x20, sdp_handle);