2 * Routines for SDP packet disassembly (RFC 2327)
4 * Jason Lango <jal@netapp.com>
5 * Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Ref http://www.ietf.org/rfc/rfc4566.txt?number=4566
35 #ifdef HAVE_SYS_TYPES_H
36 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
44 #ifdef HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
48 #ifdef HAVE_WINSOCK2_H
49 #include <winsock2.h> /* needed to define AF_ values on Windows */
52 #ifdef NEED_INET_V6DEFS_H
53 # include "inet_v6defs.h"
57 #include <epan/packet.h>
58 #include <epan/strutil.h>
59 #include <epan/emem.h>
60 #include <epan/base64.h>
61 #include <epan/asn1.h>
64 #include "packet-sdp.h"
66 #include "packet-rtp.h"
67 #include <epan/rtp_pt.h>
69 #include <epan/prefs.h>
70 #include <epan/expert.h>
72 #include "packet-rtcp.h"
73 #include "packet-t38.h"
74 #include "packet-msrp.h"
75 #include "packet-per.h"
76 #include "packet-h245.h"
77 #include "packet-h264.h"
78 #include "packet-mp4ves.h"
80 static dissector_handle_t rtp_handle=NULL;
81 static dissector_handle_t rtcp_handle=NULL;
82 static dissector_handle_t t38_handle=NULL;
83 static dissector_handle_t msrp_handle=NULL;
84 static dissector_handle_t h264_handle = NULL;
85 static dissector_handle_t mp4ves_handle = NULL;
87 static int sdp_tap = -1;
89 static int proto_sdp = -1;
91 /* preference globals */
92 static gboolean global_sdp_establish_conversation = TRUE;
94 /* Top level fields */
95 static int hf_protocol_version = -1;
96 static int hf_owner = -1;
97 static int hf_session_name = -1;
98 static int hf_session_info = -1;
99 static int hf_uri = -1;
100 static int hf_email = -1;
101 static int hf_phone = -1;
102 static int hf_connection_info = -1;
103 static int hf_bandwidth = -1;
104 static int hf_timezone = -1;
105 static int hf_encryption_key = -1;
106 static int hf_session_attribute = -1;
107 static int hf_media_attribute = -1;
108 static int hf_time = -1;
109 static int hf_repeat_time = -1;
110 static int hf_media = -1;
111 static int hf_media_title = -1;
112 static int hf_unknown = -1;
113 static int hf_invalid = -1;
114 static int hf_ipbcp_version = -1;
115 static int hf_ipbcp_type = -1;
117 /* hf_owner subfields*/
118 static int hf_owner_username = -1;
119 static int hf_owner_sessionid = -1;
120 static int hf_owner_version = -1;
121 static int hf_owner_network_type = -1;
122 static int hf_owner_address_type = -1;
123 static int hf_owner_address = -1;
125 /* hf_connection_info subfields */
126 static int hf_connection_info_network_type = -1;
127 static int hf_connection_info_address_type = -1;
128 static int hf_connection_info_connection_address = -1;
129 static int hf_connection_info_ttl = -1;
130 static int hf_connection_info_num_addr = -1;
132 /* hf_bandwidth subfields */
133 static int hf_bandwidth_modifier = -1;
134 static int hf_bandwidth_value = -1;
136 /* hf_time subfields */
137 static int hf_time_start = -1;
138 static int hf_time_stop = -1;
140 /* hf_repeat_time subfield */
141 static int hf_repeat_time_interval = -1;
142 static int hf_repeat_time_duration = -1;
143 static int hf_repeat_time_offset = -1;
145 /* hf_timezone subfields */
146 static int hf_timezone_time = -1;
147 static int hf_timezone_offset = -1;
149 /* hf_encryption_key subfields */
150 static int hf_encryption_key_type = -1;
151 static int hf_encryption_key_data = -1;
153 /* hf_session_attribute subfields */
154 static int hf_session_attribute_field = -1;
155 static int hf_session_attribute_value = -1;
157 /* hf_media subfields */
158 static int hf_media_media = -1;
159 static int hf_media_port = -1;
160 static int hf_media_portcount = -1;
161 static int hf_media_proto = -1;
162 static int hf_media_format = -1;
164 /* hf_session_attribute subfields */
165 static int hf_media_attribute_field = -1;
166 static int hf_media_attribute_value = -1;
167 static int hf_media_encoding_name = -1;
168 static int hf_media_sample_rate = -1;
169 static int hf_media_format_specific_parameter = -1;
170 static int hf_sdp_fmtp_mpeg4_profile_level_id = -1;
171 static int hf_sdp_fmtp_h263_profile = -1;
172 static int hf_sdp_fmtp_h263_level = -1;
173 static int hf_sdp_h264_packetization_mode = -1;
174 static int hf_sdp_h264_sprop_parameter_sets = -1;
175 static int hf_SDPh223LogicalChannelParameters = -1;
177 /* hf_session_attribute hf_media_attribute subfields */
178 static int hf_key_mgmt_att_value = -1;
179 static int hf_key_mgmt_prtcl_id = -1;
180 static int hf_key_mgmt_data = -1;
183 static int ett_sdp = -1;
184 static int ett_sdp_owner = -1;
185 static int ett_sdp_connection_info = -1;
186 static int ett_sdp_bandwidth = -1;
187 static int ett_sdp_time = -1;
188 static int ett_sdp_repeat_time = -1;
189 static int ett_sdp_timezone = -1;
190 static int ett_sdp_encryption_key = -1;
191 static int ett_sdp_session_attribute = -1;
192 static int ett_sdp_media = -1;
193 static int ett_sdp_media_attribute = -1;
194 static int ett_sdp_fmtp = -1;
195 static int ett_sdp_key_mgmt = -1;
198 #define SDP_MAX_RTP_CHANNELS 4
199 #define SDP_MAX_RTP_PAYLOAD_TYPES 20
200 #define SDP_NO_OF_PT 128
202 gint32 pt[SDP_MAX_RTP_PAYLOAD_TYPES];
204 GHashTable *rtp_dyn_payload;
205 } transport_media_pt_t;
208 char *connection_address;
209 char *connection_type;
211 char *encoding_name[SDP_NO_OF_PT];
212 char *media_port[SDP_MAX_RTP_CHANNELS];
213 char *media_proto[SDP_MAX_RTP_CHANNELS];
214 transport_media_pt_t media[SDP_MAX_RTP_CHANNELS];
219 /* MSRP transport info (as set while parsing path attribute) */
220 static gboolean msrp_transport_address_set = FALSE;
221 static guint32 msrp_ipaddr[4];
222 static guint16 msrp_port_number;
224 /* key-mgmt dissector
226 * http://www.iana.org/assignments/sdp-parameters
228 static dissector_table_t key_mgmt_dissector_table;
231 /* Protocol registration */
232 void proto_register_sdp(void);
233 void proto_reg_handoff_sdp(void);
236 /* static functions */
238 static void call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti,
239 transport_info_t *transport_info);
241 /* Subdissector functions */
242 static void dissect_sdp_owner(tvbuff_t *tvb, proto_item* ti);
243 static void dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
244 transport_info_t *transport_info);
245 static void dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti);
246 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti);
247 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti);
248 static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti);
249 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti);
250 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti);
251 static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
252 transport_info_t *transport_info);
253 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti, transport_info_t *transport_info);
256 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
258 proto_tree *sdp_tree;
259 proto_item *ti, *sub_ti;
263 gboolean in_media_description;
273 transport_info_t transport_info;
276 gboolean is_rtp=FALSE;
277 gboolean is_srtp=FALSE;
278 gboolean is_t38=FALSE;
279 gboolean is_msrp=FALSE;
280 gboolean set_rtp=FALSE;
281 gboolean is_ipv4_addr=FALSE;
282 gboolean is_ipv6_addr=FALSE;
283 gboolean is_video=FALSE;
286 sdp_packet_info *sdp_pi;
287 gchar *unknown_encoding = ep_strdup("Unknown");
289 /* Initialise packet info for passing to tap */
290 sdp_pi = ep_alloc(sizeof(sdp_packet_info));
291 sdp_pi->summary_str[0] = '\0';
293 /* Initialise RTP channel info */
294 transport_info.connection_address=NULL;
295 transport_info.connection_type=NULL;
296 transport_info.media_type=NULL;
297 for (n=0; n < SDP_NO_OF_PT; n++){
298 transport_info.encoding_name[n]=unknown_encoding;
300 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++)
302 transport_info.media_port[n]=NULL;
303 transport_info.media_proto[n]=NULL;
304 transport_info.media[n].pt_count = 0;
305 transport_info.media[n].rtp_dyn_payload =
306 g_hash_table_new_full( g_int_hash, g_int_equal, g_free, g_free);
308 transport_info.media_count = 0;
311 * As RFC 2327 says, "SDP is purely a format for session
312 * description - it does not incorporate a transport protocol,
313 * and is intended to use different transport protocols as
314 * appropriate including the Session Announcement Protocol,
315 * Session Initiation Protocol, Real-Time Streaming Protocol,
316 * electronic mail using the MIME extensions, and the
317 * Hypertext Transport Protocol."
319 * We therefore don't set the protocol or info columns;
320 * instead, we append to them, so that we don't erase
321 * what the protocol inside which the SDP stuff resides
324 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
326 /* XXX: Needs description. */
327 col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
329 ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
330 sdp_tree = proto_item_add_subtree(ti, ett_sdp);
333 * Show the SDP message a line at a time.
335 in_media_description = FALSE;
337 while (tvb_reported_length_remaining(tvb, offset) > 0) {
339 * Find the end of the line.
341 linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
346 * Line must contain at least e.g. "v=".
351 type = tvb_get_guint8(tvb,offset);
352 delim = tvb_get_guint8(tvb,offset + 1);
354 proto_item *ti = proto_tree_add_item(sdp_tree, hf_invalid, tvb, offset, linelen, FALSE);
355 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_NOTE,
356 "Invalid SDP line (no '=' delimiter)");
357 offset = next_offset;
366 hf = hf_protocol_version;
372 hf = hf_session_name;
375 if (in_media_description) {
379 hf = hf_session_info;
392 hf = hf_connection_info;
405 in_media_description = TRUE;
408 hf = hf_encryption_key;
411 if (in_media_description) {
412 hf = hf_media_attribute;
415 hf = hf_session_attribute;
426 if (hf == hf_unknown)
428 string = (char*)tvb_get_ephemeral_string(tvb, offset + tokenoffset,
429 linelen - tokenoffset);
430 sub_ti = proto_tree_add_string(sdp_tree, hf, tvb, offset, linelen,
432 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
434 linelen-tokenoffset),
436 hf,sub_ti,&transport_info),
437 offset = next_offset;
441 /* Now look, if we have strings collected.
442 * Try to convert ipv4 addresses and ports into binary format,
443 * so we can use them to detect rtp and rtcp streams.
444 * Don't forget to free the strings!
447 for (n = 0; n < transport_info.media_count; n++)
449 if(transport_info.media_port[n]!=NULL) {
450 port = atol(transport_info.media_port[n]);
452 if(transport_info.media_proto[n]!=NULL) {
453 /* Check if media protocol is RTP
454 * and stream decoding is enabled in preferences
456 if(global_sdp_establish_conversation){
457 /* Check if media protocol is RTP */
458 is_rtp = (strcmp(transport_info.media_proto[n],"RTP/AVP")==0);
459 /* Check if media protocol is SRTP */
460 is_srtp = (strcmp(transport_info.media_proto[n],"RTP/SAVP")==0);
461 /* Check if media protocol is T38 */
462 is_t38 = ( (strcmp(transport_info.media_proto[n],"UDPTL")==0) ||
463 (strcmp(transport_info.media_proto[n],"udptl")==0) );
464 /* Check if media protocol is MSRP/TCP */
465 is_msrp = (strcmp(transport_info.media_proto[n],"msrp/tcp")==0);
470 if(transport_info.connection_address!=NULL) {
471 if(transport_info.connection_type!=NULL) {
472 if (strcmp(transport_info.connection_type,"IP4")==0) {
473 if(inet_pton(AF_INET,transport_info.connection_address, &ipaddr)==1 ) {
474 /* connection_address could be converted to a valid ipv4 address*/
476 src_addr.type=AT_IPv4;
480 else if (strcmp(transport_info.connection_type,"IP6")==0){
481 if (inet_pton(AF_INET6, transport_info.connection_address, &ipaddr)==1){
482 /* connection_address could be converted to a valid ipv6 address*/
484 src_addr.type=AT_IPv6;
490 if (strcmp(transport_info.media_type,"video")==0){
494 /* Add (s)rtp and (s)rtcp conversation, if available (overrides t38 if conversation already set) */
495 if((!pinfo->fd->flags.visited) && port!=0 && (is_rtp||is_srtp) && (is_ipv4_addr || is_ipv6_addr)){
496 src_addr.data=(guint8*)&ipaddr;
499 struct srtp_info *dummy_srtp_info = se_alloc0(sizeof(struct srtp_info));
500 srtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num, is_video,
501 transport_info.media[n].rtp_dyn_payload, dummy_srtp_info);
503 rtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num, is_video,
504 transport_info.media[n].rtp_dyn_payload);
510 rtcp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
514 /* Add t38 conversation, if available and only if no rtp */
515 if((!pinfo->fd->flags.visited) && port!=0 && !set_rtp && is_t38 && is_ipv4_addr){
516 src_addr.data=(guint8*)&ipaddr;
518 t38_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
522 /* Add MSRP conversation. Uses addresses discovered in attribute
523 rather than connection information of media session line */
525 if ((!pinfo->fd->flags.visited) && msrp_transport_address_set){
527 src_addr.type=AT_IPv4;
529 src_addr.data=(guint8*)&msrp_ipaddr;
530 msrp_add_address(pinfo, &src_addr, msrp_port_number, "SDP", pinfo->fd->num);
535 /* Create the RTP summary str for the Voip Call analysis */
536 for (i = 0; i < transport_info.media[n].pt_count; i++)
538 /* if the payload type is dynamic (96 to 127), check the hash table to add the desc in the SDP summary */
539 if ( (transport_info.media[n].pt[i] >=96) && (transport_info.media[n].pt[i] <=127) ) {
540 gchar *str_dyn_pt = g_hash_table_lookup(transport_info.media[n].rtp_dyn_payload, &transport_info.media[n].pt[i]);
542 g_snprintf(sdp_pi->summary_str, 50, "%s %s", sdp_pi->summary_str, str_dyn_pt);
544 g_snprintf(sdp_pi->summary_str, 50, "%s %d", sdp_pi->summary_str, transport_info.media[n].pt[i]);
546 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"));
549 /* Free the hash table if we did't assigned it to a conv use it */
550 if (set_rtp == FALSE)
551 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
553 /* Create the T38 summary str for the Voip Call analysis */
554 if (is_t38) g_snprintf(sdp_pi->summary_str, 50, "%s t38", sdp_pi->summary_str);
557 /* Free the remainded hash tables not used */
558 for (n = transport_info.media_count; n < SDP_MAX_RTP_CHANNELS; n++)
560 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
564 datalen = tvb_length_remaining(tvb, offset);
566 proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)",
570 /* Report this packet to the tap */
571 tap_queue_packet(sdp_tap, pinfo, sdp_pi);
575 call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, transport_info_t *transport_info){
577 dissect_sdp_owner(tvb,ti);
578 } else if ( hf == hf_connection_info) {
579 dissect_sdp_connection_info(tvb,ti,transport_info);
580 } else if ( hf == hf_bandwidth) {
581 dissect_sdp_bandwidth(tvb,ti);
582 } else if ( hf == hf_time) {
583 dissect_sdp_time(tvb,ti);
584 } else if ( hf == hf_repeat_time ){
585 dissect_sdp_repeat_time(tvb,ti);
586 } else if ( hf == hf_timezone ) {
587 dissect_sdp_timezone(tvb,ti);
588 } else if ( hf == hf_encryption_key ) {
589 dissect_sdp_encryption_key(tvb,ti);
590 } else if ( hf == hf_session_attribute ){
591 dissect_sdp_session_attribute(tvb,pinfo,ti);
592 } else if ( hf == hf_media ) {
593 dissect_sdp_media(tvb,ti,transport_info);
594 } else if ( hf == hf_media_attribute ){
595 dissect_sdp_media_attribute(tvb,pinfo,ti,transport_info);
600 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
601 proto_tree *sdp_owner_tree;
602 gint offset,next_offset,tokenlen;
608 sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
610 /* Find the username */
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_username, tvb, offset, tokenlen,
618 offset = next_offset + 1;
620 /* Find the session id */
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_sessionid, tvb, offset,
628 offset = next_offset + 1;
630 /* Find the version */
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_version, tvb, offset, tokenlen,
638 offset = next_offset + 1;
640 /* Find the network 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_network_type, tvb, offset,
648 offset = next_offset + 1;
650 /* Find the address type */
651 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
652 if( next_offset == -1 )
654 tokenlen = next_offset - offset;
656 proto_tree_add_item(sdp_owner_tree, hf_owner_address_type, tvb, offset,
658 offset = next_offset + 1;
660 /* Find the address */
661 proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
665 * XXX - this can leak memory if an exception is thrown after we've fetched
669 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
670 transport_info_t *transport_info){
671 proto_tree *sdp_connection_info_tree;
672 gint offset,next_offset,tokenlen;
678 sdp_connection_info_tree = proto_item_add_subtree(ti,
679 ett_sdp_connection_info);
681 /* Find the network type */
682 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
683 if( next_offset == -1 )
685 tokenlen = next_offset - offset;
687 proto_tree_add_item(sdp_connection_info_tree,
688 hf_connection_info_network_type, tvb, offset, tokenlen,
690 offset = next_offset + 1;
692 /* Find the address type */
693 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
694 if( next_offset == -1 )
696 tokenlen = next_offset - offset;
697 /* Save connection address type */
698 transport_info->connection_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
701 proto_tree_add_item(sdp_connection_info_tree,
702 hf_connection_info_address_type, tvb, offset, tokenlen,
704 offset = next_offset + 1;
706 /* Find the connection address */
707 /* XXX - what if there's a <number of addresses> value? */
708 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
709 if( next_offset == -1){
710 tokenlen = -1; /* end of tvbuff */
711 /* Save connection address */
712 transport_info->connection_address =
713 (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
715 tokenlen = next_offset - offset;
716 /* Save connection address */
717 transport_info->connection_address = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
720 proto_tree_add_item(sdp_connection_info_tree,
721 hf_connection_info_connection_address, tvb, offset,
723 if(next_offset != -1){
724 offset = next_offset + 1;
725 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
726 if( next_offset == -1){
727 tokenlen = -1; /* end of tvbuff */
729 tokenlen = next_offset - offset;
731 proto_tree_add_item(sdp_connection_info_tree,
732 hf_connection_info_ttl, tvb, offset, tokenlen, FALSE);
733 if(next_offset != -1){
734 offset = next_offset + 1;
735 proto_tree_add_item(sdp_connection_info_tree,
736 hf_connection_info_num_addr, tvb, offset, -1, FALSE);
742 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
743 proto_tree * sdp_bandwidth_tree;
744 gint offset, next_offset, tokenlen;
746 gboolean unit_is_kbs = FALSE;
747 gboolean unit_is_bps = FALSE;
753 sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
755 /* find the modifier */
756 next_offset = tvb_find_guint8(tvb,offset,-1,':');
758 if( next_offset == -1)
761 tokenlen = next_offset - offset;
763 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier, tvb, offset,
765 if (tvb_strneql(tvb, offset, "CT", 2) == 0){
766 proto_item_append_text(item, " [Conference Total(total bandwidth of all RTP sessions)]");
768 }else if (tvb_strneql(tvb, offset, "AS", 2) == 0){
769 proto_item_append_text(item, " [Application Specific (RTP session bandwidth)]");
771 }else if (tvb_strneql(tvb, offset, "TIAS", 4) == 0){
772 proto_item_append_text(item, " [Transport Independent Application Specific maximum]");
777 offset = next_offset + 1;
779 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value, tvb, offset, -1,
781 if (unit_is_kbs == TRUE)
782 proto_item_append_text(item, " kb/s");
783 if (unit_is_bps == TRUE)
784 proto_item_append_text(item, " b/s");
787 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
788 proto_tree *sdp_time_tree;
789 gint offset,next_offset, tokenlen;
795 sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
798 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
799 if( next_offset == -1 )
802 tokenlen = next_offset - offset;
803 proto_tree_add_item(sdp_time_tree, hf_time_start, tvb, offset, tokenlen,
807 offset = next_offset + 1;
808 proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb, offset, -1, FALSE);
811 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
812 proto_tree *sdp_repeat_time_tree;
813 gint offset,next_offset, tokenlen;
819 sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
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_interval, tvb,
828 offset, tokenlen, FALSE);
831 offset = next_offset + 1;
832 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
833 if( next_offset == -1 )
836 tokenlen = next_offset - offset;
837 proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
838 offset, tokenlen, FALSE);
842 offset = next_offset +1;
843 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
844 if(next_offset != -1){
845 tokenlen = next_offset - offset;
847 tokenlen = -1; /* end of tvbuff */
849 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
850 tvb, offset, tokenlen, FALSE);
851 } while( next_offset != -1 );
855 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
856 proto_tree* sdp_timezone_tree;
857 gint offset, next_offset, tokenlen;
862 sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
865 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
866 if(next_offset == -1)
868 tokenlen = next_offset - offset;
870 proto_tree_add_item(sdp_timezone_tree, hf_timezone_time, tvb, offset,
872 offset = next_offset + 1;
873 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
874 if(next_offset != -1){
875 tokenlen = next_offset - offset;
877 tokenlen = -1; /* end of tvbuff */
879 proto_tree_add_item(sdp_timezone_tree, hf_timezone_offset, tvb, offset,
881 offset = next_offset + 1;
882 } while (next_offset != -1);
887 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
888 proto_tree *sdp_encryption_key_tree;
889 gint offset, next_offset, tokenlen;
895 sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
897 next_offset = tvb_find_guint8(tvb,offset,-1,':');
899 if(next_offset == -1)
902 tokenlen = next_offset - offset;
904 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
905 tvb, offset, tokenlen, FALSE);
907 offset = next_offset + 1;
908 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
909 tvb, offset, -1, FALSE);
912 static void dissect_key_mgmt(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
914 gchar *prtcl_id = NULL;
916 tvbuff_t *keymgmt_tvb;
917 gboolean found_match = FALSE;
918 proto_tree *key_tree;
923 key_tree = proto_item_add_subtree(ti, ett_sdp_key_mgmt);
925 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
927 if (next_offset == -1)
930 tokenlen = next_offset - offset;
931 prtcl_id = tvb_get_ephemeral_string(tvb, offset, tokenlen);
933 proto_tree_add_item(key_tree, hf_key_mgmt_prtcl_id, tvb, offset, tokenlen, FALSE);
935 offset = next_offset + 1;
937 len = tvb_length_remaining(tvb, offset);
941 data = tvb_get_ephemeral_string(tvb, offset, len);
942 keymgmt_tvb = base64_to_tvb(tvb, data);
943 add_new_data_source(pinfo, keymgmt_tvb, "Key Management Data");
945 if ( prtcl_id != NULL && key_mgmt_dissector_table != NULL ) {
946 found_match = dissector_try_string(key_mgmt_dissector_table,
953 proto_item *ti = proto_tree_add_item(key_tree, hf_key_mgmt_data,
954 keymgmt_tvb, 0, -1, FALSE);
955 PROTO_ITEM_SET_HIDDEN(ti);
958 proto_tree_add_item(key_tree, hf_key_mgmt_data,
959 keymgmt_tvb, 0, -1, FALSE);
965 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
966 proto_tree *sdp_session_attribute_tree;
967 gint offset, next_offset, tokenlen;
974 sdp_session_attribute_tree = proto_item_add_subtree(ti,
975 ett_sdp_session_attribute);
977 next_offset = tvb_find_guint8(tvb,offset,-1,':');
979 if(next_offset == -1)
982 tokenlen = next_offset - offset;
984 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_field,
985 tvb, offset, tokenlen, FALSE);
987 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
989 offset = next_offset + 1;
991 if (strcmp((char*)field_name, "ipbcp") == 0) {
992 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"0123456789");
997 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
999 if (next_offset == -1)
1002 tokenlen = next_offset - offset;
1004 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_version,tvb,offset,tokenlen,FALSE);
1006 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
1011 tokenlen = tvb_find_line_end(tvb,offset,-1, &next_offset, FALSE);
1016 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE);
1017 } else if (strcmp((char*)field_name, "key-mgmt") == 0) {
1021 key_tvb = tvb_new_subset_remaining(tvb, offset);
1022 key_ti = proto_tree_add_item(sdp_session_attribute_tree, hf_key_mgmt_att_value, key_tvb, 0, -1, FALSE);
1024 dissect_key_mgmt(key_tvb, pinfo, key_ti);
1026 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value,
1027 tvb, offset, -1, FALSE);
1032 /* Dissect media description */
1034 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
1035 transport_info_t *transport_info){
1036 proto_tree *sdp_media_tree;
1037 gint offset, next_offset, tokenlen, index;
1038 guint8 *media_format;
1044 /* Re-initialise for a new media description */
1045 msrp_transport_address_set = FALSE;
1047 /* Create tree for media session */
1048 sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
1050 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1052 if(next_offset == -1)
1055 tokenlen = next_offset - offset;
1057 /* Type of media session */
1058 proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, offset, tokenlen,
1061 transport_info->media_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1063 offset = next_offset + 1;
1065 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1066 if(next_offset == -1)
1068 tokenlen = next_offset - offset;
1069 next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
1071 if(next_offset != -1){
1072 tokenlen = next_offset - offset;
1073 /* Save port info */
1074 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1076 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1077 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1078 offset = next_offset + 1;
1079 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1080 if(next_offset == -1)
1082 tokenlen = next_offset - offset;
1083 proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb, offset,
1085 offset = next_offset + 1;
1087 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1089 if(next_offset == -1)
1091 tokenlen = next_offset - offset;
1092 /* Save port info */
1093 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1095 /* XXX Remember Port */
1096 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1097 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1098 offset = next_offset + 1;
1101 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1103 if( next_offset == -1)
1106 tokenlen = next_offset - offset;
1107 /* Save port protocol */
1108 transport_info->media_proto[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1110 /* XXX Remember Protocol */
1111 proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb, offset, tokenlen,
1115 offset = next_offset + 1;
1116 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1118 if(next_offset == -1){
1119 tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
1121 break; /* Nothing more left */
1123 tokenlen = next_offset - offset;
1126 if (strcmp(transport_info->media_proto[transport_info->media_count],
1128 media_format = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1129 proto_tree_add_string(sdp_media_tree, hf_media_format, tvb, offset,
1130 tokenlen, val_to_str(atol((char*)media_format), rtp_payload_type_vals, "%u"));
1131 index = transport_info->media[transport_info->media_count].pt_count;
1132 transport_info->media[transport_info->media_count].pt[index] = atol((char*)media_format);
1133 if (index < (SDP_MAX_RTP_PAYLOAD_TYPES-1))
1134 transport_info->media[transport_info->media_count].pt_count++;
1136 proto_tree_add_item(sdp_media_tree, hf_media_format, tvb, offset,
1139 } while (next_offset != -1);
1141 /* Increase the count of media channels, but don't walk off the end
1143 if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
1144 transport_info->media_count++;
1147 /* XXX Dissect traffic to "Port" as "Protocol"
1148 * Remember this Port/Protocol pair so we can tear it down again later
1149 * Actually, it's harder than that:
1150 * We need to find out the address of the other side first and it
1151 * looks like that info can be found in SIP headers only.
1157 ascii_bytes_to_tvb(tvbuff_t *tvb, packet_info *pinfo, gint len, gchar *msg)
1159 guint8 *buf = g_malloc(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_child_real_data(tvb, buf,i,i);
1224 tvb_set_free_cb(bytes_tvb, g_free);
1225 add_new_data_source(pinfo, bytes_tvb, "ASCII bytes to tvb");
1231 /* Annex X Profiles and levels definition */
1232 static const value_string h263_profile_vals[] =
1234 { 0, "Baseline Profile" },
1235 { 1, "H.320 Coding Efficiency Version 2 Backward-Compatibility Profile" },
1236 { 2, "Version 1 Backward-Compatibility Profile" },
1237 { 3, "Version 2 Interactive and Streaming Wireless Profile" },
1238 { 4, "Version 3 Interactive and Streaming Wireless Profile" },
1239 { 5, "Conversational High Compression Profile" },
1240 { 6, "Conversational Internet Profile" },
1241 { 7, "Conversational Interlace Profile" },
1242 { 8, "High Latency Profile" },
1247 /* RFC 4629 The level are described in table X.2 of H.263 annex X */
1248 static const value_string h263_level_vals[] =
1250 { 10, "QCIF (176 x 144), 1 x 64Kb/s" },
1251 { 20, "CIF (352 x 288), 2 x 64Kb/s" },
1252 { 30, "CIF (352 x 288), 6 x 64Kb/s" },
1253 { 40, "CIF (352 x 288), 32 x 64Kb/s" },
1254 { 45, "QCIF (176 x144) support of CPFMT, 2 x 64Kb/s" },
1255 { 50, "CIF (352 x 288) support of CPFMT, 64 x 64Kb/s" },
1256 { 60, "CPFMT: 720 x 288 support of CPFMT, 128 x 64Kb/s" },
1257 { 70, "CPFMT: 720 x 576 support of CPFMT, 256 x 64Kb/s" },
1262 static const value_string h264_packetization_mode_vals[] =
1264 { 0, "Single NAL mode" },
1265 { 1, "Non-interleaved mode" },
1266 { 2, "Interleaved mode" },
1271 * TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
1274 decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint tokenlen, char *mime_type){
1278 gchar *format_specific_parameter;
1282 end_offset = offset + tokenlen;
1285 proto_tree_add_text(tree, tvb, offset, tokenlen, "Debug; Analysed string: '%s'",
1286 tvb_get_ephemeral_string(tvb, offset, tokenlen));
1289 /* Look for an '=' within this value - this may indicate that there is a
1290 profile-level-id parameter to find if the MPEG4 media type is in use */
1291 next_offset = tvb_find_guint8(tvb,offset,-1,'=');
1292 if (next_offset == -1)
1294 /* Give up (and avoid exception) if '=' not found */
1298 /* Find the name of the parameter */
1299 tokenlen = next_offset - offset;
1300 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1301 /*proto_tree_add_text(tree, tvb, offset, tokenlen, "Debug; MIMEtype '%s'Parameter name: '%s'", mime_type, field_name); */
1303 offset = next_offset;
1305 /* Dissect the MPEG4 profile-level-id parameter if present */
1306 if (mime_type != NULL && g_ascii_strcasecmp(mime_type, "MP4V-ES") == 0) {
1307 if (strcmp((char*)field_name, "profile-level-id") == 0) {
1309 tokenlen = end_offset - offset;
1310 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1311 item = proto_tree_add_uint(tree, hf_sdp_fmtp_mpeg4_profile_level_id, tvb, offset, tokenlen,
1312 atol((char*)format_specific_parameter));
1313 PROTO_ITEM_SET_GENERATED(item);
1314 }else if(strcmp((char*)field_name, "config") == 0) {
1315 /* String including "=" */
1316 tokenlen = end_offset - offset;
1317 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1318 /* ascii_bytes_to_tvb requires the "=" to be in the buffer */
1319 data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
1320 if(mp4ves_handle && data_tvb){
1321 dissect_mp4ves_config(data_tvb, pinfo, tree);
1326 /* Dissect the H263-2000 profile parameter if present */
1327 if ((mime_type != NULL && g_ascii_strcasecmp(mime_type, "H263-2000") == 0)||(mime_type != NULL && g_ascii_strcasecmp(mime_type, "H263-1998") == 0)) {
1328 if (strcmp((char*)field_name, "profile") == 0) {
1330 tokenlen = end_offset - offset;
1331 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1332 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_profile, tvb, offset, tokenlen,
1333 atol((char*)format_specific_parameter));
1334 PROTO_ITEM_SET_GENERATED(item);
1335 }else if(strcmp((char*)field_name, "level") == 0) {
1337 tokenlen = end_offset - offset;
1338 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1339 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_level, tvb, offset, tokenlen,
1340 atol((char*)format_specific_parameter));
1341 PROTO_ITEM_SET_GENERATED(item);
1346 /* Dissect the H264 profile-level-id parameter
1348 * A base16 [6] (hexadecimal) representation of
1349 * the following three bytes in the sequence
1350 * parameter set NAL unit specified in [1]: 1)
1351 * profile_idc, 2) a byte herein referred to as
1352 * profile-iop, composed of the values of
1353 * constraint_set0_flag, constraint_set1_flag,
1354 * constraint_set2_flag, and reserved_zero_5bits
1355 * in bit-significance order, starting from the
1356 * most significant bit, and 3) level_idc.
1358 if (mime_type != NULL && g_ascii_strcasecmp(mime_type, "H264") == 0) {
1359 if (strcmp(field_name, "profile-level-id") == 0) {
1362 /* Length includes "=" as it's required by ascii_bytes_to_tvb()*/
1363 tokenlen = end_offset - offset;
1364 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1365 data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
1366 length = tvb_length(data_tvb);
1368 if(h264_handle && data_tvb){
1369 dissect_h264_profile(data_tvb, pinfo, tree);
1372 item = proto_tree_add_text(tree, tvb, offset, tokenlen, "Incorrectly coded, must be three bytes");
1373 PROTO_ITEM_SET_GENERATED(item);
1375 }else if (strcmp(field_name, "packetization-mode") == 0) {
1377 tokenlen = end_offset - offset;
1378 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1379 item = proto_tree_add_uint(tree, hf_sdp_h264_packetization_mode, tvb, offset, tokenlen,
1380 atol((char*)format_specific_parameter));
1381 PROTO_ITEM_SET_GENERATED(item);
1383 }else if (strcmp(field_name, "sprop-parameter-sets") == 0) {
1384 /* The value of the parameter is the
1385 base64 [6] representation of the initial
1386 parameter set NAL units as specified in
1387 sections 7.3.2.1 and 7.3.2.2 of [1]. The
1388 parameter sets are conveyed in decoding order,
1389 and no framing of the parameter set NAL units
1390 takes place. A comma is used to separate any
1391 pair of parameter sets in the list.
1399 comma_offset = tvb_find_guint8(tvb,offset,-1,',');
1400 if (comma_offset != -1){
1401 tokenlen = comma_offset - offset;
1403 tokenlen = end_offset - offset;
1406 data = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1407 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 1 string: %s", data);
1409 /* proto_tree_add_text(tree, tvb, offset, tokenlen, "String %s",data); */
1410 data_tvb = base64_to_tvb(tvb, data);
1411 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets");
1413 if(h264_handle && data_tvb){
1414 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1415 if (comma_offset != -1){
1416 /* Second NAL unit */
1417 offset = comma_offset +1;
1418 tokenlen = end_offset - offset;
1419 data = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1420 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 2 string: %s", data);
1421 data_tvb = base64_to_tvb(tvb, data);
1422 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets 2");
1423 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1435 #define SDP_RTPMAP 1
1438 #define SDP_H248_ITEM 4
1440 static const sdp_names_t sdp_media_attribute_names[] = {
1441 { "Unknown-name"}, /* 0 Pad so that the real headers start at index 1 */
1442 { "rtpmap"}, /* 1 */
1445 { "h248item"}, /* 4 */
1448 static gint find_sdp_media_attribute_names(tvbuff_t *tvb, int offset, guint len)
1452 for (i = 1; i < array_length(sdp_media_attribute_names); i++) {
1453 if (len == strlen(sdp_media_attribute_names[i].name) &&
1454 tvb_strncaseeql(tvb, offset, sdp_media_attribute_names[i].name, len) == 0)
1461 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item * ti, transport_info_t *transport_info){
1462 proto_tree *sdp_media_attribute_tree;
1463 proto_item *fmtp_item, *media_format_item;
1464 proto_tree *fmtp_tree;
1465 gint offset, next_offset, tokenlen, n, colon_offset;
1467 guint8 *payload_type;
1468 guint8 *attribute_value;
1471 gint sdp_media_attrbute_code;
1472 const char *msrp_res = "msrp://";
1473 const char *h324ext_h223lcparm = "h324ext/h223lcparm";
1474 gboolean has_more_pars = TRUE;
1481 /* Create attribute tree */
1482 sdp_media_attribute_tree = proto_item_add_subtree(ti,
1483 ett_sdp_media_attribute);
1484 /* Find end of field */
1485 colon_offset = tvb_find_guint8(tvb,offset,-1,':');
1487 if(colon_offset == -1)
1490 /* Attribute field name is token before ':' */
1491 tokenlen = colon_offset - offset;
1492 proto_tree_add_item(sdp_media_attribute_tree,
1493 hf_media_attribute_field,
1494 tvb, offset, tokenlen, FALSE);
1495 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1496 sdp_media_attrbute_code = find_sdp_media_attribute_names(tvb, offset, tokenlen);
1499 offset = colon_offset + 1;
1500 /* skip leading wsp */
1501 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1503 /* Value is the remainder of the line */
1504 attribute_value = tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
1508 /*********************************************/
1509 /* Special parsing for some field name types */
1511 switch (sdp_media_attrbute_code){
1513 /* decode the rtpmap to see if it is DynamicPayload to dissect them automatic */
1514 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1516 if(next_offset == -1)
1519 tokenlen = next_offset - offset;
1521 proto_tree_add_item(sdp_media_attribute_tree, hf_media_format, tvb,
1522 offset, tokenlen, FALSE);
1524 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1526 offset = next_offset + 1;
1528 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
1530 if(next_offset == -1){
1534 tokenlen = next_offset - offset;
1536 proto_tree_add_item(sdp_media_attribute_tree, hf_media_encoding_name, tvb,
1537 offset, tokenlen, FALSE);
1539 key=g_malloc( sizeof(gint) );
1540 *key=atol((char*)payload_type);
1541 pt = atoi((char*)payload_type);
1542 if (pt >= SDP_NO_OF_PT) {
1543 return; /* Invalid */
1545 transport_info->encoding_name[pt] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1548 offset = next_offset + 1;
1549 tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
1551 tokenlen = next_offset - offset;
1552 proto_tree_add_item(sdp_media_attribute_tree, hf_media_sample_rate, tvb,
1553 offset, tokenlen, FALSE);
1554 /* As per RFC2327 it is possible to have multiple Media Descriptions ("m=").
1557 a=rtpmap:101 G726-32/8000
1558 m=audio 49170 RTP/AVP 0 97
1559 a=rtpmap:97 telephone-event/8000
1560 m=audio 49172 RTP/AVP 97 101
1561 a=rtpmap:97 G726-24/8000
1563 The Media attributes ("a="s) after the "m=" only apply for that "m=".
1564 If there is an "a=" before the first "m=", that attribute applies for
1565 all the session (all the "m="s).
1568 /* so, if this "a=" appear before any "m=", we add it to all the dynamic
1571 if (transport_info->media_count == 0) {
1572 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++) {
1574 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1575 key, g_strdup(transport_info->encoding_name[pt]));
1576 else { /* we create a new key and encoding_name to assign to the other hash tables */
1578 key2=g_malloc( sizeof(gint) );
1579 *key2=atol((char*)payload_type);
1580 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1581 key2, g_strdup(transport_info->encoding_name[pt]));
1585 /* if the "a=" is after an "m=", only apply to this "m=" */
1587 /* in case there is an overflow in SDP_MAX_RTP_CHANNELS, we keep always the last "m=" */
1588 if (transport_info->media_count == SDP_MAX_RTP_CHANNELS-1)
1589 g_hash_table_insert(transport_info->media[ transport_info->media_count ].rtp_dyn_payload,
1590 key, g_strdup(transport_info->encoding_name[pt]));
1592 g_hash_table_insert(transport_info->media[ transport_info->media_count-1 ].rtp_dyn_payload,
1593 key, g_strdup(transport_info->encoding_name[pt]));
1596 if(sdp_media_attribute_tree){
1597 guint8 media_format;
1598 /* Reading the Format parameter(fmtp) */
1599 /* Skip leading space, if any */
1600 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1601 /* Media format extends to the next space */
1602 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1604 if(next_offset == -1)
1607 tokenlen = next_offset - offset;
1610 media_format_item = proto_tree_add_item(sdp_media_attribute_tree,
1611 hf_media_format, tvb, offset,
1613 media_format = atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen));
1614 if (media_format >= SDP_NO_OF_PT) {
1615 return; /* Invalid */
1618 /* Append encoding name to format if known */
1619 proto_item_append_text(media_format_item, " [%s]",
1620 transport_info->encoding_name[media_format]);
1622 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1623 /* Move offset past the payload type */
1624 offset = next_offset + 1;
1626 while(has_more_pars==TRUE){
1627 next_offset = tvb_find_guint8(tvb,offset,-1,';');
1628 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1630 if(next_offset == -1){
1631 has_more_pars = FALSE;
1632 next_offset= tvb_length(tvb);
1637 /* There are at least 2 - add the first parameter */
1638 tokenlen = next_offset - offset;
1639 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1640 hf_media_format_specific_parameter, tvb,
1641 offset, tokenlen, FALSE);
1643 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1645 decode_sdp_fmtp(fmtp_tree, tvb, pinfo, offset, tokenlen,
1646 transport_info->encoding_name[media_format]);
1648 /* Move offset past "; " and onto firts char */
1649 offset = next_offset + 1;
1654 /* msrp attributes that contain address needed for conversation */
1655 if (strncmp((char*)attribute_value, msrp_res, strlen(msrp_res)) == 0){
1656 int address_offset, port_offset, port_end_offset;
1658 /* Address starts here */
1659 address_offset = offset + (int)strlen(msrp_res);
1661 /* Port is after next ':' */
1662 port_offset = tvb_find_guint8(tvb, address_offset, -1, ':');
1664 /* Port ends with '/' */
1665 port_end_offset = tvb_find_guint8(tvb, port_offset, -1, '/');
1667 /* Attempt to convert address */
1668 if (inet_pton(AF_INET, (char*)tvb_get_ephemeral_string(tvb, address_offset, port_offset-address_offset), &msrp_ipaddr) > 0) {
1669 /* Get port number */
1670 msrp_port_number = atoi((char*)tvb_get_ephemeral_string(tvb, port_offset+1, port_end_offset-port_offset-1));
1671 /* Set flag so this info can be used */
1672 msrp_transport_address_set = TRUE;
1677 /* Decode h248 item ITU-T Rec. H.248.12 (2001)/Amd.1 (11/2002)*/
1678 if (strncmp((char*)attribute_value, h324ext_h223lcparm, strlen(msrp_res)) == 0){
1679 /* A.5.1.3 H.223 Logical channel parameters
1680 * This property indicates the H.245
1681 * H223LogicalChannelsParameters structure encoded by applying the PER specified in
1682 * ITU-T Rec. X.691. Value encoded as per A.5.1.2. For text encoding the mechanism defined
1683 * in ITU-T Rec. H.248.15 is used.
1688 len = (gint)strlen(attribute_value);
1689 h245_tvb = ascii_bytes_to_tvb(tvb, pinfo, len, attribute_value);
1690 /* arbitrary maximum length */
1691 /* should go through a handle, however, the two h245 entry
1692 points are different, one is over tpkt and the other is raw
1695 asn1_ctx_init(&actx, ASN1_ENC_PER, TRUE, pinfo);
1696 dissect_h245_H223LogicalChannelParameters(h245_tvb, 0, &actx, sdp_media_attribute_tree, hf_SDPh223LogicalChannelParameters);
1701 /* No special treatment for values of this attribute type, just add as one item. */
1702 proto_tree_add_item(sdp_media_attribute_tree, hf_media_attribute_value,
1703 tvb, offset, -1, FALSE);
1709 proto_register_sdp(void)
1711 static hf_register_info hf[] = {
1712 { &hf_protocol_version,
1713 { "Session Description Protocol Version (v)",
1714 "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
1717 { "Owner/Creator, Session Id (o)",
1718 "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
1721 { "Session Name (s)",
1722 "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
1725 { "Session Information (i)",
1726 "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
1729 { "URI of Description (u)",
1730 "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
1733 { "E-mail Address (e)",
1734 "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
1735 "E-mail Address", HFILL }},
1737 { "Phone Number (p)",
1738 "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
1740 { &hf_connection_info,
1741 { "Connection Information (c)",
1742 "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
1745 { "Bandwidth Information (b)",
1746 "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
1749 { "Time Zone Adjustments (z)",
1750 "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
1752 { &hf_encryption_key,
1753 { "Encryption Key (k)",
1754 "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
1756 { &hf_session_attribute,
1757 { "Session Attribute (a)",
1758 "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1760 { &hf_media_attribute,
1761 { "Media Attribute (a)",
1762 "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1765 { "Time Description, active time (t)",
1766 "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
1769 { "Repeat Time (r)",
1770 "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
1773 { "Media Description, name and address (m)",
1774 "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
1777 { "Media Title (i)",
1778 "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
1779 "Media Title", HFILL }},
1782 "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
1786 "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
1788 { &hf_owner_username,
1790 "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
1792 { &hf_owner_sessionid,
1794 "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
1796 { &hf_owner_version,
1797 { "Session Version",
1798 "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
1800 { &hf_owner_network_type,
1801 { "Owner Network Type",
1802 "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1804 { &hf_owner_address_type,
1805 { "Owner Address Type",
1806 "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1808 { &hf_owner_address,
1810 "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
1812 { &hf_connection_info_network_type,
1813 { "Connection Network Type",
1814 "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1816 { &hf_connection_info_address_type,
1817 { "Connection Address Type",
1818 "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1820 { &hf_connection_info_connection_address,
1821 { "Connection Address",
1822 "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
1824 { &hf_connection_info_ttl,
1826 "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
1828 { &hf_connection_info_num_addr,
1829 { "Connection Number of Addresses",
1830 "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
1832 { &hf_bandwidth_modifier,
1833 { "Bandwidth Modifier",
1834 "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
1836 { &hf_bandwidth_value,
1837 { "Bandwidth Value",
1838 "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
1839 "Bandwidth Value (in kbits/s)", HFILL }},
1841 { "Session Start Time",
1842 "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
1845 { "Session Stop Time",
1846 "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
1848 { &hf_repeat_time_interval,
1849 { "Repeat Interval",
1850 "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
1852 { &hf_repeat_time_duration,
1853 { "Repeat Duration",
1854 "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
1856 { &hf_repeat_time_offset,
1858 "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1860 { &hf_timezone_time,
1862 "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
1864 { &hf_timezone_offset,
1865 { "Timezone Offset",
1866 "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1868 { &hf_encryption_key_type,
1870 "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
1872 { &hf_encryption_key_data,
1874 "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
1876 { &hf_session_attribute_field,
1877 { "Session Attribute Fieldname",
1878 "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
1880 { &hf_session_attribute_value,
1881 { "Session Attribute Value",
1882 "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
1886 "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
1890 "sdp.media.port",FT_UINT16, BASE_DEC, NULL, 0x0,
1892 { &hf_media_portcount,
1893 { "Media Port Count",
1894 "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
1898 "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
1902 "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
1904 { &hf_media_attribute_field,
1905 { "Media Attribute Fieldname",
1906 "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
1908 { &hf_media_attribute_value,
1909 { "Media Attribute Value",
1910 "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
1912 { &hf_media_encoding_name,
1914 "sdp.mime.type",FT_STRING, BASE_NONE, NULL, 0x0,
1915 "SDP MIME Type", HFILL }},
1916 { &hf_media_sample_rate,
1918 "sdp.sample_rate",FT_STRING, BASE_NONE, NULL, 0x0,
1920 { &hf_media_format_specific_parameter,
1921 { "Media format specific parameters",
1922 "sdp.fmtp.parameter",FT_STRING, BASE_NONE, NULL, 0x0,
1923 "Format specific parameter(fmtp)", HFILL }},
1924 { &hf_ipbcp_version,
1925 { "IPBCP Protocol Version",
1926 "ipbcp.version",FT_STRING, BASE_NONE, NULL, 0x0,
1929 { "IPBCP Command Type",
1930 "ipbcp.command",FT_STRING, BASE_NONE, NULL, 0x0,
1932 {&hf_sdp_fmtp_mpeg4_profile_level_id,
1934 "sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mp4ves_level_indication_vals), 0x0,
1936 { &hf_sdp_fmtp_h263_profile,
1938 "sdp.fmtp.h263profile",FT_UINT32, BASE_DEC,VALS(h263_profile_vals), 0x0,
1940 { &hf_sdp_fmtp_h263_level,
1942 "sdp.fmtp.h263level",FT_UINT32, BASE_DEC,VALS(h263_level_vals), 0x0,
1944 { &hf_sdp_h264_packetization_mode,
1945 { "Packetization mode",
1946 "sdp.fmtp.h264_packetization_mode",FT_UINT32, BASE_DEC,VALS(h264_packetization_mode_vals), 0x0,
1948 { &hf_sdp_h264_sprop_parameter_sets,
1949 { "Sprop_parameter_sets",
1950 "sdp.h264.sprop_parameter_sets", FT_BYTES, BASE_NONE, NULL, 0x0,
1952 { &hf_SDPh223LogicalChannelParameters,
1953 { "h223LogicalChannelParameters", "sdp.h223LogicalChannelParameters",
1954 FT_NONE, BASE_NONE, NULL, 0,
1956 { &hf_key_mgmt_att_value,
1958 "sdp.key_mgmt", FT_STRING, BASE_NONE, NULL, 0x0,
1960 { &hf_key_mgmt_prtcl_id,
1961 { "Key Management Protocol (kmpid)",
1962 "sdp.key_mgmt.kmpid", FT_STRING, BASE_NONE, NULL, 0x0,
1964 { &hf_key_mgmt_data,
1965 { "Key Management Data",
1966 "sdp.key_mgmt.data", FT_BYTES, BASE_NONE, NULL, 0x0,
1969 static gint *ett[] = {
1972 &ett_sdp_connection_info,
1975 &ett_sdp_repeat_time,
1977 &ett_sdp_encryption_key,
1978 &ett_sdp_session_attribute,
1980 &ett_sdp_media_attribute,
1985 module_t *sdp_module;
1987 proto_sdp = proto_register_protocol("Session Description Protocol",
1989 proto_register_field_array(proto_sdp, hf, array_length(hf));
1990 proto_register_subtree_array(ett, array_length(ett));
1992 key_mgmt_dissector_table = register_dissector_table("key_mgmt",
1993 "Key Management", FT_STRING, BASE_NONE);
1996 * Preferences registration
1998 sdp_module = prefs_register_protocol(proto_sdp, NULL);
1999 prefs_register_bool_preference(sdp_module, "establish_conversation",
2000 "Establish Media Conversation",
2001 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
2002 "upon port numbers found in SDP payload",
2003 &global_sdp_establish_conversation);
2006 * Register the dissector by name, so other dissectors can
2007 * grab it by name rather than just referring to it directly.
2009 register_dissector("sdp", dissect_sdp, proto_sdp);
2011 /* Register for tapping */
2012 sdp_tap = register_tap("sdp");
2016 proto_reg_handoff_sdp(void)
2018 dissector_handle_t sdp_handle;
2020 rtp_handle = find_dissector("rtp");
2021 rtcp_handle = find_dissector("rtcp");
2022 msrp_handle = find_dissector("msrp");
2023 t38_handle = find_dissector("t38");
2024 h264_handle = find_dissector("h264");
2025 mp4ves_handle = find_dissector("mp4ves");
2027 sdp_handle = find_dissector("sdp");
2028 dissector_add_string("media_type", "application/sdp", sdp_handle);
2029 dissector_add("bctp.tpi", 0x20, sdp_handle);