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
36 #ifdef HAVE_SYS_TYPES_H
37 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
49 #ifdef HAVE_WINSOCK2_H
50 #include <winsock2.h> /* needed to define AF_ values on Windows */
53 #ifdef NEED_INET_V6DEFS_H
54 # include "wsutil/inet_v6defs.h"
59 #include <epan/packet.h>
60 #include <epan/strutil.h>
61 #include <epan/emem.h>
62 #include <epan/base64.h>
63 #include <epan/asn1.h>
64 #include <epan/prefs.h>
65 #include <epan/expert.h>
68 #include "packet-sdp.h"
70 #include "packet-rtp.h"
71 #include <epan/rtp_pt.h>
73 #include "packet-rtcp.h"
74 #include "packet-t38.h"
75 #include "packet-msrp.h"
76 #include "packet-per.h"
77 #include "packet-h245.h"
78 #include "packet-h264.h"
79 #include "packet-mp4ves.h"
81 static dissector_handle_t rtp_handle = NULL;
82 static dissector_handle_t rtcp_handle = NULL;
83 static dissector_handle_t t38_handle = NULL;
84 static dissector_handle_t msrp_handle = NULL;
85 static dissector_handle_t h264_handle = NULL;
86 static dissector_handle_t mp4ves_handle = NULL;
88 static int sdp_tap = -1;
90 static int proto_sdp = -1;
92 /* preference globals */
93 static gboolean global_sdp_establish_conversation = TRUE;
95 /* Top level fields */
96 static int hf_protocol_version = -1;
97 static int hf_owner = -1;
98 static int hf_session_name = -1;
99 static int hf_session_info = -1;
100 static int hf_uri = -1;
101 static int hf_email = -1;
102 static int hf_phone = -1;
103 static int hf_connection_info = -1;
104 static int hf_bandwidth = -1;
105 static int hf_timezone = -1;
106 static int hf_encryption_key = -1;
107 static int hf_session_attribute = -1;
108 static int hf_media_attribute = -1;
109 static int hf_time = -1;
110 static int hf_repeat_time = -1;
111 static int hf_media = -1;
112 static int hf_media_title = -1;
113 static int hf_unknown = -1;
114 static int hf_invalid = -1;
115 static int hf_ipbcp_version = -1;
116 static int hf_ipbcp_type = -1;
118 /* hf_owner subfields*/
119 static int hf_owner_username = -1;
120 static int hf_owner_sessionid = -1;
121 static int hf_owner_version = -1;
122 static int hf_owner_network_type = -1;
123 static int hf_owner_address_type = -1;
124 static int hf_owner_address = -1;
126 /* hf_connection_info subfields */
127 static int hf_connection_info_network_type = -1;
128 static int hf_connection_info_address_type = -1;
129 static int hf_connection_info_connection_address = -1;
130 static int hf_connection_info_ttl = -1;
131 static int hf_connection_info_num_addr = -1;
133 /* hf_bandwidth subfields */
134 static int hf_bandwidth_modifier = -1;
135 static int hf_bandwidth_value = -1;
137 /* hf_time subfields */
138 static int hf_time_start = -1;
139 static int hf_time_stop = -1;
141 /* hf_repeat_time subfield */
142 static int hf_repeat_time_interval = -1;
143 static int hf_repeat_time_duration = -1;
144 static int hf_repeat_time_offset = -1;
146 /* hf_timezone subfields */
147 static int hf_timezone_time = -1;
148 static int hf_timezone_offset = -1;
150 /* hf_encryption_key subfields */
151 static int hf_encryption_key_type = -1;
152 static int hf_encryption_key_data = -1;
154 /* hf_session_attribute subfields */
155 static int hf_session_attribute_field = -1;
156 static int hf_session_attribute_value = -1;
158 /* hf_media subfields */
159 static int hf_media_media = -1;
160 static int hf_media_port = -1;
161 static int hf_media_portcount = -1;
162 static int hf_media_proto = -1;
163 static int hf_media_format = -1;
165 /* hf_session_attribute subfields */
166 static int hf_media_attribute_field = -1;
167 static int hf_media_attribute_value = -1;
168 static int hf_media_encoding_name = -1;
169 static int hf_media_sample_rate = -1;
170 static int hf_media_format_specific_parameter = -1;
171 static int hf_sdp_fmtp_mpeg4_profile_level_id = -1;
172 static int hf_sdp_fmtp_h263_profile = -1;
173 static int hf_sdp_fmtp_h263_level = -1;
174 static int hf_sdp_h264_packetization_mode = -1;
175 static int hf_sdp_h264_sprop_parameter_sets = -1;
176 static int hf_SDPh223LogicalChannelParameters = -1;
178 /* hf_session_attribute hf_media_attribute subfields */
179 static int hf_key_mgmt_att_value = -1;
180 static int hf_key_mgmt_prtcl_id = -1;
181 static int hf_key_mgmt_data = -1;
184 static int ett_sdp = -1;
185 static int ett_sdp_owner = -1;
186 static int ett_sdp_connection_info = -1;
187 static int ett_sdp_bandwidth = -1;
188 static int ett_sdp_time = -1;
189 static int ett_sdp_repeat_time = -1;
190 static int ett_sdp_timezone = -1;
191 static int ett_sdp_encryption_key = -1;
192 static int ett_sdp_session_attribute = -1;
193 static int ett_sdp_media = -1;
194 static int ett_sdp_media_attribute = -1;
195 static int ett_sdp_fmtp = -1;
196 static int ett_sdp_key_mgmt = -1;
199 #define SDP_MAX_RTP_CHANNELS 4
200 #define SDP_MAX_RTP_PAYLOAD_TYPES 20
201 #define SDP_NO_OF_PT 128
203 gint32 pt[SDP_MAX_RTP_PAYLOAD_TYPES];
205 GHashTable *rtp_dyn_payload;
206 } transport_media_pt_t;
209 char *connection_address;
210 char *connection_type;
212 char *encoding_name[SDP_NO_OF_PT];
213 int sample_rate[SDP_NO_OF_PT];
214 char *media_port[SDP_MAX_RTP_CHANNELS];
215 char *media_proto[SDP_MAX_RTP_CHANNELS];
216 transport_media_pt_t media[SDP_MAX_RTP_CHANNELS];
221 /* MSRP transport info (as set while parsing path attribute) */
222 static gboolean msrp_transport_address_set = FALSE;
223 static guint32 msrp_ipaddr[4];
224 static guint16 msrp_port_number;
226 /* key-mgmt dissector
228 * http://www.iana.org/assignments/sdp-parameters
230 static dissector_table_t key_mgmt_dissector_table;
233 /* Protocol registration */
234 void proto_register_sdp(void);
235 void proto_reg_handoff_sdp(void);
238 /* static functions */
240 static void call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, int length,
241 transport_info_t *transport_info);
243 /* Subdissector functions */
244 static void dissect_sdp_owner(tvbuff_t *tvb, proto_item* ti);
245 static void dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
246 transport_info_t *transport_info);
247 static void dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti);
248 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti);
249 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti);
250 static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti);
251 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti);
252 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti);
253 static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
254 transport_info_t *transport_info);
255 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti, int length,transport_info_t *transport_info);
257 static void free_encoding_name_str (void *ptr)
259 encoding_name_and_rate_t *encoding_name_and_rate = (encoding_name_and_rate_t *)ptr;
261 if (encoding_name_and_rate->encoding_name) {
262 g_free(encoding_name_and_rate->encoding_name);
267 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
269 proto_tree *sdp_tree;
270 proto_item *ti, *sub_ti;
274 gboolean in_media_description;
284 transport_info_t transport_info;
287 gboolean is_rtp=FALSE;
288 gboolean is_srtp=FALSE;
289 gboolean is_t38=FALSE;
290 gboolean is_msrp=FALSE;
291 gboolean set_rtp=FALSE;
292 gboolean is_ipv4_addr=FALSE;
293 gboolean is_ipv6_addr=FALSE;
294 gboolean is_video=FALSE;
297 sdp_packet_info *sdp_pi;
298 gchar *unknown_encoding = ep_strdup("Unknown");
300 /* Initialise packet info for passing to tap */
301 sdp_pi = ep_alloc(sizeof(sdp_packet_info));
302 sdp_pi->summary_str[0] = '\0';
304 /* Initialise RTP channel info */
305 transport_info.connection_address=NULL;
306 transport_info.connection_type=NULL;
307 transport_info.media_type=NULL;
308 for (n=0; n < SDP_NO_OF_PT; n++){
309 transport_info.encoding_name[n]=unknown_encoding;
310 transport_info.sample_rate[n] = 0;
312 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++)
314 transport_info.media_port[n]=NULL;
315 transport_info.media_proto[n]=NULL;
316 transport_info.media[n].pt_count = 0;
317 transport_info.media[n].rtp_dyn_payload =
318 g_hash_table_new_full( g_int_hash, g_int_equal, g_free, free_encoding_name_str);
320 transport_info.media_count = 0;
323 * As RFC 2327 says, "SDP is purely a format for session
324 * description - it does not incorporate a transport protocol,
325 * and is intended to use different transport protocols as
326 * appropriate including the Session Announcement Protocol,
327 * Session Initiation Protocol, Real-Time Streaming Protocol,
328 * electronic mail using the MIME extensions, and the
329 * Hypertext Transport Protocol."
331 * We therefore don't set the protocol or info columns;
332 * instead, we append to them, so that we don't erase
333 * what the protocol inside which the SDP stuff resides
336 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
338 /* XXX: Needs description. */
339 col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
341 ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
342 sdp_tree = proto_item_add_subtree(ti, ett_sdp);
345 * Show the SDP message a line at a time.
347 in_media_description = FALSE;
349 while (tvb_reported_length_remaining(tvb, offset) > 0) {
351 * Find the end of the line.
353 linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
358 * Line must contain at least e.g. "v=".
363 type = tvb_get_guint8(tvb,offset);
364 delim = tvb_get_guint8(tvb,offset + 1);
366 proto_item *ti2 = proto_tree_add_item(sdp_tree, hf_invalid, tvb, offset, linelen, FALSE);
367 expert_add_info_format(pinfo, ti2, PI_MALFORMED, PI_NOTE,
368 "Invalid SDP line (no '=' delimiter)");
369 offset = next_offset;
378 hf = hf_protocol_version;
384 hf = hf_session_name;
387 if (in_media_description) {
391 hf = hf_session_info;
404 hf = hf_connection_info;
417 in_media_description = TRUE;
420 hf = hf_encryption_key;
423 if (in_media_description) {
424 hf = hf_media_attribute;
427 hf = hf_session_attribute;
438 if (hf == hf_unknown)
440 string = (char*)tvb_get_ephemeral_string(tvb, offset + tokenoffset,
441 linelen - tokenoffset);
442 sub_ti = proto_tree_add_string(sdp_tree, hf, tvb, offset, linelen,
444 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
446 linelen-tokenoffset),
448 hf,sub_ti,linelen-tokenoffset,&transport_info),
449 offset = next_offset;
453 /* Now look, if we have strings collected.
454 * Try to convert ipv4 addresses and ports into binary format,
455 * so we can use them to detect rtp and rtcp streams.
456 * Don't forget to free the strings!
459 for (n = 0; n < transport_info.media_count; n++)
461 if(transport_info.media_port[n]!=NULL) {
462 port = atol(transport_info.media_port[n]);
464 if(transport_info.media_proto[n]!=NULL) {
465 /* Check if media protocol is RTP
466 * and stream decoding is enabled in preferences
468 if(global_sdp_establish_conversation){
469 /* Check if media protocol is RTP */
470 is_rtp = (strcmp(transport_info.media_proto[n],"RTP/AVP")==0);
471 /* Check if media protocol is SRTP */
472 is_srtp = (strcmp(transport_info.media_proto[n],"RTP/SAVP")==0);
473 /* Check if media protocol is T38 */
474 is_t38 = ( (strcmp(transport_info.media_proto[n],"UDPTL")==0) ||
475 (strcmp(transport_info.media_proto[n],"udptl")==0) );
476 /* Check if media protocol is MSRP/TCP */
477 is_msrp = (strcmp(transport_info.media_proto[n],"msrp/tcp")==0);
482 if(transport_info.connection_address!=NULL) {
483 if(transport_info.connection_type!=NULL) {
484 if (strcmp(transport_info.connection_type,"IP4")==0) {
485 if(inet_pton(AF_INET,transport_info.connection_address, &ipaddr)==1 ) {
486 /* connection_address could be converted to a valid ipv4 address*/
488 src_addr.type=AT_IPv4;
492 else if (strcmp(transport_info.connection_type,"IP6")==0){
493 if (inet_pton(AF_INET6, transport_info.connection_address, &ipaddr)==1){
494 /* connection_address could be converted to a valid ipv6 address*/
496 src_addr.type=AT_IPv6;
502 if (strcmp(transport_info.media_type,"video")==0){
506 /* Add (s)rtp and (s)rtcp conversation, if available (overrides t38 if conversation already set) */
507 if((!pinfo->fd->flags.visited) && port!=0 && (is_rtp||is_srtp) && (is_ipv4_addr || is_ipv6_addr)){
508 src_addr.data=(guint8*)&ipaddr;
511 struct srtp_info *dummy_srtp_info = se_alloc0(sizeof(struct srtp_info));
512 srtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num, is_video,
513 transport_info.media[n].rtp_dyn_payload, dummy_srtp_info);
515 rtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num, is_video,
516 transport_info.media[n].rtp_dyn_payload);
522 rtcp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
526 /* Add t38 conversation, if available and only if no rtp */
527 if((!pinfo->fd->flags.visited) && port!=0 && !set_rtp && is_t38 && is_ipv4_addr){
528 src_addr.data=(guint8*)&ipaddr;
530 t38_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
534 /* Add MSRP conversation. Uses addresses discovered in attribute
535 rather than connection information of media session line */
537 if ((!pinfo->fd->flags.visited) && msrp_transport_address_set){
539 src_addr.type=AT_IPv4;
541 src_addr.data=(guint8*)&msrp_ipaddr;
542 msrp_add_address(pinfo, &src_addr, msrp_port_number, "SDP", pinfo->fd->num);
548 /* Create the RTP summary str for the Voip Call analysis */
549 for (i = 0; i < transport_info.media[n].pt_count; i++)
551 /* if the payload type is dynamic (96 to 127), check the hash table to add the desc in the SDP summary */
552 if ( (transport_info.media[n].pt[i] >=96) && (transport_info.media[n].pt[i] <=127) ) {
553 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]);
554 if (encoding_name_and_rate_pt) {
555 if (strlen(sdp_pi->summary_str)) g_strlcat(sdp_pi->summary_str, " ", 50);
556 g_strlcat(sdp_pi->summary_str, encoding_name_and_rate_pt->encoding_name, 50);
559 g_snprintf(num_pt, 10, "%u", transport_info.media[n].pt[i]);
560 if (strlen(sdp_pi->summary_str)) g_strlcat(sdp_pi->summary_str, " ", 50);
561 g_strlcat(sdp_pi->summary_str, num_pt, 50);
564 if (strlen(sdp_pi->summary_str)) g_strlcat(sdp_pi->summary_str, " ", 50);
565 g_strlcat(sdp_pi->summary_str, val_to_str_ext(transport_info.media[n].pt[i], &rtp_payload_type_short_vals_ext, "%u"), 50);
569 /* Free the hash table if we did't assigned it to a conv use it */
570 if (set_rtp == FALSE)
571 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
573 /* Create the T38 summary str for the Voip Call analysis */
574 if (port!=0 && is_t38) {
575 if (strlen(sdp_pi->summary_str)) g_strlcat(sdp_pi->summary_str, " ", 50);
576 g_strlcat(sdp_pi->summary_str, "t38", 50);
580 /* Free the remainded hash tables not used */
581 for (n = transport_info.media_count; n < SDP_MAX_RTP_CHANNELS; n++)
583 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
587 datalen = tvb_length_remaining(tvb, offset);
589 proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)",
593 /* Report this packet to the tap */
594 tap_queue_packet(sdp_tap, pinfo, sdp_pi);
598 call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, int length,transport_info_t *transport_info){
600 dissect_sdp_owner(tvb,ti);
601 } else if ( hf == hf_connection_info) {
602 dissect_sdp_connection_info(tvb,ti,transport_info);
603 } else if ( hf == hf_bandwidth) {
604 dissect_sdp_bandwidth(tvb,ti);
605 } else if ( hf == hf_time) {
606 dissect_sdp_time(tvb,ti);
607 } else if ( hf == hf_repeat_time ){
608 dissect_sdp_repeat_time(tvb,ti);
609 } else if ( hf == hf_timezone ) {
610 dissect_sdp_timezone(tvb,ti);
611 } else if ( hf == hf_encryption_key ) {
612 dissect_sdp_encryption_key(tvb,ti);
613 } else if ( hf == hf_session_attribute ){
614 dissect_sdp_session_attribute(tvb,pinfo,ti);
615 } else if ( hf == hf_media ) {
616 dissect_sdp_media(tvb,ti,transport_info);
617 } else if ( hf == hf_media_attribute ){
618 dissect_sdp_media_attribute(tvb,pinfo,ti, length, transport_info);
623 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
624 proto_tree *sdp_owner_tree;
625 gint offset,next_offset,tokenlen;
631 sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
633 /* Find the username */
634 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
635 if( next_offset == -1 )
637 tokenlen = next_offset - offset;
639 proto_tree_add_item(sdp_owner_tree, hf_owner_username, tvb, offset, tokenlen,
641 offset = next_offset + 1;
643 /* Find the session id */
644 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
645 if( next_offset == -1 )
647 tokenlen = next_offset - offset;
649 proto_tree_add_item(sdp_owner_tree, hf_owner_sessionid, tvb, offset,
651 offset = next_offset + 1;
653 /* Find the version */
654 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
655 if( next_offset == -1 )
657 tokenlen = next_offset - offset;
659 proto_tree_add_item(sdp_owner_tree, hf_owner_version, tvb, offset, tokenlen,
661 offset = next_offset + 1;
663 /* Find the network type */
664 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
665 if( next_offset == -1 )
667 tokenlen = next_offset - offset;
669 proto_tree_add_item(sdp_owner_tree, hf_owner_network_type, tvb, offset,
671 offset = next_offset + 1;
673 /* Find the address type */
674 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
675 if( next_offset == -1 )
677 tokenlen = next_offset - offset;
679 proto_tree_add_item(sdp_owner_tree, hf_owner_address_type, tvb, offset,
681 offset = next_offset + 1;
683 /* Find the address */
684 proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
688 * XXX - this can leak memory if an exception is thrown after we've fetched
692 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
693 transport_info_t *transport_info){
694 proto_tree *sdp_connection_info_tree;
695 gint offset,next_offset,tokenlen;
701 sdp_connection_info_tree = proto_item_add_subtree(ti,
702 ett_sdp_connection_info);
704 /* Find the network type */
705 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
706 if( next_offset == -1 )
708 tokenlen = next_offset - offset;
710 proto_tree_add_item(sdp_connection_info_tree,
711 hf_connection_info_network_type, tvb, offset, tokenlen,
713 offset = next_offset + 1;
715 /* Find the address type */
716 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
717 if( next_offset == -1 )
719 tokenlen = next_offset - offset;
720 /* Save connection address type */
721 transport_info->connection_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
724 proto_tree_add_item(sdp_connection_info_tree,
725 hf_connection_info_address_type, tvb, offset, tokenlen,
727 offset = next_offset + 1;
729 /* Find the connection address */
730 /* XXX - what if there's a <number of addresses> value? */
731 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
732 if( next_offset == -1){
733 tokenlen = -1; /* end of tvbuff */
734 /* Save connection address */
735 transport_info->connection_address =
736 (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
738 tokenlen = next_offset - offset;
739 /* Save connection address */
740 transport_info->connection_address = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
743 proto_tree_add_item(sdp_connection_info_tree,
744 hf_connection_info_connection_address, tvb, offset,
746 if(next_offset != -1){
747 offset = next_offset + 1;
748 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
749 if( next_offset == -1){
750 tokenlen = -1; /* end of tvbuff */
752 tokenlen = next_offset - offset;
754 proto_tree_add_item(sdp_connection_info_tree,
755 hf_connection_info_ttl, tvb, offset, tokenlen, FALSE);
756 if(next_offset != -1){
757 offset = next_offset + 1;
758 proto_tree_add_item(sdp_connection_info_tree,
759 hf_connection_info_num_addr, tvb, offset, -1, FALSE);
765 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
766 proto_tree * sdp_bandwidth_tree;
767 gint offset, next_offset, tokenlen;
769 gboolean unit_is_kbs = FALSE;
770 gboolean unit_is_bps = FALSE;
776 sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
778 /* find the modifier */
779 next_offset = tvb_find_guint8(tvb,offset,-1,':');
781 if( next_offset == -1)
784 tokenlen = next_offset - offset;
786 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier, tvb, offset,
788 if (tvb_strneql(tvb, offset, "CT", 2) == 0){
789 proto_item_append_text(item, " [Conference Total(total bandwidth of all RTP sessions)]");
791 }else if (tvb_strneql(tvb, offset, "AS", 2) == 0){
792 proto_item_append_text(item, " [Application Specific (RTP session bandwidth)]");
794 }else if (tvb_strneql(tvb, offset, "TIAS", 4) == 0){
795 proto_item_append_text(item, " [Transport Independent Application Specific maximum]");
800 offset = next_offset + 1;
802 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value, tvb, offset, -1,
804 if (unit_is_kbs == TRUE)
805 proto_item_append_text(item, " kb/s");
806 if (unit_is_bps == TRUE)
807 proto_item_append_text(item, " b/s");
810 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
811 proto_tree *sdp_time_tree;
812 gint offset,next_offset, tokenlen;
818 sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
821 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
822 if( next_offset == -1 )
825 tokenlen = next_offset - offset;
826 proto_tree_add_item(sdp_time_tree, hf_time_start, tvb, offset, tokenlen,
830 offset = next_offset + 1;
831 proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb, offset, -1, FALSE);
834 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
835 proto_tree *sdp_repeat_time_tree;
836 gint offset,next_offset, tokenlen;
842 sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
845 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
846 if( next_offset == -1 )
849 tokenlen = next_offset - offset;
850 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
851 offset, tokenlen, FALSE);
854 offset = next_offset + 1;
855 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
856 if( next_offset == -1 )
859 tokenlen = next_offset - offset;
860 proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
861 offset, tokenlen, FALSE);
865 offset = next_offset +1;
866 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
867 if(next_offset != -1){
868 tokenlen = next_offset - offset;
870 tokenlen = -1; /* end of tvbuff */
872 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
873 tvb, offset, tokenlen, FALSE);
874 } while( next_offset != -1 );
878 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
879 proto_tree* sdp_timezone_tree;
880 gint offset, next_offset, tokenlen;
885 sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
888 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
889 if(next_offset == -1)
891 tokenlen = next_offset - offset;
893 proto_tree_add_item(sdp_timezone_tree, hf_timezone_time, tvb, offset,
895 offset = next_offset + 1;
896 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
897 if(next_offset != -1){
898 tokenlen = next_offset - offset;
900 tokenlen = -1; /* end of tvbuff */
902 proto_tree_add_item(sdp_timezone_tree, hf_timezone_offset, tvb, offset,
904 offset = next_offset + 1;
905 } while (next_offset != -1);
910 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
911 proto_tree *sdp_encryption_key_tree;
912 gint offset, next_offset, tokenlen;
918 sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
920 next_offset = tvb_find_guint8(tvb,offset,-1,':');
922 if(next_offset == -1)
925 tokenlen = next_offset - offset;
927 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
928 tvb, offset, tokenlen, FALSE);
930 offset = next_offset + 1;
931 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
932 tvb, offset, -1, FALSE);
935 static void dissect_key_mgmt(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
936 gchar *data_p = NULL;
937 gchar *prtcl_id = NULL;
939 tvbuff_t *keymgmt_tvb;
940 gboolean found_match = FALSE;
941 proto_tree *key_tree;
946 key_tree = proto_item_add_subtree(ti, ett_sdp_key_mgmt);
948 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
950 if (next_offset == -1)
953 tokenlen = next_offset - offset;
954 prtcl_id = tvb_get_ephemeral_string(tvb, offset, tokenlen);
956 proto_tree_add_item(key_tree, hf_key_mgmt_prtcl_id, tvb, offset, tokenlen, FALSE);
958 offset = next_offset + 1;
960 len = tvb_length_remaining(tvb, offset);
964 data_p = tvb_get_ephemeral_string(tvb, offset, len);
965 keymgmt_tvb = base64_to_tvb(tvb, data_p);
966 add_new_data_source(pinfo, keymgmt_tvb, "Key Management Data");
968 if ( prtcl_id != NULL && key_mgmt_dissector_table != NULL ) {
969 found_match = dissector_try_string(key_mgmt_dissector_table,
976 proto_item *ti2 = proto_tree_add_item(key_tree, hf_key_mgmt_data,
977 keymgmt_tvb, 0, -1, FALSE);
978 PROTO_ITEM_SET_HIDDEN(ti2);
981 proto_tree_add_item(key_tree, hf_key_mgmt_data,
982 keymgmt_tvb, 0, -1, FALSE);
988 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
989 proto_tree *sdp_session_attribute_tree;
990 gint offset, next_offset, tokenlen;
997 sdp_session_attribute_tree = proto_item_add_subtree(ti,
998 ett_sdp_session_attribute);
1000 next_offset = tvb_find_guint8(tvb,offset,-1,':');
1002 if(next_offset == -1)
1005 tokenlen = next_offset - offset;
1007 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_field,
1008 tvb, offset, tokenlen, FALSE);
1010 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1012 offset = next_offset + 1;
1014 if (strcmp((char*)field_name, "ipbcp") == 0) {
1015 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"0123456789", NULL);
1020 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1022 if (next_offset == -1)
1025 tokenlen = next_offset - offset;
1027 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_version,tvb,offset,tokenlen,FALSE);
1029 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", NULL);
1034 tokenlen = tvb_find_line_end(tvb,offset,-1, &next_offset, FALSE);
1039 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE);
1040 } else if (strcmp((char*)field_name, "key-mgmt") == 0) {
1044 key_tvb = tvb_new_subset_remaining(tvb, offset);
1045 key_ti = proto_tree_add_item(sdp_session_attribute_tree, hf_key_mgmt_att_value, key_tvb, 0, -1, FALSE);
1047 dissect_key_mgmt(key_tvb, pinfo, key_ti);
1049 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value,
1050 tvb, offset, -1, FALSE);
1055 /* Dissect media description */
1057 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
1058 transport_info_t *transport_info){
1059 proto_tree *sdp_media_tree;
1060 gint offset, next_offset, tokenlen, idx;
1061 guint8 *media_format;
1067 /* Re-initialise for a new media description */
1068 msrp_transport_address_set = FALSE;
1070 /* Create tree for media session */
1071 sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
1073 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1075 if(next_offset == -1)
1078 tokenlen = next_offset - offset;
1080 /* Type of media session */
1081 proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, offset, tokenlen,
1084 transport_info->media_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1086 offset = next_offset + 1;
1088 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1089 if(next_offset == -1)
1091 tokenlen = next_offset - offset;
1092 next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
1094 if(next_offset != -1){
1095 tokenlen = next_offset - offset;
1096 /* Save port info */
1097 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1099 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1100 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1101 offset = next_offset + 1;
1102 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1103 if(next_offset == -1)
1105 tokenlen = next_offset - offset;
1106 proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb, offset,
1108 offset = next_offset + 1;
1110 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1112 if(next_offset == -1)
1114 tokenlen = next_offset - offset;
1115 /* Save port info */
1116 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1118 /* XXX Remember Port */
1119 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1120 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1121 offset = next_offset + 1;
1124 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1126 if( next_offset == -1)
1129 tokenlen = next_offset - offset;
1130 /* Save port protocol */
1131 transport_info->media_proto[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1133 /* XXX Remember Protocol */
1134 proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb, offset, tokenlen,
1138 offset = next_offset + 1;
1139 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1141 if(next_offset == -1){
1142 tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
1144 break; /* Nothing more left */
1146 tokenlen = next_offset - offset;
1149 if (strcmp(transport_info->media_proto[transport_info->media_count],
1151 media_format = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1152 proto_tree_add_string(sdp_media_tree, hf_media_format, tvb, offset,
1153 tokenlen, val_to_str_ext(atol((char*)media_format), &rtp_payload_type_vals_ext, "%u"));
1154 idx = transport_info->media[transport_info->media_count].pt_count;
1155 transport_info->media[transport_info->media_count].pt[idx] = atol((char*)media_format);
1156 if (idx < (SDP_MAX_RTP_PAYLOAD_TYPES-1))
1157 transport_info->media[transport_info->media_count].pt_count++;
1159 proto_tree_add_item(sdp_media_tree, hf_media_format, tvb, offset,
1162 } while (next_offset != -1);
1164 /* Increase the count of media channels, but don't walk off the end
1166 if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
1167 transport_info->media_count++;
1170 /* XXX Dissect traffic to "Port" as "Protocol"
1171 * Remember this Port/Protocol pair so we can tear it down again later
1172 * Actually, it's harder than that:
1173 * We need to find out the address of the other side first and it
1174 * looks like that info can be found in SIP headers only.
1180 ascii_bytes_to_tvb(tvbuff_t *tvb, packet_info *pinfo, gint len, gchar *msg)
1182 guint8 *buf = g_malloc(10240);
1184 /* arbitrary maximum length */
1187 tvbuff_t *bytes_tvb;
1189 /* first, skip to where the encoded pdu starts, this is
1190 the first hex digit after the '=' char.
1193 if((*msg==0)||(*msg=='\n')){
1203 if((*msg==0)||(*msg=='\n')){
1206 if( ((*msg>='0')&&(*msg<='9'))
1207 || ((*msg>='a')&&(*msg<='f'))
1208 || ((*msg>='A')&&(*msg<='F'))){
1214 while( ((*msg>='0')&&(*msg<='9'))
1215 ||((*msg>='a')&&(*msg<='f'))
1216 ||((*msg>='A')&&(*msg<='F')) ){
1218 if((*msg>='0')&&(*msg<='9')){
1220 } else if((*msg>='a')&&(*msg<='f')){
1222 } else if((*msg>='A')&&(*msg<='F')){
1229 if((*msg>='0')&&(*msg<='9')){
1231 } else if((*msg>='a')&&(*msg<='f')){
1233 } else if((*msg>='A')&&(*msg<='F')){
1246 bytes_tvb = tvb_new_child_real_data(tvb, buf,i,i);
1247 tvb_set_free_cb(bytes_tvb, g_free);
1248 add_new_data_source(pinfo, bytes_tvb, "ASCII bytes to tvb");
1254 /* Annex X Profiles and levels definition */
1255 static const value_string h263_profile_vals[] =
1257 { 0, "Baseline Profile" },
1258 { 1, "H.320 Coding Efficiency Version 2 Backward-Compatibility Profile" },
1259 { 2, "Version 1 Backward-Compatibility Profile" },
1260 { 3, "Version 2 Interactive and Streaming Wireless Profile" },
1261 { 4, "Version 3 Interactive and Streaming Wireless Profile" },
1262 { 5, "Conversational High Compression Profile" },
1263 { 6, "Conversational Internet Profile" },
1264 { 7, "Conversational Interlace Profile" },
1265 { 8, "High Latency Profile" },
1270 /* RFC 4629 The level are described in table X.2 of H.263 annex X */
1271 static const value_string h263_level_vals[] =
1273 { 10, "QCIF (176 x 144), 1 x 64Kb/s" },
1274 { 20, "CIF (352 x 288), 2 x 64Kb/s" },
1275 { 30, "CIF (352 x 288), 6 x 64Kb/s" },
1276 { 40, "CIF (352 x 288), 32 x 64Kb/s" },
1277 { 45, "QCIF (176 x144) support of CPFMT, 2 x 64Kb/s" },
1278 { 50, "CIF (352 x 288) support of CPFMT, 64 x 64Kb/s" },
1279 { 60, "CPFMT: 720 x 288 support of CPFMT, 128 x 64Kb/s" },
1280 { 70, "CPFMT: 720 x 576 support of CPFMT, 256 x 64Kb/s" },
1285 static const value_string h264_packetization_mode_vals[] =
1287 { 0, "Single NAL mode" },
1288 { 1, "Non-interleaved mode" },
1289 { 2, "Interleaved mode" },
1294 * TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
1297 decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint tokenlen, char *mime_type){
1301 gchar *format_specific_parameter;
1305 end_offset = offset + tokenlen;
1308 proto_tree_add_text(tree, tvb, offset, tokenlen, "Debug; Analysed string: '%s'",
1309 tvb_get_ephemeral_string(tvb, offset, tokenlen));
1312 /* Look for an '=' within this value - this may indicate that there is a
1313 profile-level-id parameter to find if the MPEG4 media type is in use */
1314 next_offset = tvb_find_guint8(tvb,offset,-1,'=');
1315 if (next_offset == -1)
1317 /* Give up (and avoid exception) if '=' not found */
1321 /* Find the name of the parameter */
1322 tokenlen = next_offset - offset;
1323 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1324 /*proto_tree_add_text(tree, tvb, offset, tokenlen, "Debug; MIMEtype '%s'Parameter name: '%s'", mime_type, field_name); */
1326 offset = next_offset;
1328 /* Dissect the MPEG4 profile-level-id parameter if present */
1329 if (mime_type != NULL && g_ascii_strcasecmp(mime_type, "MP4V-ES") == 0) {
1330 if (strcmp((char*)field_name, "profile-level-id") == 0) {
1332 tokenlen = end_offset - offset;
1333 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1334 item = proto_tree_add_uint(tree, hf_sdp_fmtp_mpeg4_profile_level_id, tvb, offset, tokenlen,
1335 atol((char*)format_specific_parameter));
1336 PROTO_ITEM_SET_GENERATED(item);
1337 } else if (strcmp((char*)field_name, "config") == 0) {
1338 /* String including "=" */
1339 tokenlen = end_offset - offset;
1340 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1341 /* ascii_bytes_to_tvb requires the "=" to be in the buffer */
1342 data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
1343 if(mp4ves_handle && data_tvb){
1344 dissect_mp4ves_config(data_tvb, pinfo, tree);
1349 /* Dissect the H263-2000 profile parameter if present */
1350 if ((mime_type != NULL && g_ascii_strcasecmp(mime_type, "H263-2000") == 0)||(mime_type != NULL && g_ascii_strcasecmp(mime_type, "H263-1998") == 0)) {
1351 if (strcmp((char*)field_name, "profile") == 0) {
1353 tokenlen = end_offset - offset;
1354 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1355 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_profile, tvb, offset, tokenlen,
1356 atol((char*)format_specific_parameter));
1357 PROTO_ITEM_SET_GENERATED(item);
1358 } else if(strcmp((char*)field_name, "level") == 0) {
1360 tokenlen = end_offset - offset;
1361 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1362 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_level, tvb, offset, tokenlen,
1363 atol((char*)format_specific_parameter));
1364 PROTO_ITEM_SET_GENERATED(item);
1369 /* Dissect the H264 profile-level-id parameter
1371 * A base16 [6] (hexadecimal) representation of
1372 * the following three bytes in the sequence
1373 * parameter set NAL unit specified in [1]: 1)
1374 * profile_idc, 2) a byte herein referred to as
1375 * profile-iop, composed of the values of
1376 * constraint_set0_flag, constraint_set1_flag,
1377 * constraint_set2_flag, and reserved_zero_5bits
1378 * in bit-significance order, starting from the
1379 * most significant bit, and 3) level_idc.
1381 if (mime_type != NULL && g_ascii_strcasecmp(mime_type, "H264") == 0) {
1382 if (strcmp(field_name, "profile-level-id") == 0) {
1385 /* Length includes "=" as it's required by ascii_bytes_to_tvb()*/
1386 tokenlen = end_offset - offset;
1387 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1388 data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
1390 proto_tree_add_text(tree, tvb, offset, tokenlen, "Could not convert '%s' to 3 bytes",format_specific_parameter);
1393 length = tvb_length(data_tvb);
1395 if(h264_handle && data_tvb){
1396 dissect_h264_profile(data_tvb, pinfo, tree);
1399 item = proto_tree_add_text(tree, tvb, offset, tokenlen, "Incorrectly coded, must be three bytes");
1400 PROTO_ITEM_SET_GENERATED(item);
1402 }else if (strcmp(field_name, "packetization-mode") == 0) {
1404 tokenlen = end_offset - offset;
1405 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1406 item = proto_tree_add_uint(tree, hf_sdp_h264_packetization_mode, tvb, offset, tokenlen,
1407 atol((char*)format_specific_parameter));
1408 PROTO_ITEM_SET_GENERATED(item);
1410 }else if (strcmp(field_name, "sprop-parameter-sets") == 0) {
1411 /* The value of the parameter is the
1412 base64 [6] representation of the initial
1413 parameter set NAL units as specified in
1414 sections 7.3.2.1 and 7.3.2.2 of [1]. The
1415 parameter sets are conveyed in decoding order,
1416 and no framing of the parameter set NAL units
1417 takes place. A comma is used to separate any
1418 pair of parameter sets in the list.
1420 gchar *data_p = NULL;
1426 comma_offset = tvb_find_guint8(tvb,offset,-1,',');
1427 if (comma_offset != -1){
1428 tokenlen = comma_offset - offset;
1430 tokenlen = end_offset - offset;
1433 data_p = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1434 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 1 string: %s", data_p);
1436 /* proto_tree_add_text(tree, tvb, offset, tokenlen, "String %s",data_p); */
1437 data_tvb = base64_to_tvb(tvb, data_p);
1438 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets");
1440 if(h264_handle && data_tvb){
1441 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1442 if (comma_offset != -1){
1443 /* Second NAL unit */
1444 offset = comma_offset +1;
1445 tokenlen = end_offset - offset;
1446 data_p = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1447 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 2 string: %s", data_p);
1448 data_tvb = base64_to_tvb(tvb, data_p);
1449 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets 2");
1450 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1462 #define SDP_RTPMAP 1
1465 #define SDP_H248_ITEM 4
1467 static const sdp_names_t sdp_media_attribute_names[] = {
1468 { "Unknown-name"}, /* 0 Pad so that the real headers start at index 1 */
1469 { "rtpmap"}, /* 1 */
1472 { "h248item"}, /* 4 */
1475 static gint find_sdp_media_attribute_names(tvbuff_t *tvb, int offset, guint len)
1479 for (i = 1; i < array_length(sdp_media_attribute_names); i++) {
1480 if (len == strlen(sdp_media_attribute_names[i].name) &&
1481 tvb_strncaseeql(tvb, offset, sdp_media_attribute_names[i].name, len) == 0)
1488 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item * ti, int length, transport_info_t *transport_info){
1489 proto_tree *sdp_media_attribute_tree;
1490 proto_item *fmtp_item, *media_format_item;
1491 proto_tree *fmtp_tree;
1492 gint offset, next_offset, tokenlen, n, colon_offset;
1494 /*??guint8 *field_name;*/
1495 guint8 *payload_type;
1496 guint8 *attribute_value;
1499 gint sdp_media_attrbute_code;
1500 const char *msrp_res = "msrp://";
1501 const char *h324ext_h223lcparm = "h324ext/h223lcparm";
1502 gboolean has_more_pars = TRUE;
1504 encoding_name_and_rate_t *encoding_name_and_rate;
1510 /* Create attribute tree */
1511 sdp_media_attribute_tree = proto_item_add_subtree(ti,
1512 ett_sdp_media_attribute);
1513 /* Find end of field */
1514 colon_offset = tvb_find_guint8(tvb,offset,-1,':');
1516 if(colon_offset == -1)
1519 /* Attribute field name is token before ':' */
1520 tokenlen = colon_offset - offset;
1521 proto_tree_add_item(sdp_media_attribute_tree,
1522 hf_media_attribute_field,
1523 tvb, offset, tokenlen, FALSE);
1524 /*??field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);*/
1525 sdp_media_attrbute_code = find_sdp_media_attribute_names(tvb, offset, tokenlen);
1528 offset = colon_offset + 1;
1529 /* skip leading wsp */
1530 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1532 /* Value is the remainder of the line */
1533 attribute_value = tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
1537 /*********************************************/
1538 /* Special parsing for some field name types */
1540 switch (sdp_media_attrbute_code){
1542 /* decode the rtpmap to see if it is DynamicPayload to dissect them automatic */
1543 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1545 if(next_offset == -1)
1548 tokenlen = next_offset - offset;
1550 proto_tree_add_item(sdp_media_attribute_tree, hf_media_format, tvb,
1551 offset, tokenlen, FALSE);
1553 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1555 offset = next_offset + 1;
1557 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
1559 if(next_offset == -1){
1563 tokenlen = next_offset - offset;
1565 start_offset = offset;
1566 proto_tree_add_item(sdp_media_attribute_tree, hf_media_encoding_name, tvb,
1567 offset, tokenlen, FALSE);
1569 key=g_malloc( sizeof(gint) );
1570 *key=atol((char*)payload_type);
1571 pt = atoi((char*)payload_type);
1572 if (pt >= SDP_NO_OF_PT) {
1573 return; /* Invalid */
1575 transport_info->encoding_name[pt] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1577 next_offset = next_offset + 1;
1578 offset = next_offset;
1579 while (length-1 >= next_offset){
1580 if(!isdigit(tvb_get_guint8(tvb, next_offset)))
1584 tokenlen = next_offset - offset;
1585 proto_tree_add_item(sdp_media_attribute_tree, hf_media_sample_rate, tvb,
1586 offset, tokenlen, FALSE);
1587 transport_info->sample_rate[pt] = atoi(tvb_get_ephemeral_string(tvb, offset, tokenlen));
1588 /* As per RFC2327 it is possible to have multiple Media Descriptions ("m=").
1591 a=rtpmap:101 G726-32/8000
1592 m=audio 49170 RTP/AVP 0 97
1593 a=rtpmap:97 telephone-event/8000
1594 m=audio 49172 RTP/AVP 97 101
1595 a=rtpmap:97 G726-24/8000
1597 The Media attributes ("a="s) after the "m=" only apply for that "m=".
1598 If there is an "a=" before the first "m=", that attribute applies for
1599 all the session (all the "m="s).
1602 /* so, if this "a=" appear before any "m=", we add it to all the dynamic
1605 if (transport_info->media_count == 0) {
1606 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++) {
1607 encoding_name_and_rate = g_malloc( sizeof(encoding_name_and_rate_t));
1608 encoding_name_and_rate->encoding_name = g_strdup(transport_info->encoding_name[pt]);
1609 encoding_name_and_rate->sample_rate = transport_info->sample_rate[pt];
1611 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1612 key, encoding_name_and_rate);
1614 else { /* we create a new key and encoding_name to assign to the other hash tables */
1616 key2=g_malloc( sizeof(gint) );
1617 *key2=atol((char*)payload_type);
1618 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1619 key2, encoding_name_and_rate);
1623 /* if the "a=" is after an "m=", only apply to this "m=" */
1625 /* in case there is an overflow in SDP_MAX_RTP_CHANNELS, we keep always the last "m=" */
1626 encoding_name_and_rate = g_malloc( sizeof(encoding_name_and_rate_t));
1628 encoding_name_and_rate->encoding_name = g_strdup(transport_info->encoding_name[pt]);
1629 encoding_name_and_rate->sample_rate = transport_info->sample_rate[pt];
1630 if (transport_info->media_count == SDP_MAX_RTP_CHANNELS-1)
1631 g_hash_table_insert(transport_info->media[ transport_info->media_count ].rtp_dyn_payload,
1632 key, encoding_name_and_rate);
1634 g_hash_table_insert(transport_info->media[ transport_info->media_count-1 ].rtp_dyn_payload,
1635 key, encoding_name_and_rate);
1638 if(sdp_media_attribute_tree){
1639 guint8 media_format;
1640 /* Reading the Format parameter(fmtp) */
1641 /* Skip leading space, if any */
1642 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1643 /* Media format extends to the next space */
1644 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1646 if(next_offset == -1)
1649 tokenlen = next_offset - offset;
1652 media_format_item = proto_tree_add_item(sdp_media_attribute_tree,
1653 hf_media_format, tvb, offset,
1655 media_format = atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen));
1656 if (media_format >= SDP_NO_OF_PT) {
1657 return; /* Invalid */
1660 /* Append encoding name to format if known */
1661 proto_item_append_text(media_format_item, " [%s]",
1662 transport_info->encoding_name[media_format]);
1664 /*??payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);*/
1665 /* Move offset past the payload type */
1666 offset = next_offset + 1;
1668 while(has_more_pars==TRUE){
1669 next_offset = tvb_find_guint8(tvb,offset,-1,';');
1670 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1672 if(next_offset == -1){
1673 has_more_pars = FALSE;
1674 next_offset= tvb_length(tvb);
1679 /* There are at least 2 - add the first parameter */
1680 tokenlen = next_offset - offset;
1681 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1682 hf_media_format_specific_parameter, tvb,
1683 offset, tokenlen, FALSE);
1685 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1687 decode_sdp_fmtp(fmtp_tree, tvb, pinfo, offset, tokenlen,
1688 transport_info->encoding_name[media_format]);
1690 /* Move offset past "; " and onto firts char */
1691 offset = next_offset + 1;
1696 /* msrp attributes that contain address needed for conversation */
1698 * path = path-label ":" path-list
1699 * path-label = "path"
1700 * path-list= MSRP-URI *(SP MSRP-URI)
1701 * MSRP-URI = msrp-scheme "://" authority
1702 * ["/" session-id] ";" transport *( ";" URI-parameter)
1703 * ; authority as defined in RFC3986
1705 * msrp-scheme = "msrp" / "msrps"
1707 * The authority component is preceded by a double slash ("//") and is terminated by
1708 * the next slash ("/"), question mark ("?"), or number sign ("#") character, or by
1709 * the end of the URI.
1712 /* Check for "msrp://" */
1713 if (strncmp((char*)attribute_value, msrp_res, strlen(msrp_res)) == 0){
1714 int address_offset, port_offset, port_end_offset;
1716 /* Address starts here */
1717 address_offset = offset + (int)strlen(msrp_res);
1719 /* Port is after next ':' */
1720 port_offset = tvb_find_guint8(tvb, address_offset, -1, ':');
1721 /* Check if port is present if not skipp */
1722 if(port_offset!= -1){
1723 /* Port ends with '/' */
1724 port_end_offset = tvb_find_guint8(tvb, port_offset, -1, '/');
1726 /* Attempt to convert address */
1727 if (inet_pton(AF_INET, (char*)tvb_get_ephemeral_string(tvb, address_offset, port_offset-address_offset), &msrp_ipaddr) > 0) {
1728 /* Get port number */
1729 msrp_port_number = atoi((char*)tvb_get_ephemeral_string(tvb, port_offset+1, port_end_offset-port_offset-1));
1730 /* Set flag so this info can be used */
1731 msrp_transport_address_set = TRUE;
1737 /* Decode h248 item ITU-T Rec. H.248.12 (2001)/Amd.1 (11/2002)*/
1738 if (strncmp((char*)attribute_value, h324ext_h223lcparm, strlen(msrp_res)) == 0){
1739 /* A.5.1.3 H.223 Logical channel parameters
1740 * This property indicates the H.245
1741 * H223LogicalChannelsParameters structure encoded by applying the PER specified in
1742 * ITU-T Rec. X.691. Value encoded as per A.5.1.2. For text encoding the mechanism defined
1743 * in ITU-T Rec. H.248.15 is used.
1748 len = (gint)strlen(attribute_value);
1749 h245_tvb = ascii_bytes_to_tvb(tvb, pinfo, len, attribute_value);
1750 /* arbitrary maximum length */
1751 /* should go through a handle, however, the two h245 entry
1752 points are different, one is over tpkt and the other is raw
1755 asn1_ctx_init(&actx, ASN1_ENC_PER, TRUE, pinfo);
1756 dissect_h245_H223LogicalChannelParameters(h245_tvb, 0, &actx, sdp_media_attribute_tree, hf_SDPh223LogicalChannelParameters);
1761 /* No special treatment for values of this attribute type, just add as one item. */
1762 proto_tree_add_item(sdp_media_attribute_tree, hf_media_attribute_value,
1763 tvb, offset, -1, FALSE);
1769 proto_register_sdp(void)
1771 static hf_register_info hf[] = {
1772 { &hf_protocol_version,
1773 { "Session Description Protocol Version (v)",
1774 "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
1777 { "Owner/Creator, Session Id (o)",
1778 "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
1781 { "Session Name (s)",
1782 "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
1785 { "Session Information (i)",
1786 "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
1789 { "URI of Description (u)",
1790 "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
1793 { "E-mail Address (e)",
1794 "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
1795 "E-mail Address", HFILL }},
1797 { "Phone Number (p)",
1798 "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
1800 { &hf_connection_info,
1801 { "Connection Information (c)",
1802 "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
1805 { "Bandwidth Information (b)",
1806 "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
1809 { "Time Zone Adjustments (z)",
1810 "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
1812 { &hf_encryption_key,
1813 { "Encryption Key (k)",
1814 "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
1816 { &hf_session_attribute,
1817 { "Session Attribute (a)",
1818 "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1820 { &hf_media_attribute,
1821 { "Media Attribute (a)",
1822 "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1825 { "Time Description, active time (t)",
1826 "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
1829 { "Repeat Time (r)",
1830 "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
1833 { "Media Description, name and address (m)",
1834 "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
1837 { "Media Title (i)",
1838 "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
1839 "Media Title", HFILL }},
1842 "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
1846 "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
1848 { &hf_owner_username,
1850 "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
1852 { &hf_owner_sessionid,
1854 "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
1856 { &hf_owner_version,
1857 { "Session Version",
1858 "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
1860 { &hf_owner_network_type,
1861 { "Owner Network Type",
1862 "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1864 { &hf_owner_address_type,
1865 { "Owner Address Type",
1866 "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1868 { &hf_owner_address,
1870 "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
1872 { &hf_connection_info_network_type,
1873 { "Connection Network Type",
1874 "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1876 { &hf_connection_info_address_type,
1877 { "Connection Address Type",
1878 "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1880 { &hf_connection_info_connection_address,
1881 { "Connection Address",
1882 "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
1884 { &hf_connection_info_ttl,
1886 "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
1888 { &hf_connection_info_num_addr,
1889 { "Connection Number of Addresses",
1890 "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
1892 { &hf_bandwidth_modifier,
1893 { "Bandwidth Modifier",
1894 "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
1896 { &hf_bandwidth_value,
1897 { "Bandwidth Value",
1898 "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
1899 "Bandwidth Value (in kbits/s)", HFILL }},
1901 { "Session Start Time",
1902 "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
1905 { "Session Stop Time",
1906 "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
1908 { &hf_repeat_time_interval,
1909 { "Repeat Interval",
1910 "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
1912 { &hf_repeat_time_duration,
1913 { "Repeat Duration",
1914 "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
1916 { &hf_repeat_time_offset,
1918 "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1920 { &hf_timezone_time,
1922 "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
1924 { &hf_timezone_offset,
1925 { "Timezone Offset",
1926 "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1928 { &hf_encryption_key_type,
1930 "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
1932 { &hf_encryption_key_data,
1934 "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
1936 { &hf_session_attribute_field,
1937 { "Session Attribute Fieldname",
1938 "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
1940 { &hf_session_attribute_value,
1941 { "Session Attribute Value",
1942 "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
1946 "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
1950 "sdp.media.port",FT_UINT16, BASE_DEC, NULL, 0x0,
1952 { &hf_media_portcount,
1953 { "Media Port Count",
1954 "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
1958 "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
1962 "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
1964 { &hf_media_attribute_field,
1965 { "Media Attribute Fieldname",
1966 "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
1968 { &hf_media_attribute_value,
1969 { "Media Attribute Value",
1970 "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
1972 { &hf_media_encoding_name,
1974 "sdp.mime.type",FT_STRING, BASE_NONE, NULL, 0x0,
1975 "SDP MIME Type", HFILL }},
1976 { &hf_media_sample_rate,
1978 "sdp.sample_rate",FT_STRING, BASE_NONE, NULL, 0x0,
1980 { &hf_media_format_specific_parameter,
1981 { "Media format specific parameters",
1982 "sdp.fmtp.parameter",FT_STRING, BASE_NONE, NULL, 0x0,
1983 "Format specific parameter(fmtp)", HFILL }},
1984 { &hf_ipbcp_version,
1985 { "IPBCP Protocol Version",
1986 "ipbcp.version",FT_STRING, BASE_NONE, NULL, 0x0,
1989 { "IPBCP Command Type",
1990 "ipbcp.command",FT_STRING, BASE_NONE, NULL, 0x0,
1992 {&hf_sdp_fmtp_mpeg4_profile_level_id,
1994 "sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mp4ves_level_indication_vals), 0x0,
1996 { &hf_sdp_fmtp_h263_profile,
1998 "sdp.fmtp.h263profile",FT_UINT32, BASE_DEC,VALS(h263_profile_vals), 0x0,
2000 { &hf_sdp_fmtp_h263_level,
2002 "sdp.fmtp.h263level",FT_UINT32, BASE_DEC,VALS(h263_level_vals), 0x0,
2004 { &hf_sdp_h264_packetization_mode,
2005 { "Packetization mode",
2006 "sdp.fmtp.h264_packetization_mode",FT_UINT32, BASE_DEC,VALS(h264_packetization_mode_vals), 0x0,
2008 { &hf_sdp_h264_sprop_parameter_sets,
2009 { "Sprop_parameter_sets",
2010 "sdp.h264.sprop_parameter_sets", FT_BYTES, BASE_NONE, NULL, 0x0,
2012 { &hf_SDPh223LogicalChannelParameters,
2013 { "h223LogicalChannelParameters", "sdp.h223LogicalChannelParameters",
2014 FT_NONE, BASE_NONE, NULL, 0,
2016 { &hf_key_mgmt_att_value,
2018 "sdp.key_mgmt", FT_STRING, BASE_NONE, NULL, 0x0,
2020 { &hf_key_mgmt_prtcl_id,
2021 { "Key Management Protocol (kmpid)",
2022 "sdp.key_mgmt.kmpid", FT_STRING, BASE_NONE, NULL, 0x0,
2024 { &hf_key_mgmt_data,
2025 { "Key Management Data",
2026 "sdp.key_mgmt.data", FT_BYTES, BASE_NONE, NULL, 0x0,
2029 static gint *ett[] = {
2032 &ett_sdp_connection_info,
2035 &ett_sdp_repeat_time,
2037 &ett_sdp_encryption_key,
2038 &ett_sdp_session_attribute,
2040 &ett_sdp_media_attribute,
2045 module_t *sdp_module;
2047 proto_sdp = proto_register_protocol("Session Description Protocol",
2049 proto_register_field_array(proto_sdp, hf, array_length(hf));
2050 proto_register_subtree_array(ett, array_length(ett));
2052 key_mgmt_dissector_table = register_dissector_table("key_mgmt",
2053 "Key Management", FT_STRING, BASE_NONE);
2056 * Preferences registration
2058 sdp_module = prefs_register_protocol(proto_sdp, NULL);
2059 prefs_register_bool_preference(sdp_module, "establish_conversation",
2060 "Establish Media Conversation",
2061 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
2062 "upon port numbers found in SDP payload",
2063 &global_sdp_establish_conversation);
2066 * Register the dissector by name, so other dissectors can
2067 * grab it by name rather than just referring to it directly.
2069 register_dissector("sdp", dissect_sdp, proto_sdp);
2071 /* Register for tapping */
2072 sdp_tap = register_tap("sdp");
2076 proto_reg_handoff_sdp(void)
2078 dissector_handle_t sdp_handle;
2080 rtp_handle = find_dissector("rtp");
2081 rtcp_handle = find_dissector("rtcp");
2082 msrp_handle = find_dissector("msrp");
2083 t38_handle = find_dissector("t38");
2084 h264_handle = find_dissector("h264");
2085 mp4ves_handle = find_dissector("mp4ves");
2087 sdp_handle = find_dissector("sdp");
2088 dissector_add_string("media_type", "application/sdp", sdp_handle);
2089 dissector_add_uint("bctp.tpi", 0x20, sdp_handle);