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
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
45 #ifdef HAVE_WINSOCK2_H
46 #include <winsock2.h> /* needed to define AF_ values on Windows */
49 #ifdef NEED_INET_V6DEFS_H
50 # include "inet_v6defs.h"
54 #include <epan/packet.h>
55 #include <epan/conversation.h>
56 #include <epan/strutil.h>
57 #include <epan/emem.h>
58 #include <epan/base64.h>
59 #include <epan/asn1.h>
62 #include "packet-sdp.h"
64 #include "packet-rtp.h"
65 #include <epan/rtp_pt.h>
67 #include <epan/prefs.h>
68 #include <epan/expert.h>
70 #include "packet-rtcp.h"
71 #include "packet-t38.h"
72 #include "packet-msrp.h"
73 #include "packet-per.h"
74 #include "packet-h245.h"
75 #include "packet-h264.h"
77 static dissector_handle_t rtp_handle=NULL;
78 static dissector_handle_t rtcp_handle=NULL;
79 static dissector_handle_t t38_handle=NULL;
80 static dissector_handle_t msrp_handle=NULL;
81 static dissector_handle_t h264_handle = NULL;
83 static int sdp_tap = -1;
85 static int proto_sdp = -1;
87 /* preference globals */
88 static gboolean global_sdp_establish_conversation = TRUE;
90 /* Top level fields */
91 static int hf_protocol_version = -1;
92 static int hf_owner = -1;
93 static int hf_session_name = -1;
94 static int hf_session_info = -1;
95 static int hf_uri = -1;
96 static int hf_email = -1;
97 static int hf_phone = -1;
98 static int hf_connection_info = -1;
99 static int hf_bandwidth = -1;
100 static int hf_timezone = -1;
101 static int hf_encryption_key = -1;
102 static int hf_session_attribute = -1;
103 static int hf_media_attribute = -1;
104 static int hf_time = -1;
105 static int hf_repeat_time = -1;
106 static int hf_media = -1;
107 static int hf_media_title = -1;
108 static int hf_unknown = -1;
109 static int hf_invalid = -1;
110 static int hf_ipbcp_version = -1;
111 static int hf_ipbcp_type = -1;
113 /* hf_owner subfields*/
114 static int hf_owner_username = -1;
115 static int hf_owner_sessionid = -1;
116 static int hf_owner_version = -1;
117 static int hf_owner_network_type = -1;
118 static int hf_owner_address_type = -1;
119 static int hf_owner_address = -1;
121 /* hf_connection_info subfields */
122 static int hf_connection_info_network_type = -1;
123 static int hf_connection_info_address_type = -1;
124 static int hf_connection_info_connection_address = -1;
125 static int hf_connection_info_ttl = -1;
126 static int hf_connection_info_num_addr = -1;
128 /* hf_bandwidth subfields */
129 static int hf_bandwidth_modifier = -1;
130 static int hf_bandwidth_value = -1;
132 /* hf_time subfields */
133 static int hf_time_start = -1;
134 static int hf_time_stop = -1;
136 /* hf_repeat_time subfield */
137 static int hf_repeat_time_interval = -1;
138 static int hf_repeat_time_duration = -1;
139 static int hf_repeat_time_offset = -1;
141 /* hf_timezone subfields */
142 static int hf_timezone_time = -1;
143 static int hf_timezone_offset = -1;
145 /* hf_encryption_key subfields */
146 static int hf_encryption_key_type = -1;
147 static int hf_encryption_key_data = -1;
149 /* hf_session_attribute subfields */
150 static int hf_session_attribute_field = -1;
151 static int hf_session_attribute_value = -1;
153 /* hf_media subfields */
154 static int hf_media_media = -1;
155 static int hf_media_port = -1;
156 static int hf_media_portcount = -1;
157 static int hf_media_proto = -1;
158 static int hf_media_format = -1;
160 /* hf_session_attribute subfields */
161 static int hf_media_attribute_field = -1;
162 static int hf_media_attribute_value = -1;
163 static int hf_media_encoding_name = -1;
164 static int hf_media_format_specific_parameter = -1;
165 static int hf_sdp_fmtp_profile_level_id = -1;
166 static int hf_sdp_fmtp_h263_profile = -1;
167 static int hf_SDPh223LogicalChannelParameters = -1;
169 /* hf_session_attribute hf_media_attribute subfields */
170 static int hf_key_mgmt_att_value = -1;
171 static int hf_key_mgmt_prtcl_id = -1;
172 static int hf_key_mgmt_data = -1;
175 static int ett_sdp = -1;
176 static int ett_sdp_owner = -1;
177 static int ett_sdp_connection_info = -1;
178 static int ett_sdp_bandwidth = -1;
179 static int ett_sdp_time = -1;
180 static int ett_sdp_repeat_time = -1;
181 static int ett_sdp_timezone = -1;
182 static int ett_sdp_encryption_key = -1;
183 static int ett_sdp_session_attribute = -1;
184 static int ett_sdp_media = -1;
185 static int ett_sdp_media_attribute = -1;
186 static int ett_sdp_fmtp = -1;
187 static int ett_sdp_key_mgmt = -1;
190 #define SDP_MAX_RTP_CHANNELS 4
191 #define SDP_MAX_RTP_PAYLOAD_TYPES 20
194 gint32 pt[SDP_MAX_RTP_PAYLOAD_TYPES];
196 GHashTable *rtp_dyn_payload;
197 } transport_media_pt_t;
200 char *connection_address;
201 char *connection_type;
203 char *media_port[SDP_MAX_RTP_CHANNELS];
204 char *media_proto[SDP_MAX_RTP_CHANNELS];
205 transport_media_pt_t media[SDP_MAX_RTP_CHANNELS];
210 /* MSRP transport info (as set while parsing path attribute) */
211 static gboolean msrp_transport_address_set = FALSE;
212 static guint32 msrp_ipaddr[4];
213 static guint16 msrp_port_number;
215 /* key-mgmt dissector
217 * http://www.iana.org/assignments/sdp-parameters
219 static dissector_table_t key_mgmt_dissector_table;
222 /* Protocol registration */
223 void proto_register_sdp(void);
224 void proto_reg_handoff_sdp(void);
227 /* static functions */
229 static void call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti,
230 transport_info_t *transport_info);
232 /* Subdissector functions */
233 static void dissect_sdp_owner(tvbuff_t *tvb, proto_item* ti);
234 static void dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
235 transport_info_t *transport_info);
236 static void dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti);
237 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti);
238 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti);
239 static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti);
240 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti);
241 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti);
242 static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
243 transport_info_t *transport_info);
244 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti, transport_info_t *transport_info);
247 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
249 proto_tree *sdp_tree;
250 proto_item *ti, *sub_ti;
254 gboolean in_media_description;
264 transport_info_t transport_info;
267 gboolean is_rtp=FALSE;
268 gboolean is_srtp=FALSE;
269 gboolean is_t38=FALSE;
270 gboolean is_msrp=FALSE;
271 gboolean set_rtp=FALSE;
272 gboolean is_ipv4_addr=FALSE;
273 gboolean is_ipv6_addr=FALSE;
276 sdp_packet_info *sdp_pi;
278 /* Initialise packet info for passing to tap */
279 sdp_pi = ep_alloc(sizeof(sdp_packet_info));
280 sdp_pi->summary_str[0] = '\0';
282 /* Initialise RTP channel info */
283 transport_info.connection_address=NULL;
284 transport_info.connection_type=NULL;
285 transport_info.encoding_name=NULL;
286 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++)
288 transport_info.media_port[n]=NULL;
289 transport_info.media_proto[n]=NULL;
290 transport_info.media[n].pt_count = 0;
291 #if GLIB_MAJOR_VERSION < 2
292 transport_info.media[n].rtp_dyn_payload = g_hash_table_new( g_int_hash,
295 transport_info.media[n].rtp_dyn_payload = g_hash_table_new_full( g_int_hash,
296 g_int_equal, g_free, g_free);
299 transport_info.media_count = 0;
302 * As RFC 2327 says, "SDP is purely a format for session
303 * description - it does not incorporate a transport protocol,
304 * and is intended to use different transport protocols as
305 * appropriate including the Session Announcement Protocol,
306 * Session Initiation Protocol, Real-Time Streaming Protocol,
307 * electronic mail using the MIME extensions, and the
308 * Hypertext Transport Protocol."
310 * We therefore don't set the protocol or info columns;
311 * instead, we append to them, so that we don't erase
312 * what the protocol inside which the SDP stuff resides
315 if (check_col(pinfo->cinfo, COL_PROTOCOL))
316 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
318 if (check_col(pinfo->cinfo, COL_INFO)) {
319 /* XXX: Needs description. */
320 col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
323 ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
324 sdp_tree = proto_item_add_subtree(ti, ett_sdp);
327 * Show the SDP message a line at a time.
329 in_media_description = FALSE;
331 while (tvb_reported_length_remaining(tvb, offset) > 0) {
333 * Find the end of the line.
335 linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
340 * Line must contain at least e.g. "v=".
345 type = tvb_get_guint8(tvb,offset);
346 delim = tvb_get_guint8(tvb,offset + 1);
348 proto_item *ti = proto_tree_add_item(sdp_tree, hf_invalid, tvb, offset, linelen, FALSE);
349 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_NOTE,
350 "Invalid SDP line (no '=' delimiter)");
351 offset = next_offset;
360 hf = hf_protocol_version;
366 hf = hf_session_name;
369 if (in_media_description) {
373 hf = hf_session_info;
386 hf = hf_connection_info;
399 in_media_description = TRUE;
402 hf = hf_encryption_key;
405 if (in_media_description) {
406 hf = hf_media_attribute;
409 hf = hf_session_attribute;
420 if (hf == hf_unknown)
422 string = (char*)tvb_get_ephemeral_string(tvb, offset + tokenoffset,
423 linelen - tokenoffset);
424 sub_ti = proto_tree_add_string(sdp_tree, hf, tvb, offset, linelen,
426 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
428 linelen-tokenoffset),
430 hf,sub_ti,&transport_info),
431 offset = next_offset;
435 /* Now look, if we have strings collected.
436 * Try to convert ipv4 addresses and ports into binary format,
437 * so we can use them to detect rtp and rtcp streams.
438 * Don't forget to free the strings!
441 for (n = 0; n < transport_info.media_count; n++)
443 if(transport_info.media_port[n]!=NULL) {
444 port = atol(transport_info.media_port[n]);
446 if(transport_info.media_proto[n]!=NULL) {
447 /* Check if media protocol is RTP
448 * and stream decoding is enabled in preferences
450 if(global_sdp_establish_conversation){
451 /* Check if media protocol is RTP */
452 is_rtp = (strcmp(transport_info.media_proto[n],"RTP/AVP")==0);
453 /* Check if media protocol is SRTP */
454 is_srtp = (strcmp(transport_info.media_proto[n],"RTP/SAVP")==0);
455 /* Check if media protocol is T38 */
456 is_t38 = ( (strcmp(transport_info.media_proto[n],"UDPTL")==0) || (strcmp(transport_info.media_proto[n],"udptl")==0) );
457 /* Check if media protocol is MSRP/TCP */
458 is_msrp = (strcmp(transport_info.media_proto[n],"msrp/tcp")==0);
463 if(transport_info.connection_address!=NULL) {
464 if(transport_info.connection_type!=NULL) {
465 if (strcmp(transport_info.connection_type,"IP4")==0) {
466 if(inet_pton(AF_INET,transport_info.connection_address, &ipaddr)==1 ) {
467 /* connection_address could be converted to a valid ipv4 address*/
469 src_addr.type=AT_IPv4;
473 else if (strcmp(transport_info.connection_type,"IP6")==0){
474 if (inet_pton(AF_INET6, transport_info.connection_address, &ipaddr)==1){
475 /* connection_address could be converted to a valid ipv6 address*/
477 src_addr.type=AT_IPv6;
484 /* Add (s)rtp and (s)rtcp conversation, if available (overrides t38 if conversation already set) */
485 if((!pinfo->fd->flags.visited) && port!=0 && (is_rtp||is_srtp) && (is_ipv4_addr || is_ipv6_addr)){
486 src_addr.data=(guint8*)&ipaddr;
489 struct srtp_info *dummy_srtp_info = se_alloc0(sizeof(struct srtp_info));
490 srtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num,
491 transport_info.media[n].rtp_dyn_payload, dummy_srtp_info);
493 rtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num,
494 transport_info.media[n].rtp_dyn_payload);
500 rtcp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
504 /* Add t38 conversation, if available and only if no rtp */
505 if((!pinfo->fd->flags.visited) && port!=0 && !set_rtp && is_t38 && is_ipv4_addr){
506 src_addr.data=(guint8*)&ipaddr;
508 t38_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
512 /* Add MSRP conversation. Uses addresses discovered in attribute
513 rather than connection information of media session line */
515 if ((!pinfo->fd->flags.visited) && msrp_transport_address_set){
517 src_addr.type=AT_IPv4;
519 src_addr.data=(guint8*)&msrp_ipaddr;
520 msrp_add_address(pinfo, &src_addr, msrp_port_number, "SDP", pinfo->fd->num);
525 /* Create the RTP summary str for the Voip Call analysis */
526 for (i = 0; i < transport_info.media[n].pt_count; i++)
528 /* if the payload type is dynamic (96 to 127), check the hash table to add the desc in the SDP summary */
529 if ( (transport_info.media[n].pt[i] >=96) && (transport_info.media[n].pt[i] <=127) ) {
530 gchar *str_dyn_pt = g_hash_table_lookup(transport_info.media[n].rtp_dyn_payload, &transport_info.media[n].pt[i]);
532 g_snprintf(sdp_pi->summary_str, 50, "%s %s", sdp_pi->summary_str, str_dyn_pt);
534 g_snprintf(sdp_pi->summary_str, 50, "%s %d", sdp_pi->summary_str, transport_info.media[n].pt[i]);
536 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"));
539 /* Free the hash table if we did't assigned it to a conv use it */
540 if (set_rtp == FALSE)
541 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
543 /* Create the T38 summary str for the Voip Call analysis */
544 if (is_t38) g_snprintf(sdp_pi->summary_str, 50, "%s t38", sdp_pi->summary_str);
547 /* Free the remainded hash tables not used */
548 for (n = transport_info.media_count; n < SDP_MAX_RTP_CHANNELS; n++)
550 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
554 datalen = tvb_length_remaining(tvb, offset);
556 proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)",
560 /* Report this packet to the tap */
561 tap_queue_packet(sdp_tap, pinfo, sdp_pi);
565 call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, transport_info_t *transport_info){
567 dissect_sdp_owner(tvb,ti);
568 } else if ( hf == hf_connection_info) {
569 dissect_sdp_connection_info(tvb,ti,transport_info);
570 } else if ( hf == hf_bandwidth) {
571 dissect_sdp_bandwidth(tvb,ti);
572 } else if ( hf == hf_time) {
573 dissect_sdp_time(tvb,ti);
574 } else if ( hf == hf_repeat_time ){
575 dissect_sdp_repeat_time(tvb,ti);
576 } else if ( hf == hf_timezone ) {
577 dissect_sdp_timezone(tvb,ti);
578 } else if ( hf == hf_encryption_key ) {
579 dissect_sdp_encryption_key(tvb,ti);
580 } else if ( hf == hf_session_attribute ){
581 dissect_sdp_session_attribute(tvb,pinfo,ti);
582 } else if ( hf == hf_media ) {
583 dissect_sdp_media(tvb,ti,transport_info);
584 } else if ( hf == hf_media_attribute ){
585 dissect_sdp_media_attribute(tvb,pinfo,ti,transport_info);
590 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
591 proto_tree *sdp_owner_tree;
592 gint offset,next_offset,tokenlen;
598 sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
600 /* Find the username */
601 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
602 if( next_offset == -1 )
604 tokenlen = next_offset - offset;
606 proto_tree_add_item(sdp_owner_tree, hf_owner_username, tvb, offset, tokenlen,
608 offset = next_offset + 1;
610 /* Find the session id */
611 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
612 if( next_offset == -1 )
614 tokenlen = next_offset - offset;
616 proto_tree_add_item(sdp_owner_tree, hf_owner_sessionid, tvb, offset,
618 offset = next_offset + 1;
620 /* Find the version */
621 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
622 if( next_offset == -1 )
624 tokenlen = next_offset - offset;
626 proto_tree_add_item(sdp_owner_tree, hf_owner_version, tvb, offset, tokenlen,
628 offset = next_offset + 1;
630 /* Find the network type */
631 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
632 if( next_offset == -1 )
634 tokenlen = next_offset - offset;
636 proto_tree_add_item(sdp_owner_tree, hf_owner_network_type, tvb, offset,
638 offset = next_offset + 1;
640 /* Find the address type */
641 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
642 if( next_offset == -1 )
644 tokenlen = next_offset - offset;
646 proto_tree_add_item(sdp_owner_tree, hf_owner_address_type, tvb, offset,
648 offset = next_offset + 1;
650 /* Find the address */
651 proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
655 * XXX - this can leak memory if an exception is thrown after we've fetched
659 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
660 transport_info_t *transport_info){
661 proto_tree *sdp_connection_info_tree;
662 gint offset,next_offset,tokenlen;
668 sdp_connection_info_tree = proto_item_add_subtree(ti,
669 ett_sdp_connection_info);
671 /* Find the network type */
672 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
673 if( next_offset == -1 )
675 tokenlen = next_offset - offset;
677 proto_tree_add_item(sdp_connection_info_tree,
678 hf_connection_info_network_type, tvb, offset, tokenlen,
680 offset = next_offset + 1;
682 /* Find the address type */
683 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
684 if( next_offset == -1 )
686 tokenlen = next_offset - offset;
687 /* Save connection address type */
688 transport_info->connection_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
691 proto_tree_add_item(sdp_connection_info_tree,
692 hf_connection_info_address_type, tvb, offset, tokenlen,
694 offset = next_offset + 1;
696 /* Find the connection address */
697 /* XXX - what if there's a <number of addresses> value? */
698 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
699 if( next_offset == -1){
700 tokenlen = -1; /* end of tvbuff */
701 /* Save connection address */
702 transport_info->connection_address =
703 (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
705 tokenlen = next_offset - offset;
706 /* Save connection address */
707 transport_info->connection_address = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
710 proto_tree_add_item(sdp_connection_info_tree,
711 hf_connection_info_connection_address, tvb, offset,
713 if(next_offset != -1){
714 offset = next_offset + 1;
715 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
716 if( next_offset == -1){
717 tokenlen = -1; /* end of tvbuff */
719 tokenlen = next_offset - offset;
721 proto_tree_add_item(sdp_connection_info_tree,
722 hf_connection_info_ttl, tvb, offset, tokenlen, FALSE);
723 if(next_offset != -1){
724 offset = next_offset + 1;
725 proto_tree_add_item(sdp_connection_info_tree,
726 hf_connection_info_num_addr, tvb, offset, -1, FALSE);
732 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
733 proto_tree * sdp_bandwidth_tree;
734 gint offset, next_offset, tokenlen;
736 gboolean unit_is_kbs = FALSE;
737 gboolean unit_is_bps = FALSE;
743 sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
745 /* find the modifier */
746 next_offset = tvb_find_guint8(tvb,offset,-1,':');
748 if( next_offset == -1)
751 tokenlen = next_offset - offset;
753 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier, tvb, offset,
755 if (tvb_strneql(tvb, offset, "CT", 2) == 0){
756 proto_item_append_text(item, " [Conference Total(total bandwidth of all RTP sessions)]");
758 }else if (tvb_strneql(tvb, offset, "AS", 2) == 0){
759 proto_item_append_text(item, " [Application Specific (RTP session bandwidth)]");
761 }else if (tvb_strneql(tvb, offset, "TIAS", 4) == 0){
762 proto_item_append_text(item, " [Transport Independent Application Specific maximum]");
767 offset = next_offset + 1;
769 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value, tvb, offset, -1,
771 if (unit_is_kbs == TRUE)
772 proto_item_append_text(item, " kb/s");
773 if (unit_is_bps == TRUE)
774 proto_item_append_text(item, " b/s");
777 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
778 proto_tree *sdp_time_tree;
779 gint offset,next_offset, tokenlen;
785 sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
788 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
789 if( next_offset == -1 )
792 tokenlen = next_offset - offset;
793 proto_tree_add_item(sdp_time_tree, hf_time_start, tvb, offset, tokenlen,
797 offset = next_offset + 1;
798 proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb, offset, -1, FALSE);
801 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
802 proto_tree *sdp_repeat_time_tree;
803 gint offset,next_offset, tokenlen;
809 sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
812 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
813 if( next_offset == -1 )
816 tokenlen = next_offset - offset;
817 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
818 offset, tokenlen, FALSE);
821 offset = next_offset + 1;
822 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
823 if( next_offset == -1 )
826 tokenlen = next_offset - offset;
827 proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
828 offset, tokenlen, FALSE);
832 offset = next_offset +1;
833 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
834 if(next_offset != -1){
835 tokenlen = next_offset - offset;
837 tokenlen = -1; /* end of tvbuff */
839 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
840 tvb, offset, tokenlen, FALSE);
841 } while( next_offset != -1 );
845 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
846 proto_tree* sdp_timezone_tree;
847 gint offset, next_offset, tokenlen;
852 sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
855 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
856 if(next_offset == -1)
858 tokenlen = next_offset - offset;
860 proto_tree_add_item(sdp_timezone_tree, hf_timezone_time, tvb, offset,
862 offset = next_offset + 1;
863 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
864 if(next_offset != -1){
865 tokenlen = next_offset - offset;
867 tokenlen = -1; /* end of tvbuff */
869 proto_tree_add_item(sdp_timezone_tree, hf_timezone_offset, tvb, offset,
871 offset = next_offset + 1;
872 } while (next_offset != -1);
877 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
878 proto_tree *sdp_encryption_key_tree;
879 gint offset, next_offset, tokenlen;
885 sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
887 next_offset = tvb_find_guint8(tvb,offset,-1,':');
889 if(next_offset == -1)
892 tokenlen = next_offset - offset;
894 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
895 tvb, offset, tokenlen, FALSE);
897 offset = next_offset + 1;
898 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
899 tvb, offset, -1, FALSE);
902 /* Return a tvb that contains the binary representation of a base64
906 base64_to_tvb(const char *base64)
909 char *data = g_strdup(base64);
912 len = epan_base64_decode(data);
913 tvb = tvb_new_real_data((const guint8 *)data, len, len);
915 tvb_set_free_cb(tvb, g_free);
921 static void dissect_key_mgmt(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
923 gchar *prtcl_id = NULL;
925 tvbuff_t *keymgmt_tvb;
926 gboolean found_match = FALSE;
927 proto_tree *key_tree;
932 key_tree = proto_item_add_subtree(ti, ett_sdp_key_mgmt);
934 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
936 if (next_offset == -1)
939 tokenlen = next_offset - offset;
940 prtcl_id = tvb_get_ephemeral_string(tvb, offset, tokenlen);
942 proto_tree_add_item(key_tree, hf_key_mgmt_prtcl_id, tvb, offset, tokenlen, FALSE);
944 offset = next_offset + 1;
946 len = tvb_length_remaining(tvb, offset);
950 data = tvb_get_ephemeral_string(tvb, offset, len);
951 keymgmt_tvb = base64_to_tvb(data);
952 tvb_set_child_real_data_tvbuff(tvb, keymgmt_tvb);
953 add_new_data_source(pinfo, keymgmt_tvb, "Key Management Data");
955 if ( prtcl_id != NULL && key_mgmt_dissector_table != NULL ) {
956 found_match = dissector_try_string(key_mgmt_dissector_table,
963 proto_tree_add_item_hidden(key_tree, hf_key_mgmt_data,
964 keymgmt_tvb, 0, -1, FALSE);
966 proto_tree_add_item(key_tree, hf_key_mgmt_data,
967 keymgmt_tvb, 0, -1, FALSE);
972 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
973 proto_tree *sdp_session_attribute_tree;
974 gint offset, next_offset, tokenlen;
981 sdp_session_attribute_tree = proto_item_add_subtree(ti,
982 ett_sdp_session_attribute);
984 next_offset = tvb_find_guint8(tvb,offset,-1,':');
986 if(next_offset == -1)
989 tokenlen = next_offset - offset;
991 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_field,
992 tvb, offset, tokenlen, FALSE);
994 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
996 offset = next_offset + 1;
998 if (strcmp((char*)field_name, "ipbcp") == 0) {
999 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"0123456789");
1004 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1006 if (next_offset == -1)
1009 tokenlen = next_offset - offset;
1011 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_version,tvb,offset,tokenlen,FALSE);
1013 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
1018 tokenlen = tvb_find_line_end(tvb,offset,-1, &next_offset, FALSE);
1023 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE);
1024 } else if (strcmp((char*)field_name, "key-mgmt") == 0) {
1028 key_tvb = tvb_new_subset(tvb, offset, -1, -1);
1029 key_ti = proto_tree_add_item(sdp_session_attribute_tree, hf_key_mgmt_att_value, key_tvb, 0, -1, FALSE);
1031 dissect_key_mgmt(key_tvb, pinfo, key_ti);
1033 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value,
1034 tvb, offset, -1, FALSE);
1039 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
1040 transport_info_t *transport_info){
1041 proto_tree *sdp_media_tree;
1042 gint offset, next_offset, tokenlen, index;
1043 guint8 *media_format;
1049 /* Re-initialise for a new media description */
1050 msrp_transport_address_set = FALSE;
1052 sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
1054 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1056 if(next_offset == -1)
1059 tokenlen = next_offset - offset;
1061 proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, offset, tokenlen,
1064 offset = next_offset + 1;
1066 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1067 if(next_offset == -1)
1069 tokenlen = next_offset - offset;
1070 next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
1072 if(next_offset != -1){
1073 tokenlen = next_offset - offset;
1074 /* Save port info */
1075 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1077 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1078 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1079 offset = next_offset + 1;
1080 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1081 if(next_offset == -1)
1083 tokenlen = next_offset - offset;
1084 proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb, offset,
1086 offset = next_offset + 1;
1088 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1090 if(next_offset == -1)
1092 tokenlen = next_offset - offset;
1093 /* Save port info */
1094 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1096 /* XXX Remember Port */
1097 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1098 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1099 offset = next_offset + 1;
1102 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1104 if( next_offset == -1)
1107 tokenlen = next_offset - offset;
1108 /* Save port protocol */
1109 transport_info->media_proto[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1111 /* XXX Remember Protocol */
1112 proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb, offset, tokenlen,
1116 offset = next_offset + 1;
1117 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1119 if(next_offset == -1){
1120 tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
1122 break; /* Nothing more left */
1124 tokenlen = next_offset - offset;
1127 if (strcmp(transport_info->media_proto[transport_info->media_count],
1129 media_format = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1130 proto_tree_add_string(sdp_media_tree, hf_media_format, tvb, offset,
1131 tokenlen, val_to_str(atol((char*)media_format), rtp_payload_type_vals, "%u"));
1132 index = transport_info->media[transport_info->media_count].pt_count;
1133 transport_info->media[transport_info->media_count].pt[index] = atol((char*)media_format);
1134 if (index < (SDP_MAX_RTP_PAYLOAD_TYPES-1))
1135 transport_info->media[transport_info->media_count].pt_count++;
1137 proto_tree_add_item(sdp_media_tree, hf_media_format, tvb, offset,
1140 } while (next_offset != -1);
1142 /* Increase the count of media channels, but don't walk off the end
1144 if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
1145 transport_info->media_count++;
1148 /* XXX Dissect traffic to "Port" as "Protocol"
1149 * Remember this Port/Protocol pair so we can tear it down again later
1150 * Actually, it's harder than that:
1151 * We need to find out the address of the other side first and it
1152 * looks like that info can be found in SIP headers only.
1157 tvbuff_t *ascii_bytes_to_tvb(tvbuff_t *tvb, proto_tree *tree _U_, packet_info *pinfo, gint offset _U_, gint len, gchar *msg)
1159 guint8 *buf = ep_alloc(10240);
1161 /* arbitrary maximum length */
1164 tvbuff_t *bytes_tvb;
1166 /* first, skip to where the encoded pdu starts, this is
1167 the first hex digit after the '=' char.
1170 if((*msg==0)||(*msg=='\n')){
1180 if((*msg==0)||(*msg=='\n')){
1183 if( ((*msg>='0')&&(*msg<='9'))
1184 || ((*msg>='a')&&(*msg<='f'))
1185 || ((*msg>='A')&&(*msg<='F'))){
1191 while( ((*msg>='0')&&(*msg<='9'))
1192 ||((*msg>='a')&&(*msg<='f'))
1193 ||((*msg>='A')&&(*msg<='F')) ){
1195 if((*msg>='0')&&(*msg<='9')){
1197 } else if((*msg>='a')&&(*msg<='f')){
1199 } else if((*msg>='A')&&(*msg<='F')){
1206 if((*msg>='0')&&(*msg<='9')){
1208 } else if((*msg>='a')&&(*msg<='f')){
1210 } else if((*msg>='A')&&(*msg<='F')){
1223 bytes_tvb = tvb_new_real_data(buf,i,i);
1224 tvb_set_child_real_data_tvbuff(tvb,bytes_tvb);
1225 add_new_data_source(pinfo, bytes_tvb, "ASCII bytes to tvb");
1231 14496-2, Annex G, Table G-1.
1232 Table G-1 FLC table for profile_and_level_indication Profile/Level Code
1234 static const value_string mpeg4es_level_indication_vals[] =
1237 { 1, "Simple Profile/Level 1" },
1238 { 2, "Simple Profile/Level 2" },
1244 { 8, "Simple Profile/Level 0" },
1245 { 9, "Simple Profile/Level 0b" },
1246 /* Reserved 00001001 - 00010000 */
1247 { 0x11, "Simple Scalable Profile/Level 1" },
1248 { 0x12, "Simple Scalable Profile/Level 2" },
1249 /* Reserved 00010011 - 00100000 */
1250 { 0x21, "Core Profile/Level 1" },
1251 { 0x22, "Core Profile/Level 2" },
1252 /* Reserved 00100011 - 00110001 */
1253 { 0x32, "Main Profile/Level 2" },
1254 { 0x33, "Main Profile/Level 3" },
1255 { 0x34, "Main Profile/Level 4" },
1256 /* Reserved 00110101 - 01000001 */
1257 { 0x42, "N-bit Profile/Level 2" },
1258 /* Reserved 01000011 - 01010000 */
1259 { 0x51, "Scalable Texture Profile/Level 1" },
1260 /* Reserved 01010010 - 01100000 */
1261 { 0x61, "Simple Face Animation Profile/Level 1" },
1262 { 0x62, "Simple Face Animation Profile/Level 2" },
1263 { 0x63, "Simple FBA Profile/Level 1" },
1264 { 0x64, "Simple FBA Profile/Level 2" },
1265 /* Reserved 01100101 - 01110000 */
1266 { 0x71, "Basic Animated Texture Profile/Level 1" },
1267 { 0x72, "Basic Animated Texture Profile/Level 2" },
1268 /* Reserved 01110011 - 10000000 */
1269 { 0x81, "Hybrid Profile/Level 1" },
1270 { 0x82, "Hybrid Profile/Level 2" },
1271 /* Reserved 10000011 - 10010000 */
1272 { 0x91, "Advanced Real Time Simple Profile/Level 1" },
1273 { 0x92, "Advanced Real Time Simple Profile/Level 2" },
1274 { 0x93, "Advanced Real Time Simple Profile/Level 3" },
1275 { 0x94, "Advanced Real Time Simple Profile/Level 4" },
1276 /* Reserved 10010101 - 10100000 */
1277 { 0xa1, "Core Scalable Profile/Level 1" },
1278 { 0xa2, "Core Scalable Profile/Level 2" },
1279 { 0xa3, "Core Scalable Profile/Level 3" },
1280 /* Reserved 10100100 - 10110000 */
1281 { 0xb1, "Advanced Coding Efficiency Profile/Level 1" },
1282 { 0xb2, "Advanced Coding Efficiency Profile/Level 2" },
1283 { 0xb3, "Advanced Coding Efficiency Profile/Level 3" },
1284 { 0xb4, "Advanced Coding Efficiency Profile/Level 4" },
1285 /* Reserved 10110101 - 11000000 */
1286 { 0xc1, "Advanced Core Profile/Level 1" },
1287 { 0xc2, "Advanced Core Profile/Level 2" },
1288 /* Reserved 11000011 - 11010000 */
1289 { 0xd1, "Advanced Scalable Texture/Level 1" },
1290 { 0xd2, "Advanced Scalable Texture/Level 2" },
1291 { 0xd3, "Advanced Scalable Texture/Level 3" },
1292 /* Reserved 11010100 - 11100000 */
1293 { 0xe1, "Simple Studio Profile/Level 1" },
1294 { 0xe2, "Simple Studio Profile/Level 2" },
1295 { 0xe3, "Simple Studio Profile/Level 3" },
1296 { 0xe4, "Simple Studio Profile/Level 4" },
1297 { 0xe5, "Core Studio Profile/Level 1" },
1298 { 0xe6, "Core Studio Profile/Level 2" },
1299 { 0xe7, "Core Studio Profile/Level 3" },
1300 { 0xe8, "Core Studio Profile/Level 4" },
1301 /* Reserved 11101001 - 11101111 */
1302 { 0xf0, "Advanced Simple Profile/Level 0" },
1303 { 0xf1, "Advanced Simple Profile/Level 1" },
1304 { 0xf2, "Advanced Simple Profile/Level 2" },
1305 { 0xf3, "Advanced Simple Profile/Level 3" },
1306 { 0xf4, "Advanced Simple Profile/Level 4" },
1307 { 0xf5, "Advanced Simple Profile/Level 5" },
1308 /* Reserved 11110110 - 11110111 */
1309 { 0xf8, "Fine Granularity Scalable Profile/Level 0" },
1310 { 0xf9, "Fine Granularity Scalable Profile/Level 1" },
1311 { 0xfa, "Fine Granularity Scalable Profile/Level 2" },
1312 { 0xfb, "Fine Granularity Scalable Profile/Level 3" },
1313 { 0xfc, "Fine Granularity Scalable Profile/Level 4" },
1314 { 0xfd, "Fine Granularity Scalable Profile/Level 5" },
1315 { 0xfe, "Reserved" },
1316 { 0xff, "Reserved for Escape" },
1319 /* Annex X Profiles and levels definition */
1320 static const value_string h263_profile_vals[] =
1322 { 0, "Baseline Profile" },
1323 { 1, "H.320 Coding Efficiency Version 2 Backward-Compatibility Profile" },
1324 { 2, "Version 1 Backward-Compatibility Profile" },
1325 { 3, "Version 2 Interactive and Streaming Wireless Profile" },
1326 { 4, "Version 3 Interactive and Streaming Wireless Profile" },
1327 { 5, "Conversational High Compression Profile" },
1328 { 6, "Conversational Internet Profile" },
1329 { 7, "Conversational Interlace Profile" },
1330 { 8, "High Latency Profile" },
1335 * TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
1338 decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint tokenlen, guint8 *mime_type){
1342 gchar *format_specific_parameter;
1345 end_offset = offset + tokenlen;
1347 /* Look for an '=' within this value - this may indicate that there is a
1348 profile-level-id parameter to find if the MPEG4 media type is in use */
1349 next_offset = tvb_find_guint8(tvb,offset,-1,'=');
1350 if (next_offset == -1)
1352 /* Give up (and avoid exception) if '=' not found */
1356 /* Find the name of the parameter */
1357 tokenlen = next_offset - offset;
1358 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1360 offset = next_offset;
1362 /* Dissect the MPEG4 profile-level-id parameter if present */
1363 if (mime_type != NULL && strcmp((char*)mime_type, "MP4V-ES") == 0) {
1364 if (strcmp((char*)field_name, "profile-level-id") == 0) {
1366 tokenlen = end_offset - offset;
1367 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1368 item = proto_tree_add_uint(tree, hf_sdp_fmtp_profile_level_id, tvb, offset, tokenlen,
1369 atol((char*)format_specific_parameter));
1370 PROTO_ITEM_SET_GENERATED(item);
1374 /* Dissect the H263-2000 profile parameter if present */
1375 if (mime_type != NULL && strcmp((char*)mime_type, "H263-2000") == 0) {
1376 if (strcmp((char*)field_name, "profile") == 0) {
1378 tokenlen = end_offset - offset;
1379 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1380 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_profile, tvb, offset, tokenlen,
1381 atol((char*)format_specific_parameter));
1382 PROTO_ITEM_SET_GENERATED(item);
1387 /* Dissect the H264 profile-level-id parameter */
1388 if (mime_type != NULL && strcmp(mime_type, "H264") == 0) {
1389 if (strcmp(field_name, "profile-level-id") == 0) {
1390 tvbuff_t *h264_profile_tvb;
1392 /* Length includes "=" */
1393 tokenlen = end_offset - offset;
1394 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1395 h264_profile_tvb = ascii_bytes_to_tvb(tvb, tree, pinfo, offset, tokenlen, format_specific_parameter);
1396 if(h264_handle && h264_profile_tvb){
1397 dissect_h264_profile(h264_profile_tvb, pinfo, tree);
1408 #define SDP_RTPMAP 1
1411 #define SDP_H248_ITEM 4
1413 static const sdp_names_t sdp_media_attribute_names[] = {
1414 { "Unknown-name"}, /* 0 Pad so that the real headers start at index 1 */
1415 { "rtpmap"}, /* 1 */
1418 { "h248item"}, /* 4 */
1421 static gint find_sdp_media_attribute_names(tvbuff_t *tvb, int offset, guint len)
1425 for (i = 1; i < array_length(sdp_media_attribute_names); i++) {
1426 if (len == strlen(sdp_media_attribute_names[i].name) &&
1427 tvb_strncaseeql(tvb, offset, sdp_media_attribute_names[i].name, len) == 0)
1434 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item * ti, transport_info_t *transport_info){
1435 proto_tree *sdp_media_attribute_tree;
1436 proto_item *fmtp_item, *media_format_item;
1437 proto_tree *fmtp_tree;
1438 gint offset, next_offset, tokenlen, n;
1440 guint8 *payload_type;
1441 guint8 *attribute_value;
1443 gint sdp_media_attrbute_code;
1444 const char *msrp_res = "msrp://";
1445 const char *h324ext_h223lcparm = "h324ext/h223lcparm";
1451 /* Create attribute tree */
1452 sdp_media_attribute_tree = proto_item_add_subtree(ti,
1453 ett_sdp_media_attribute);
1454 /* Find end of field */
1455 next_offset = tvb_find_guint8(tvb,offset,-1,':');
1457 if(next_offset == -1)
1460 /* Attribute field name is token before ':' */
1461 tokenlen = next_offset - offset;
1462 proto_tree_add_item(sdp_media_attribute_tree,
1463 hf_media_attribute_field,
1464 tvb, offset, tokenlen, FALSE);
1465 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1466 sdp_media_attrbute_code = find_sdp_media_attribute_names(tvb, offset, tokenlen);
1469 offset = next_offset + 1;
1471 /* Value is the remainder of the line */
1472 attribute_value = tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
1476 /*********************************************/
1477 /* Special parsing for some field name types */
1479 switch (sdp_media_attrbute_code){
1481 /* decode the rtpmap to see if it is DynamicPayload to dissect them automatic */
1482 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1484 if(next_offset == -1)
1487 tokenlen = next_offset - offset;
1489 proto_tree_add_item(sdp_media_attribute_tree, hf_media_format, tvb,
1490 offset, tokenlen, FALSE);
1492 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1494 offset = next_offset + 1;
1496 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
1498 if(next_offset == -1){
1502 tokenlen = next_offset - offset;
1504 proto_tree_add_item(sdp_media_attribute_tree, hf_media_encoding_name, tvb,
1505 offset, tokenlen, FALSE);
1506 /* get_string is needed here as the string is "saved" in a hashtable */
1507 transport_info->encoding_name = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1509 key=g_malloc( sizeof(gint) );
1510 *key=atol((char*)payload_type);
1512 /* As per RFC2327 it is possible to have multiple Media Descriptions ("m=").
1515 a=rtpmap:101 G726-32/8000
1516 m=audio 49170 RTP/AVP 0 97
1517 a=rtpmap:97 telephone-event/8000
1518 m=audio 49172 RTP/AVP 97 101
1519 a=rtpmap:97 G726-24/8000
1521 The Media attributes ("a="s) after the "m=" only apply for that "m=".
1522 If there is an "a=" before the first "m=", that attribute applies for
1523 all the session (all the "m="s).
1526 /* so, if this "a=" appear before any "m=", we add it to all the dynamic
1529 if (transport_info->media_count == 0) {
1530 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++) {
1532 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1533 key, g_strdup(transport_info->encoding_name));
1534 else { /* we create a new key and encoding_name to assign to the other hash tables */
1536 key2=g_malloc( sizeof(gint) );
1537 *key2=atol((char*)payload_type);
1538 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1539 key2, g_strdup(transport_info->encoding_name));
1543 /* if the "a=" is after an "m=", only apply to this "m=" */
1545 /* in case there is an overflow in SDP_MAX_RTP_CHANNELS, we keep always the last "m=" */
1546 if (transport_info->media_count == SDP_MAX_RTP_CHANNELS-1)
1547 g_hash_table_insert(transport_info->media[ transport_info->media_count ].rtp_dyn_payload,
1548 key, g_strdup(transport_info->encoding_name));
1550 g_hash_table_insert(transport_info->media[ transport_info->media_count-1 ].rtp_dyn_payload,
1551 key, g_strdup(transport_info->encoding_name));
1555 /* Reading the Format parameter(fmtp) */
1556 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1558 if(next_offset == -1)
1561 tokenlen = next_offset - offset;
1563 /* Media format extends to the next space */
1564 media_format_item = proto_tree_add_item(sdp_media_attribute_tree,
1565 hf_media_format, tvb, offset,
1567 /* Append encoding name to format if known */
1568 if (transport_info->encoding_name)
1569 proto_item_append_text(media_format_item, " [%s]",
1570 transport_info->encoding_name);
1572 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1574 offset = next_offset + 1;
1576 /* There may be 2 parameters given
1577 * TODO: Handle arbitary number of parameters.
1579 next_offset = tvb_find_guint8(tvb,offset,-1,';');
1581 if(next_offset != -1){
1582 /* There are 2 - add the first parameter */
1583 tokenlen = next_offset - offset;
1584 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1585 hf_media_format_specific_parameter, tvb,
1586 offset, tokenlen, FALSE);
1588 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1590 decode_sdp_fmtp(fmtp_tree, tvb, pinfo, offset, tokenlen,
1591 (guint8 *)transport_info->encoding_name);
1593 offset = next_offset + 1;
1596 /* Now add remaining (or only) parameter */
1597 tokenlen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1599 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1600 hf_media_format_specific_parameter, tvb,
1601 offset, tokenlen, FALSE);
1603 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1605 decode_sdp_fmtp(fmtp_tree, tvb, pinfo, offset, tokenlen,
1606 (guint8 *)transport_info->encoding_name);
1610 /* msrp attributes that contain address needed for conversation */
1611 if (strncmp((char*)attribute_value, msrp_res, strlen(msrp_res)) == 0){
1612 int address_offset, port_offset, port_end_offset;
1614 /* Address starts here */
1615 address_offset = offset + strlen(msrp_res);
1617 /* Port is after next ':' */
1618 port_offset = tvb_find_guint8(tvb, address_offset, -1, ':');
1620 /* Port ends with '/' */
1621 port_end_offset = tvb_find_guint8(tvb, port_offset, -1, '/');
1623 /* Attempt to convert address */
1624 if (inet_pton(AF_INET, (char*)tvb_get_ephemeral_string(tvb, address_offset, port_offset-address_offset), &msrp_ipaddr) > 0) {
1625 /* Get port number */
1626 msrp_port_number = atoi((char*)tvb_get_ephemeral_string(tvb, port_offset+1, port_end_offset-port_offset-1));
1627 /* Set flag so this info can be used */
1628 msrp_transport_address_set = TRUE;
1633 /* Decode h248 item ITU-T Rec. H.248.12 (2001)/Amd.1 (11/2002)*/
1634 if (strncmp((char*)attribute_value, h324ext_h223lcparm, strlen(msrp_res)) == 0){
1635 /* A.5.1.3 H.223 Logical channel parameters
1636 * This property indicates the H.245
1637 * H223LogicalChannelsParameters structure encoded by applying the PER specified in
1638 * ITU-T Rec. X.691. Value encoded as per A.5.1.2. For text encoding the mechanism defined
1639 * in ITU-T Rec. H.248.15 is used.
1641 guint8 *buf = ep_alloc(256);
1645 len = strlen(attribute_value);
1646 /* arbitrary maximum length */
1651 /* first, skip to where the encoded pdu starts, this is
1652 the first hex digit after the '=' char.
1655 if((*attribute_value==0)||(*attribute_value=='\n')){
1658 if(*attribute_value=='='){
1665 if((*attribute_value==0)||(*attribute_value=='\n')){
1668 if( ((*attribute_value>='0')&&(*attribute_value<='9'))
1669 || ((*attribute_value>='a')&&(*attribute_value<='f'))
1670 || ((*attribute_value>='A')&&(*attribute_value<='F'))){
1676 while( ((*attribute_value>='0')&&(*attribute_value<='9'))
1677 ||((*attribute_value>='a')&&(*attribute_value<='f'))
1678 ||((*attribute_value>='A')&&(*attribute_value<='F')) ){
1680 if((*attribute_value>='0')&&(*attribute_value<='9')){
1681 val=(*attribute_value)-'0';
1682 } else if((*attribute_value>='a')&&(*attribute_value<='f')){
1683 val=(*attribute_value)-'a'+10;
1684 } else if((*attribute_value>='A')&&(*attribute_value<='F')){
1685 val=(*attribute_value)-'A'+10;
1691 if((*attribute_value>='0')&&(*attribute_value<='9')){
1692 val|=(*attribute_value)-'0';
1693 } else if((*attribute_value>='a')&&(*attribute_value<='f')){
1694 val|=(*attribute_value)-'a'+10;
1695 } else if((*attribute_value>='A')&&(*attribute_value<='F')){
1696 val|=(*attribute_value)-'A'+10;
1708 h245_tvb = tvb_new_real_data(buf,i,i);
1709 tvb_set_child_real_data_tvbuff(tvb,h245_tvb);
1710 add_new_data_source(pinfo, h245_tvb, "H.245 in SDP");
1711 /* should go through a handle, however, the two h245 entry
1712 points are different, one is over tpkt and the other is raw
1714 asn1_ctx_init(&actx, ASN1_ENC_PER, TRUE, pinfo);
1715 dissect_h245_H223LogicalChannelParameters(h245_tvb, 0, &actx, sdp_media_attribute_tree, hf_SDPh223LogicalChannelParameters);
1721 /* No special treatment for values of this attribute type, just add as one item. */
1722 proto_tree_add_item(sdp_media_attribute_tree, hf_media_attribute_value,
1723 tvb, offset, -1, FALSE);
1729 proto_register_sdp(void)
1731 static hf_register_info hf[] = {
1732 { &hf_protocol_version,
1733 { "Session Description Protocol Version (v)",
1734 "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
1735 "Session Description Protocol Version", HFILL }},
1737 { "Owner/Creator, Session Id (o)",
1738 "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
1739 "Owner/Creator, Session Id", HFILL}},
1741 { "Session Name (s)",
1742 "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
1743 "Session Name", HFILL }},
1745 { "Session Information (i)",
1746 "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
1747 "Session Information", HFILL }},
1749 { "URI of Description (u)",
1750 "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
1751 "URI of Description", HFILL }},
1753 { "E-mail Address (e)",
1754 "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
1755 "E-mail Address", HFILL }},
1757 { "Phone Number (p)",
1758 "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
1759 "Phone Number", HFILL }},
1760 { &hf_connection_info,
1761 { "Connection Information (c)",
1762 "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
1763 "Connection Information", HFILL }},
1765 { "Bandwidth Information (b)",
1766 "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
1767 "Bandwidth Information", HFILL }},
1769 { "Time Zone Adjustments (z)",
1770 "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
1771 "Time Zone Adjustments", HFILL }},
1772 { &hf_encryption_key,
1773 { "Encryption Key (k)",
1774 "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
1775 "Encryption Key", HFILL }},
1776 { &hf_session_attribute,
1777 { "Session Attribute (a)",
1778 "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1779 "Session Attribute", HFILL }},
1780 { &hf_media_attribute,
1781 { "Media Attribute (a)",
1782 "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1783 "Media Attribute", HFILL }},
1785 { "Time Description, active time (t)",
1786 "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
1787 "Time Description, active time", HFILL }},
1789 { "Repeat Time (r)",
1790 "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
1791 "Repeat Time", HFILL }},
1793 { "Media Description, name and address (m)",
1794 "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
1795 "Media Description, name and address", HFILL }},
1797 { "Media Title (i)",
1798 "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
1799 "Media Title", HFILL }},
1802 "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
1803 "Unknown", HFILL }},
1806 "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
1807 "Invalid line", HFILL }},
1808 { &hf_owner_username,
1810 "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
1811 "Owner Username", HFILL }},
1812 { &hf_owner_sessionid,
1814 "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
1815 "Session ID", HFILL }},
1816 { &hf_owner_version,
1817 { "Session Version",
1818 "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
1819 "Session Version", HFILL }},
1820 { &hf_owner_network_type,
1821 { "Owner Network Type",
1822 "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1823 "Owner Network Type", HFILL }},
1824 { &hf_owner_address_type,
1825 { "Owner Address Type",
1826 "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1827 "Owner Address Type", HFILL }},
1828 { &hf_owner_address,
1830 "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
1831 "Owner Address", HFILL }},
1832 { &hf_connection_info_network_type,
1833 { "Connection Network Type",
1834 "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1835 "Connection Network Type", HFILL }},
1836 { &hf_connection_info_address_type,
1837 { "Connection Address Type",
1838 "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1839 "Connection Address Type", HFILL }},
1840 { &hf_connection_info_connection_address,
1841 { "Connection Address",
1842 "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
1843 "Connection Address", HFILL }},
1844 { &hf_connection_info_ttl,
1846 "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
1847 "Connection TTL", HFILL }},
1848 { &hf_connection_info_num_addr,
1849 { "Connection Number of Addresses",
1850 "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
1851 "Connection Number of Addresses", HFILL }},
1852 { &hf_bandwidth_modifier,
1853 { "Bandwidth Modifier",
1854 "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
1855 "Bandwidth Modifier", HFILL }},
1856 { &hf_bandwidth_value,
1857 { "Bandwidth Value",
1858 "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
1859 "Bandwidth Value (in kbits/s)", HFILL }},
1861 { "Session Start Time",
1862 "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
1863 "Session Start Time", HFILL }},
1865 { "Session Stop Time",
1866 "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
1867 "Session Stop Time", HFILL }},
1868 { &hf_repeat_time_interval,
1869 { "Repeat Interval",
1870 "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
1871 "Repeat Interval", HFILL }},
1872 { &hf_repeat_time_duration,
1873 { "Repeat Duration",
1874 "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
1875 "Repeat Duration", HFILL }},
1876 { &hf_repeat_time_offset,
1878 "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1879 "Repeat Offset", HFILL }},
1880 { &hf_timezone_time,
1882 "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
1883 "Timezone Time", HFILL }},
1884 { &hf_timezone_offset,
1885 { "Timezone Offset",
1886 "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1887 "Timezone Offset", HFILL }},
1888 { &hf_encryption_key_type,
1890 "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
1892 { &hf_encryption_key_data,
1894 "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
1896 { &hf_session_attribute_field,
1897 { "Session Attribute Fieldname",
1898 "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
1899 "Session Attribute Fieldname", HFILL }},
1900 { &hf_session_attribute_value,
1901 { "Session Attribute Value",
1902 "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
1903 "Session Attribute Value", HFILL }},
1906 "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
1907 "Media Type", HFILL }},
1910 "sdp.media.port",FT_UINT16, BASE_DEC, NULL, 0x0,
1911 "Media Port", HFILL }},
1912 { &hf_media_portcount,
1913 { "Media Port Count",
1914 "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
1915 "Media Port Count", HFILL }},
1918 "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
1919 "Media Protocol", HFILL }},
1922 "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
1923 "Media Format", HFILL }},
1924 { &hf_media_attribute_field,
1925 { "Media Attribute Fieldname",
1926 "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
1927 "Media Attribute Fieldname", HFILL }},
1928 { &hf_media_attribute_value,
1929 { "Media Attribute Value",
1930 "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
1931 "Media Attribute Value", HFILL }},
1932 { &hf_media_encoding_name,
1934 "sdp.mime.type",FT_STRING, BASE_NONE, NULL, 0x0,
1935 "SDP MIME Type", HFILL }},
1936 { &hf_media_format_specific_parameter,
1937 { "Media format specific parameters",
1938 "sdp.fmtp.parameter",FT_STRING, BASE_NONE, NULL, 0x0,
1939 "Format specific parameter(fmtp)", HFILL }},
1940 { &hf_ipbcp_version,
1941 { "IPBCP Protocol Version",
1942 "ipbcp.version",FT_STRING, BASE_NONE, NULL, 0x0,
1943 "IPBCP Protocol Version", HFILL }},
1945 { "IPBCP Command Type",
1946 "ipbcp.command",FT_STRING, BASE_NONE, NULL, 0x0,
1947 "IPBCP Command Type", HFILL }},
1948 {&hf_sdp_fmtp_profile_level_id,
1950 "sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mpeg4es_level_indication_vals), 0x0,
1951 "Level Code", HFILL }},
1952 { &hf_sdp_fmtp_h263_profile,
1954 "sdp.fmtp.h263profile",FT_UINT32, BASE_DEC,VALS(h263_profile_vals), 0x0,
1955 "Profile", HFILL }},
1956 { &hf_SDPh223LogicalChannelParameters,
1957 { "h223LogicalChannelParameters", "sdp.h223LogicalChannelParameters",
1958 FT_NONE, BASE_NONE, NULL, 0,
1959 "sdp.h223LogicalChannelParameters", HFILL }},
1960 { &hf_key_mgmt_att_value,
1962 "sdp.key_mgmt", FT_STRING, BASE_NONE, NULL, 0x0,
1963 "Key Management", HFILL }},
1964 { &hf_key_mgmt_prtcl_id,
1965 { "Key Management Protocol (kmpid)",
1966 "sdp.key_mgmt.kmpid", FT_STRING, BASE_NONE, NULL, 0x0,
1967 "Key Management Protocol", HFILL }},
1968 { &hf_key_mgmt_data,
1969 { "Key Management Data",
1970 "sdp.key_mgmt.data", FT_BYTES, BASE_NONE, NULL, 0x0,
1971 "Key Management Data", HFILL }},
1973 static gint *ett[] = {
1976 &ett_sdp_connection_info,
1979 &ett_sdp_repeat_time,
1981 &ett_sdp_encryption_key,
1982 &ett_sdp_session_attribute,
1984 &ett_sdp_media_attribute,
1989 module_t *sdp_module;
1991 proto_sdp = proto_register_protocol("Session Description Protocol",
1993 proto_register_field_array(proto_sdp, hf, array_length(hf));
1994 proto_register_subtree_array(ett, array_length(ett));
1996 key_mgmt_dissector_table = register_dissector_table("key_mgmt",
1997 "Key Management", FT_STRING, BASE_NONE);
2000 * Preferences registration
2002 sdp_module = prefs_register_protocol(proto_sdp, NULL);
2003 prefs_register_bool_preference(sdp_module, "establish_conversation",
2004 "Establish Media Conversation",
2005 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
2006 "upon port numbers found in SIP/SDP payload",
2007 &global_sdp_establish_conversation);
2010 * Register the dissector by name, so other dissectors can
2011 * grab it by name rather than just referring to it directly.
2013 register_dissector("sdp", dissect_sdp, proto_sdp);
2015 /* Register for tapping */
2016 sdp_tap = register_tap("sdp");
2020 proto_reg_handoff_sdp(void)
2022 dissector_handle_t sdp_handle;
2024 rtp_handle = find_dissector("rtp");
2025 rtcp_handle = find_dissector("rtcp");
2026 msrp_handle = find_dissector("msrp");
2027 t38_handle = find_dissector("t38");
2028 h264_handle = find_dissector("h264");
2030 sdp_handle = find_dissector("sdp");
2031 dissector_add_string("media_type", "application/sdp", sdp_handle);
2032 dissector_add("bctp.tpi", 0x20, sdp_handle);