2 * Routines for SDP packet disassembly (RFC 2327)
4 * Jason Lango <jal@netapp.com>
5 * Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Ref http://www.ietf.org/rfc/rfc4566.txt?number=4566
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
45 #ifdef HAVE_WINSOCK2_H
46 #include <winsock2.h> /* needed to define AF_ values on Windows */
49 #ifdef NEED_INET_V6DEFS_H
50 # include "inet_v6defs.h"
54 #include <epan/packet.h>
55 #include <epan/conversation.h>
56 #include <epan/strutil.h>
57 #include <epan/emem.h>
58 #include <epan/base64.h>
59 #include <epan/asn1.h>
62 #include "packet-sdp.h"
64 #include "packet-rtp.h"
65 #include <epan/rtp_pt.h>
67 #include <epan/prefs.h>
68 #include <epan/expert.h>
70 #include "packet-rtcp.h"
71 #include "packet-t38.h"
72 #include "packet-msrp.h"
73 #include "packet-per.h"
74 #include "packet-h245.h"
75 #include "packet-h264.h"
77 static dissector_handle_t rtp_handle=NULL;
78 static dissector_handle_t rtcp_handle=NULL;
79 static dissector_handle_t t38_handle=NULL;
80 static dissector_handle_t msrp_handle=NULL;
81 static dissector_handle_t h264_handle = NULL;
83 static int sdp_tap = -1;
85 static int proto_sdp = -1;
87 /* preference globals */
88 static gboolean global_sdp_establish_conversation = TRUE;
90 /* Top level fields */
91 static int hf_protocol_version = -1;
92 static int hf_owner = -1;
93 static int hf_session_name = -1;
94 static int hf_session_info = -1;
95 static int hf_uri = -1;
96 static int hf_email = -1;
97 static int hf_phone = -1;
98 static int hf_connection_info = -1;
99 static int hf_bandwidth = -1;
100 static int hf_timezone = -1;
101 static int hf_encryption_key = -1;
102 static int hf_session_attribute = -1;
103 static int hf_media_attribute = -1;
104 static int hf_time = -1;
105 static int hf_repeat_time = -1;
106 static int hf_media = -1;
107 static int hf_media_title = -1;
108 static int hf_unknown = -1;
109 static int hf_invalid = -1;
110 static int hf_ipbcp_version = -1;
111 static int hf_ipbcp_type = -1;
113 /* hf_owner subfields*/
114 static int hf_owner_username = -1;
115 static int hf_owner_sessionid = -1;
116 static int hf_owner_version = -1;
117 static int hf_owner_network_type = -1;
118 static int hf_owner_address_type = -1;
119 static int hf_owner_address = -1;
121 /* hf_connection_info subfields */
122 static int hf_connection_info_network_type = -1;
123 static int hf_connection_info_address_type = -1;
124 static int hf_connection_info_connection_address = -1;
125 static int hf_connection_info_ttl = -1;
126 static int hf_connection_info_num_addr = -1;
128 /* hf_bandwidth subfields */
129 static int hf_bandwidth_modifier = -1;
130 static int hf_bandwidth_value = -1;
132 /* hf_time subfields */
133 static int hf_time_start = -1;
134 static int hf_time_stop = -1;
136 /* hf_repeat_time subfield */
137 static int hf_repeat_time_interval = -1;
138 static int hf_repeat_time_duration = -1;
139 static int hf_repeat_time_offset = -1;
141 /* hf_timezone subfields */
142 static int hf_timezone_time = -1;
143 static int hf_timezone_offset = -1;
145 /* hf_encryption_key subfields */
146 static int hf_encryption_key_type = -1;
147 static int hf_encryption_key_data = -1;
149 /* hf_session_attribute subfields */
150 static int hf_session_attribute_field = -1;
151 static int hf_session_attribute_value = -1;
153 /* hf_media subfields */
154 static int hf_media_media = -1;
155 static int hf_media_port = -1;
156 static int hf_media_portcount = -1;
157 static int hf_media_proto = -1;
158 static int hf_media_format = -1;
160 /* hf_session_attribute subfields */
161 static int hf_media_attribute_field = -1;
162 static int hf_media_attribute_value = -1;
163 static int hf_media_encoding_name = -1;
164 static int hf_media_format_specific_parameter = -1;
165 static int hf_sdp_fmtp_mpeg4_profile_level_id = -1;
166 static int hf_sdp_fmtp_h263_profile = -1;
167 static int hf_sdp_h264_packetization_mode = -1;
168 static int hf_sdp_h264_sprop_parameter_sets = -1;
169 static int hf_SDPh223LogicalChannelParameters = -1;
171 /* hf_session_attribute hf_media_attribute subfields */
172 static int hf_key_mgmt_att_value = -1;
173 static int hf_key_mgmt_prtcl_id = -1;
174 static int hf_key_mgmt_data = -1;
177 static int ett_sdp = -1;
178 static int ett_sdp_owner = -1;
179 static int ett_sdp_connection_info = -1;
180 static int ett_sdp_bandwidth = -1;
181 static int ett_sdp_time = -1;
182 static int ett_sdp_repeat_time = -1;
183 static int ett_sdp_timezone = -1;
184 static int ett_sdp_encryption_key = -1;
185 static int ett_sdp_session_attribute = -1;
186 static int ett_sdp_media = -1;
187 static int ett_sdp_media_attribute = -1;
188 static int ett_sdp_fmtp = -1;
189 static int ett_sdp_key_mgmt = -1;
192 #define SDP_MAX_RTP_CHANNELS 4
193 #define SDP_MAX_RTP_PAYLOAD_TYPES 20
196 gint32 pt[SDP_MAX_RTP_PAYLOAD_TYPES];
198 GHashTable *rtp_dyn_payload;
199 } transport_media_pt_t;
202 char *connection_address;
203 char *connection_type;
205 char *media_port[SDP_MAX_RTP_CHANNELS];
206 char *media_proto[SDP_MAX_RTP_CHANNELS];
207 transport_media_pt_t media[SDP_MAX_RTP_CHANNELS];
212 /* MSRP transport info (as set while parsing path attribute) */
213 static gboolean msrp_transport_address_set = FALSE;
214 static guint32 msrp_ipaddr[4];
215 static guint16 msrp_port_number;
217 /* key-mgmt dissector
219 * http://www.iana.org/assignments/sdp-parameters
221 static dissector_table_t key_mgmt_dissector_table;
224 /* Protocol registration */
225 void proto_register_sdp(void);
226 void proto_reg_handoff_sdp(void);
229 /* static functions */
231 static void call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti,
232 transport_info_t *transport_info);
234 /* Subdissector functions */
235 static void dissect_sdp_owner(tvbuff_t *tvb, proto_item* ti);
236 static void dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
237 transport_info_t *transport_info);
238 static void dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti);
239 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti);
240 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti);
241 static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti);
242 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti);
243 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti);
244 static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
245 transport_info_t *transport_info);
246 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti, transport_info_t *transport_info);
249 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
251 proto_tree *sdp_tree;
252 proto_item *ti, *sub_ti;
256 gboolean in_media_description;
266 transport_info_t transport_info;
269 gboolean is_rtp=FALSE;
270 gboolean is_srtp=FALSE;
271 gboolean is_t38=FALSE;
272 gboolean is_msrp=FALSE;
273 gboolean set_rtp=FALSE;
274 gboolean is_ipv4_addr=FALSE;
275 gboolean is_ipv6_addr=FALSE;
278 sdp_packet_info *sdp_pi;
280 /* Initialise packet info for passing to tap */
281 sdp_pi = ep_alloc(sizeof(sdp_packet_info));
282 sdp_pi->summary_str[0] = '\0';
284 /* Initialise RTP channel info */
285 transport_info.connection_address=NULL;
286 transport_info.connection_type=NULL;
287 transport_info.encoding_name=NULL;
288 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++)
290 transport_info.media_port[n]=NULL;
291 transport_info.media_proto[n]=NULL;
292 transport_info.media[n].pt_count = 0;
293 transport_info.media[n].rtp_dyn_payload = g_hash_table_new_full( g_int_hash,
294 g_int_equal, g_free, g_free);
296 transport_info.media_count = 0;
299 * As RFC 2327 says, "SDP is purely a format for session
300 * description - it does not incorporate a transport protocol,
301 * and is intended to use different transport protocols as
302 * appropriate including the Session Announcement Protocol,
303 * Session Initiation Protocol, Real-Time Streaming Protocol,
304 * electronic mail using the MIME extensions, and the
305 * Hypertext Transport Protocol."
307 * We therefore don't set the protocol or info columns;
308 * instead, we append to them, so that we don't erase
309 * what the protocol inside which the SDP stuff resides
312 if (check_col(pinfo->cinfo, COL_PROTOCOL))
313 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
315 if (check_col(pinfo->cinfo, COL_INFO)) {
316 /* XXX: Needs description. */
317 col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
320 ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
321 sdp_tree = proto_item_add_subtree(ti, ett_sdp);
324 * Show the SDP message a line at a time.
326 in_media_description = FALSE;
328 while (tvb_reported_length_remaining(tvb, offset) > 0) {
330 * Find the end of the line.
332 linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
337 * Line must contain at least e.g. "v=".
342 type = tvb_get_guint8(tvb,offset);
343 delim = tvb_get_guint8(tvb,offset + 1);
345 proto_item *ti = proto_tree_add_item(sdp_tree, hf_invalid, tvb, offset, linelen, FALSE);
346 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_NOTE,
347 "Invalid SDP line (no '=' delimiter)");
348 offset = next_offset;
357 hf = hf_protocol_version;
363 hf = hf_session_name;
366 if (in_media_description) {
370 hf = hf_session_info;
383 hf = hf_connection_info;
396 in_media_description = TRUE;
399 hf = hf_encryption_key;
402 if (in_media_description) {
403 hf = hf_media_attribute;
406 hf = hf_session_attribute;
417 if (hf == hf_unknown)
419 string = (char*)tvb_get_ephemeral_string(tvb, offset + tokenoffset,
420 linelen - tokenoffset);
421 sub_ti = proto_tree_add_string(sdp_tree, hf, tvb, offset, linelen,
423 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
425 linelen-tokenoffset),
427 hf,sub_ti,&transport_info),
428 offset = next_offset;
432 /* Now look, if we have strings collected.
433 * Try to convert ipv4 addresses and ports into binary format,
434 * so we can use them to detect rtp and rtcp streams.
435 * Don't forget to free the strings!
438 for (n = 0; n < transport_info.media_count; n++)
440 if(transport_info.media_port[n]!=NULL) {
441 port = atol(transport_info.media_port[n]);
443 if(transport_info.media_proto[n]!=NULL) {
444 /* Check if media protocol is RTP
445 * and stream decoding is enabled in preferences
447 if(global_sdp_establish_conversation){
448 /* Check if media protocol is RTP */
449 is_rtp = (strcmp(transport_info.media_proto[n],"RTP/AVP")==0);
450 /* Check if media protocol is SRTP */
451 is_srtp = (strcmp(transport_info.media_proto[n],"RTP/SAVP")==0);
452 /* Check if media protocol is T38 */
453 is_t38 = ( (strcmp(transport_info.media_proto[n],"UDPTL")==0) || (strcmp(transport_info.media_proto[n],"udptl")==0) );
454 /* Check if media protocol is MSRP/TCP */
455 is_msrp = (strcmp(transport_info.media_proto[n],"msrp/tcp")==0);
460 if(transport_info.connection_address!=NULL) {
461 if(transport_info.connection_type!=NULL) {
462 if (strcmp(transport_info.connection_type,"IP4")==0) {
463 if(inet_pton(AF_INET,transport_info.connection_address, &ipaddr)==1 ) {
464 /* connection_address could be converted to a valid ipv4 address*/
466 src_addr.type=AT_IPv4;
470 else if (strcmp(transport_info.connection_type,"IP6")==0){
471 if (inet_pton(AF_INET6, transport_info.connection_address, &ipaddr)==1){
472 /* connection_address could be converted to a valid ipv6 address*/
474 src_addr.type=AT_IPv6;
481 /* Add (s)rtp and (s)rtcp conversation, if available (overrides t38 if conversation already set) */
482 if((!pinfo->fd->flags.visited) && port!=0 && (is_rtp||is_srtp) && (is_ipv4_addr || is_ipv6_addr)){
483 src_addr.data=(guint8*)&ipaddr;
486 struct srtp_info *dummy_srtp_info = se_alloc0(sizeof(struct srtp_info));
487 srtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num,
488 transport_info.media[n].rtp_dyn_payload, dummy_srtp_info);
490 rtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num,
491 transport_info.media[n].rtp_dyn_payload);
497 rtcp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
501 /* Add t38 conversation, if available and only if no rtp */
502 if((!pinfo->fd->flags.visited) && port!=0 && !set_rtp && is_t38 && is_ipv4_addr){
503 src_addr.data=(guint8*)&ipaddr;
505 t38_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
509 /* Add MSRP conversation. Uses addresses discovered in attribute
510 rather than connection information of media session line */
512 if ((!pinfo->fd->flags.visited) && msrp_transport_address_set){
514 src_addr.type=AT_IPv4;
516 src_addr.data=(guint8*)&msrp_ipaddr;
517 msrp_add_address(pinfo, &src_addr, msrp_port_number, "SDP", pinfo->fd->num);
522 /* Create the RTP summary str for the Voip Call analysis */
523 for (i = 0; i < transport_info.media[n].pt_count; i++)
525 /* if the payload type is dynamic (96 to 127), check the hash table to add the desc in the SDP summary */
526 if ( (transport_info.media[n].pt[i] >=96) && (transport_info.media[n].pt[i] <=127) ) {
527 gchar *str_dyn_pt = g_hash_table_lookup(transport_info.media[n].rtp_dyn_payload, &transport_info.media[n].pt[i]);
529 g_snprintf(sdp_pi->summary_str, 50, "%s %s", sdp_pi->summary_str, str_dyn_pt);
531 g_snprintf(sdp_pi->summary_str, 50, "%s %d", sdp_pi->summary_str, transport_info.media[n].pt[i]);
533 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"));
536 /* Free the hash table if we did't assigned it to a conv use it */
537 if (set_rtp == FALSE)
538 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
540 /* Create the T38 summary str for the Voip Call analysis */
541 if (is_t38) g_snprintf(sdp_pi->summary_str, 50, "%s t38", sdp_pi->summary_str);
544 /* Free the remainded hash tables not used */
545 for (n = transport_info.media_count; n < SDP_MAX_RTP_CHANNELS; n++)
547 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
551 datalen = tvb_length_remaining(tvb, offset);
553 proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)",
557 /* Report this packet to the tap */
558 tap_queue_packet(sdp_tap, pinfo, sdp_pi);
562 call_sdp_subdissector(tvbuff_t *tvb, packet_info *pinfo, int hf, proto_tree* ti, transport_info_t *transport_info){
564 dissect_sdp_owner(tvb,ti);
565 } else if ( hf == hf_connection_info) {
566 dissect_sdp_connection_info(tvb,ti,transport_info);
567 } else if ( hf == hf_bandwidth) {
568 dissect_sdp_bandwidth(tvb,ti);
569 } else if ( hf == hf_time) {
570 dissect_sdp_time(tvb,ti);
571 } else if ( hf == hf_repeat_time ){
572 dissect_sdp_repeat_time(tvb,ti);
573 } else if ( hf == hf_timezone ) {
574 dissect_sdp_timezone(tvb,ti);
575 } else if ( hf == hf_encryption_key ) {
576 dissect_sdp_encryption_key(tvb,ti);
577 } else if ( hf == hf_session_attribute ){
578 dissect_sdp_session_attribute(tvb,pinfo,ti);
579 } else if ( hf == hf_media ) {
580 dissect_sdp_media(tvb,ti,transport_info);
581 } else if ( hf == hf_media_attribute ){
582 dissect_sdp_media_attribute(tvb,pinfo,ti,transport_info);
587 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
588 proto_tree *sdp_owner_tree;
589 gint offset,next_offset,tokenlen;
595 sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
597 /* Find the username */
598 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
599 if( next_offset == -1 )
601 tokenlen = next_offset - offset;
603 proto_tree_add_item(sdp_owner_tree, hf_owner_username, tvb, offset, tokenlen,
605 offset = next_offset + 1;
607 /* Find the session id */
608 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
609 if( next_offset == -1 )
611 tokenlen = next_offset - offset;
613 proto_tree_add_item(sdp_owner_tree, hf_owner_sessionid, tvb, offset,
615 offset = next_offset + 1;
617 /* Find the version */
618 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
619 if( next_offset == -1 )
621 tokenlen = next_offset - offset;
623 proto_tree_add_item(sdp_owner_tree, hf_owner_version, tvb, offset, tokenlen,
625 offset = next_offset + 1;
627 /* Find the network type */
628 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
629 if( next_offset == -1 )
631 tokenlen = next_offset - offset;
633 proto_tree_add_item(sdp_owner_tree, hf_owner_network_type, tvb, offset,
635 offset = next_offset + 1;
637 /* Find the address type */
638 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
639 if( next_offset == -1 )
641 tokenlen = next_offset - offset;
643 proto_tree_add_item(sdp_owner_tree, hf_owner_address_type, tvb, offset,
645 offset = next_offset + 1;
647 /* Find the address */
648 proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
652 * XXX - this can leak memory if an exception is thrown after we've fetched
656 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
657 transport_info_t *transport_info){
658 proto_tree *sdp_connection_info_tree;
659 gint offset,next_offset,tokenlen;
665 sdp_connection_info_tree = proto_item_add_subtree(ti,
666 ett_sdp_connection_info);
668 /* Find the network type */
669 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
670 if( next_offset == -1 )
672 tokenlen = next_offset - offset;
674 proto_tree_add_item(sdp_connection_info_tree,
675 hf_connection_info_network_type, tvb, offset, tokenlen,
677 offset = next_offset + 1;
679 /* Find the address type */
680 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
681 if( next_offset == -1 )
683 tokenlen = next_offset - offset;
684 /* Save connection address type */
685 transport_info->connection_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
688 proto_tree_add_item(sdp_connection_info_tree,
689 hf_connection_info_address_type, tvb, offset, tokenlen,
691 offset = next_offset + 1;
693 /* Find the connection address */
694 /* XXX - what if there's a <number of addresses> value? */
695 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
696 if( next_offset == -1){
697 tokenlen = -1; /* end of tvbuff */
698 /* Save connection address */
699 transport_info->connection_address =
700 (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
702 tokenlen = next_offset - offset;
703 /* Save connection address */
704 transport_info->connection_address = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
707 proto_tree_add_item(sdp_connection_info_tree,
708 hf_connection_info_connection_address, tvb, offset,
710 if(next_offset != -1){
711 offset = next_offset + 1;
712 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
713 if( next_offset == -1){
714 tokenlen = -1; /* end of tvbuff */
716 tokenlen = next_offset - offset;
718 proto_tree_add_item(sdp_connection_info_tree,
719 hf_connection_info_ttl, tvb, offset, tokenlen, FALSE);
720 if(next_offset != -1){
721 offset = next_offset + 1;
722 proto_tree_add_item(sdp_connection_info_tree,
723 hf_connection_info_num_addr, tvb, offset, -1, FALSE);
729 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
730 proto_tree * sdp_bandwidth_tree;
731 gint offset, next_offset, tokenlen;
733 gboolean unit_is_kbs = FALSE;
734 gboolean unit_is_bps = FALSE;
740 sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
742 /* find the modifier */
743 next_offset = tvb_find_guint8(tvb,offset,-1,':');
745 if( next_offset == -1)
748 tokenlen = next_offset - offset;
750 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier, tvb, offset,
752 if (tvb_strneql(tvb, offset, "CT", 2) == 0){
753 proto_item_append_text(item, " [Conference Total(total bandwidth of all RTP sessions)]");
755 }else if (tvb_strneql(tvb, offset, "AS", 2) == 0){
756 proto_item_append_text(item, " [Application Specific (RTP session bandwidth)]");
758 }else if (tvb_strneql(tvb, offset, "TIAS", 4) == 0){
759 proto_item_append_text(item, " [Transport Independent Application Specific maximum]");
764 offset = next_offset + 1;
766 item = proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value, tvb, offset, -1,
768 if (unit_is_kbs == TRUE)
769 proto_item_append_text(item, " kb/s");
770 if (unit_is_bps == TRUE)
771 proto_item_append_text(item, " b/s");
774 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
775 proto_tree *sdp_time_tree;
776 gint offset,next_offset, tokenlen;
782 sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
785 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
786 if( next_offset == -1 )
789 tokenlen = next_offset - offset;
790 proto_tree_add_item(sdp_time_tree, hf_time_start, tvb, offset, tokenlen,
794 offset = next_offset + 1;
795 proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb, offset, -1, FALSE);
798 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
799 proto_tree *sdp_repeat_time_tree;
800 gint offset,next_offset, tokenlen;
806 sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
809 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
810 if( next_offset == -1 )
813 tokenlen = next_offset - offset;
814 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
815 offset, tokenlen, FALSE);
818 offset = next_offset + 1;
819 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
820 if( next_offset == -1 )
823 tokenlen = next_offset - offset;
824 proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
825 offset, tokenlen, FALSE);
829 offset = next_offset +1;
830 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
831 if(next_offset != -1){
832 tokenlen = next_offset - offset;
834 tokenlen = -1; /* end of tvbuff */
836 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
837 tvb, offset, tokenlen, FALSE);
838 } while( next_offset != -1 );
842 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
843 proto_tree* sdp_timezone_tree;
844 gint offset, next_offset, tokenlen;
849 sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
852 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
853 if(next_offset == -1)
855 tokenlen = next_offset - offset;
857 proto_tree_add_item(sdp_timezone_tree, hf_timezone_time, tvb, offset,
859 offset = next_offset + 1;
860 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
861 if(next_offset != -1){
862 tokenlen = next_offset - offset;
864 tokenlen = -1; /* end of tvbuff */
866 proto_tree_add_item(sdp_timezone_tree, hf_timezone_offset, tvb, offset,
868 offset = next_offset + 1;
869 } while (next_offset != -1);
874 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
875 proto_tree *sdp_encryption_key_tree;
876 gint offset, next_offset, tokenlen;
882 sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
884 next_offset = tvb_find_guint8(tvb,offset,-1,':');
886 if(next_offset == -1)
889 tokenlen = next_offset - offset;
891 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
892 tvb, offset, tokenlen, FALSE);
894 offset = next_offset + 1;
895 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
896 tvb, offset, -1, FALSE);
899 /* Return a tvb that contains the binary representation of a base64
903 base64_to_tvb(const char *base64)
906 char *data = g_strdup(base64);
909 len = epan_base64_decode(data);
910 tvb = tvb_new_real_data((const guint8 *)data, len, len);
912 tvb_set_free_cb(tvb, g_free);
918 static void dissect_key_mgmt(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
920 gchar *prtcl_id = NULL;
922 tvbuff_t *keymgmt_tvb;
923 gboolean found_match = FALSE;
924 proto_tree *key_tree;
929 key_tree = proto_item_add_subtree(ti, ett_sdp_key_mgmt);
931 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
933 if (next_offset == -1)
936 tokenlen = next_offset - offset;
937 prtcl_id = tvb_get_ephemeral_string(tvb, offset, tokenlen);
939 proto_tree_add_item(key_tree, hf_key_mgmt_prtcl_id, tvb, offset, tokenlen, FALSE);
941 offset = next_offset + 1;
943 len = tvb_length_remaining(tvb, offset);
947 data = tvb_get_ephemeral_string(tvb, offset, len);
948 keymgmt_tvb = base64_to_tvb(data);
949 tvb_set_child_real_data_tvbuff(tvb, keymgmt_tvb);
950 add_new_data_source(pinfo, keymgmt_tvb, "Key Management Data");
952 if ( prtcl_id != NULL && key_mgmt_dissector_table != NULL ) {
953 found_match = dissector_try_string(key_mgmt_dissector_table,
960 proto_item *ti = proto_tree_add_item(key_tree, hf_key_mgmt_data,
961 keymgmt_tvb, 0, -1, FALSE);
962 PROTO_ITEM_SET_HIDDEN(ti);
965 proto_tree_add_item(key_tree, hf_key_mgmt_data,
966 keymgmt_tvb, 0, -1, FALSE);
972 static void dissect_sdp_session_attribute(tvbuff_t *tvb, packet_info * pinfo, proto_item * ti){
973 proto_tree *sdp_session_attribute_tree;
974 gint offset, next_offset, tokenlen;
981 sdp_session_attribute_tree = proto_item_add_subtree(ti,
982 ett_sdp_session_attribute);
984 next_offset = tvb_find_guint8(tvb,offset,-1,':');
986 if(next_offset == -1)
989 tokenlen = next_offset - offset;
991 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_field,
992 tvb, offset, tokenlen, FALSE);
994 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
996 offset = next_offset + 1;
998 if (strcmp((char*)field_name, "ipbcp") == 0) {
999 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"0123456789");
1004 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1006 if (next_offset == -1)
1009 tokenlen = next_offset - offset;
1011 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_version,tvb,offset,tokenlen,FALSE);
1013 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
1018 tokenlen = tvb_find_line_end(tvb,offset,-1, &next_offset, FALSE);
1023 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE);
1024 } else if (strcmp((char*)field_name, "key-mgmt") == 0) {
1028 key_tvb = tvb_new_subset(tvb, offset, -1, -1);
1029 key_ti = proto_tree_add_item(sdp_session_attribute_tree, hf_key_mgmt_att_value, key_tvb, 0, -1, FALSE);
1031 dissect_key_mgmt(key_tvb, pinfo, key_ti);
1033 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value,
1034 tvb, offset, -1, FALSE);
1038 /* Dissect media description */
1040 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
1041 transport_info_t *transport_info){
1042 proto_tree *sdp_media_tree;
1043 gint offset, next_offset, tokenlen, index;
1044 guint8 *media_format;
1050 /* Re-initialise for a new media description */
1051 msrp_transport_address_set = FALSE;
1053 /* Create tree for media session */
1054 sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
1056 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1058 if(next_offset == -1)
1061 tokenlen = next_offset - offset;
1063 /* Type of media session */
1064 proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, offset, tokenlen,
1067 offset = next_offset + 1;
1069 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1070 if(next_offset == -1)
1072 tokenlen = next_offset - offset;
1073 next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
1075 if(next_offset != -1){
1076 tokenlen = next_offset - offset;
1077 /* Save port info */
1078 transport_info->media_port[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1080 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1081 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1082 offset = next_offset + 1;
1083 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1084 if(next_offset == -1)
1086 tokenlen = next_offset - offset;
1087 proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb, offset,
1089 offset = next_offset + 1;
1091 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
1093 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 /* XXX Remember Port */
1100 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
1101 atoi((char*)tvb_get_ephemeral_string(tvb, offset, tokenlen)));
1102 offset = next_offset + 1;
1105 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1107 if( next_offset == -1)
1110 tokenlen = next_offset - offset;
1111 /* Save port protocol */
1112 transport_info->media_proto[transport_info->media_count] = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1114 /* XXX Remember Protocol */
1115 proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb, offset, tokenlen,
1119 offset = next_offset + 1;
1120 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1122 if(next_offset == -1){
1123 tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
1125 break; /* Nothing more left */
1127 tokenlen = next_offset - offset;
1130 if (strcmp(transport_info->media_proto[transport_info->media_count],
1132 media_format = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1133 proto_tree_add_string(sdp_media_tree, hf_media_format, tvb, offset,
1134 tokenlen, val_to_str(atol((char*)media_format), rtp_payload_type_vals, "%u"));
1135 index = transport_info->media[transport_info->media_count].pt_count;
1136 transport_info->media[transport_info->media_count].pt[index] = atol((char*)media_format);
1137 if (index < (SDP_MAX_RTP_PAYLOAD_TYPES-1))
1138 transport_info->media[transport_info->media_count].pt_count++;
1140 proto_tree_add_item(sdp_media_tree, hf_media_format, tvb, offset,
1143 } while (next_offset != -1);
1145 /* Increase the count of media channels, but don't walk off the end
1147 if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
1148 transport_info->media_count++;
1151 /* XXX Dissect traffic to "Port" as "Protocol"
1152 * Remember this Port/Protocol pair so we can tear it down again later
1153 * Actually, it's harder than that:
1154 * We need to find out the address of the other side first and it
1155 * looks like that info can be found in SIP headers only.
1160 tvbuff_t *ascii_bytes_to_tvb(tvbuff_t *tvb, packet_info *pinfo, gint len, gchar *msg)
1162 guint8 *buf = ep_alloc(10240);
1164 /* arbitrary maximum length */
1167 tvbuff_t *bytes_tvb;
1169 /* first, skip to where the encoded pdu starts, this is
1170 the first hex digit after the '=' char.
1173 if((*msg==0)||(*msg=='\n')){
1183 if((*msg==0)||(*msg=='\n')){
1186 if( ((*msg>='0')&&(*msg<='9'))
1187 || ((*msg>='a')&&(*msg<='f'))
1188 || ((*msg>='A')&&(*msg<='F'))){
1194 while( ((*msg>='0')&&(*msg<='9'))
1195 ||((*msg>='a')&&(*msg<='f'))
1196 ||((*msg>='A')&&(*msg<='F')) ){
1198 if((*msg>='0')&&(*msg<='9')){
1200 } else if((*msg>='a')&&(*msg<='f')){
1202 } else if((*msg>='A')&&(*msg<='F')){
1209 if((*msg>='0')&&(*msg<='9')){
1211 } else if((*msg>='a')&&(*msg<='f')){
1213 } else if((*msg>='A')&&(*msg<='F')){
1226 bytes_tvb = tvb_new_real_data(buf,i,i);
1227 tvb_set_child_real_data_tvbuff(tvb,bytes_tvb);
1228 add_new_data_source(pinfo, bytes_tvb, "ASCII bytes to tvb");
1234 14496-2, Annex G, Table G-1.
1235 Table G-1 FLC table for profile_and_level_indication Profile/Level Code
1237 static const value_string mpeg4es_level_indication_vals[] =
1240 { 1, "Simple Profile/Level 1" },
1241 { 2, "Simple Profile/Level 2" },
1247 { 8, "Simple Profile/Level 0" },
1248 { 9, "Simple Profile/Level 0b" },
1249 /* Reserved 00001001 - 00010000 */
1250 { 0x11, "Simple Scalable Profile/Level 1" },
1251 { 0x12, "Simple Scalable Profile/Level 2" },
1252 /* Reserved 00010011 - 00100000 */
1253 { 0x21, "Core Profile/Level 1" },
1254 { 0x22, "Core Profile/Level 2" },
1255 /* Reserved 00100011 - 00110001 */
1256 { 0x32, "Main Profile/Level 2" },
1257 { 0x33, "Main Profile/Level 3" },
1258 { 0x34, "Main Profile/Level 4" },
1259 /* Reserved 00110101 - 01000001 */
1260 { 0x42, "N-bit Profile/Level 2" },
1261 /* Reserved 01000011 - 01010000 */
1262 { 0x51, "Scalable Texture Profile/Level 1" },
1263 /* Reserved 01010010 - 01100000 */
1264 { 0x61, "Simple Face Animation Profile/Level 1" },
1265 { 0x62, "Simple Face Animation Profile/Level 2" },
1266 { 0x63, "Simple FBA Profile/Level 1" },
1267 { 0x64, "Simple FBA Profile/Level 2" },
1268 /* Reserved 01100101 - 01110000 */
1269 { 0x71, "Basic Animated Texture Profile/Level 1" },
1270 { 0x72, "Basic Animated Texture Profile/Level 2" },
1271 /* Reserved 01110011 - 10000000 */
1272 { 0x81, "Hybrid Profile/Level 1" },
1273 { 0x82, "Hybrid Profile/Level 2" },
1274 /* Reserved 10000011 - 10010000 */
1275 { 0x91, "Advanced Real Time Simple Profile/Level 1" },
1276 { 0x92, "Advanced Real Time Simple Profile/Level 2" },
1277 { 0x93, "Advanced Real Time Simple Profile/Level 3" },
1278 { 0x94, "Advanced Real Time Simple Profile/Level 4" },
1279 /* Reserved 10010101 - 10100000 */
1280 { 0xa1, "Core Scalable Profile/Level 1" },
1281 { 0xa2, "Core Scalable Profile/Level 2" },
1282 { 0xa3, "Core Scalable Profile/Level 3" },
1283 /* Reserved 10100100 - 10110000 */
1284 { 0xb1, "Advanced Coding Efficiency Profile/Level 1" },
1285 { 0xb2, "Advanced Coding Efficiency Profile/Level 2" },
1286 { 0xb3, "Advanced Coding Efficiency Profile/Level 3" },
1287 { 0xb4, "Advanced Coding Efficiency Profile/Level 4" },
1288 /* Reserved 10110101 - 11000000 */
1289 { 0xc1, "Advanced Core Profile/Level 1" },
1290 { 0xc2, "Advanced Core Profile/Level 2" },
1291 /* Reserved 11000011 - 11010000 */
1292 { 0xd1, "Advanced Scalable Texture/Level 1" },
1293 { 0xd2, "Advanced Scalable Texture/Level 2" },
1294 { 0xd3, "Advanced Scalable Texture/Level 3" },
1295 /* Reserved 11010100 - 11100000 */
1296 { 0xe1, "Simple Studio Profile/Level 1" },
1297 { 0xe2, "Simple Studio Profile/Level 2" },
1298 { 0xe3, "Simple Studio Profile/Level 3" },
1299 { 0xe4, "Simple Studio Profile/Level 4" },
1300 { 0xe5, "Core Studio Profile/Level 1" },
1301 { 0xe6, "Core Studio Profile/Level 2" },
1302 { 0xe7, "Core Studio Profile/Level 3" },
1303 { 0xe8, "Core Studio Profile/Level 4" },
1304 /* Reserved 11101001 - 11101111 */
1305 { 0xf0, "Advanced Simple Profile/Level 0" },
1306 { 0xf1, "Advanced Simple Profile/Level 1" },
1307 { 0xf2, "Advanced Simple Profile/Level 2" },
1308 { 0xf3, "Advanced Simple Profile/Level 3" },
1309 { 0xf4, "Advanced Simple Profile/Level 4" },
1310 { 0xf5, "Advanced Simple Profile/Level 5" },
1311 /* Reserved 11110110 - 11110111 */
1312 { 0xf8, "Fine Granularity Scalable Profile/Level 0" },
1313 { 0xf9, "Fine Granularity Scalable Profile/Level 1" },
1314 { 0xfa, "Fine Granularity Scalable Profile/Level 2" },
1315 { 0xfb, "Fine Granularity Scalable Profile/Level 3" },
1316 { 0xfc, "Fine Granularity Scalable Profile/Level 4" },
1317 { 0xfd, "Fine Granularity Scalable Profile/Level 5" },
1318 { 0xfe, "Reserved" },
1319 { 0xff, "Reserved for Escape" },
1322 /* Annex X Profiles and levels definition */
1323 static const value_string h263_profile_vals[] =
1325 { 0, "Baseline Profile" },
1326 { 1, "H.320 Coding Efficiency Version 2 Backward-Compatibility Profile" },
1327 { 2, "Version 1 Backward-Compatibility Profile" },
1328 { 3, "Version 2 Interactive and Streaming Wireless Profile" },
1329 { 4, "Version 3 Interactive and Streaming Wireless Profile" },
1330 { 5, "Conversational High Compression Profile" },
1331 { 6, "Conversational Internet Profile" },
1332 { 7, "Conversational Interlace Profile" },
1333 { 8, "High Latency Profile" },
1337 static const value_string h264_packetization_mode_vals[] =
1339 { 0, "Single NAL mode" },
1340 { 1, "Non-interleaved mode" },
1341 { 2, "Interleaved mode" },
1346 * TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
1349 decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint tokenlen, guint8 *mime_type){
1353 gchar *format_specific_parameter;
1357 end_offset = offset + tokenlen;
1359 /* Look for an '=' within this value - this may indicate that there is a
1360 profile-level-id parameter to find if the MPEG4 media type is in use */
1361 next_offset = tvb_find_guint8(tvb,offset,-1,'=');
1362 if (next_offset == -1)
1364 /* Give up (and avoid exception) if '=' not found */
1368 /* Find the name of the parameter */
1369 tokenlen = next_offset - offset;
1370 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1372 offset = next_offset;
1374 /* Dissect the MPEG4 profile-level-id parameter if present */
1375 if (mime_type != NULL && strcmp((char*)mime_type, "MP4V-ES") == 0) {
1376 if (strcmp((char*)field_name, "profile-level-id") == 0) {
1378 tokenlen = end_offset - offset;
1379 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1380 item = proto_tree_add_uint(tree, hf_sdp_fmtp_mpeg4_profile_level_id, tvb, offset, tokenlen,
1381 atol((char*)format_specific_parameter));
1382 PROTO_ITEM_SET_GENERATED(item);
1386 /* Dissect the H263-2000 profile parameter if present */
1387 if (mime_type != NULL && strcmp((char*)mime_type, "H263-2000") == 0) {
1388 if (strcmp((char*)field_name, "profile") == 0) {
1390 tokenlen = end_offset - offset;
1391 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1392 item = proto_tree_add_uint(tree, hf_sdp_fmtp_h263_profile, tvb, offset, tokenlen,
1393 atol((char*)format_specific_parameter));
1394 PROTO_ITEM_SET_GENERATED(item);
1399 /* Dissect the H264 profile-level-id parameter */
1400 if (mime_type != NULL && strcmp(mime_type, "H264") == 0) {
1401 if (strcmp(field_name, "profile-level-id") == 0) {
1403 /* Length includes "=" */
1404 tokenlen = end_offset - offset;
1405 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1406 data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
1407 if(h264_handle && data_tvb){
1408 dissect_h264_profile(data_tvb, pinfo, tree);
1410 }else if (strcmp(field_name, "packetization-mode") == 0) {
1412 tokenlen = end_offset - offset;
1413 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1414 item = proto_tree_add_uint(tree, hf_sdp_h264_packetization_mode, tvb, offset, tokenlen,
1415 atol((char*)format_specific_parameter));
1417 }else if (strcmp(field_name, "sprop-parameter-sets") == 0) {
1418 /* The value of the parameter is the
1419 base64 [6] representation of the initial
1420 parameter set NAL units as specified in
1421 sections 7.3.2.1 and 7.3.2.2 of [1]. The
1422 parameter sets are conveyed in decoding order,
1423 and no framing of the parameter set NAL units
1424 takes place. A comma is used to separate any
1425 pair of parameter sets in the list.
1433 comma_offset = tvb_find_guint8(tvb,offset,-1,',');
1434 if (comma_offset != -1){
1435 tokenlen = comma_offset - offset;
1437 tokenlen = end_offset - offset;
1440 data = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1441 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 1 string: %s", data);
1443 /* proto_tree_add_text(tree, tvb, offset, tokenlen, "String %s",data); */
1444 data_tvb = base64_to_tvb(data);
1445 tvb_set_child_real_data_tvbuff(tvb, data_tvb);
1446 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets");
1448 if(h264_handle && data_tvb){
1449 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1450 if (comma_offset != -1){
1451 /* Second NAL unit */
1452 offset = comma_offset +1;
1453 tokenlen = end_offset - offset;
1454 data = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1455 proto_tree_add_text(tree, tvb, offset, tokenlen, "NAL unit 2 string: %s", data);
1456 data_tvb = base64_to_tvb(data);
1457 tvb_set_child_real_data_tvbuff(tvb, data_tvb);
1458 add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets 2");
1459 dissect_h264_nal_unit(data_tvb, pinfo, tree);
1471 #define SDP_RTPMAP 1
1474 #define SDP_H248_ITEM 4
1476 static const sdp_names_t sdp_media_attribute_names[] = {
1477 { "Unknown-name"}, /* 0 Pad so that the real headers start at index 1 */
1478 { "rtpmap"}, /* 1 */
1481 { "h248item"}, /* 4 */
1484 static gint find_sdp_media_attribute_names(tvbuff_t *tvb, int offset, guint len)
1488 for (i = 1; i < array_length(sdp_media_attribute_names); i++) {
1489 if (len == strlen(sdp_media_attribute_names[i].name) &&
1490 tvb_strncaseeql(tvb, offset, sdp_media_attribute_names[i].name, len) == 0)
1497 static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto_item * ti, transport_info_t *transport_info){
1498 proto_tree *sdp_media_attribute_tree;
1499 proto_item *fmtp_item, *media_format_item;
1500 proto_tree *fmtp_tree;
1501 gint offset, next_offset, tokenlen, n;
1503 guint8 *payload_type;
1504 guint8 *attribute_value;
1506 gint sdp_media_attrbute_code;
1507 const char *msrp_res = "msrp://";
1508 const char *h324ext_h223lcparm = "h324ext/h223lcparm";
1509 gboolean has_more_pars = TRUE;
1516 /* Create attribute tree */
1517 sdp_media_attribute_tree = proto_item_add_subtree(ti,
1518 ett_sdp_media_attribute);
1519 /* Find end of field */
1520 next_offset = tvb_find_guint8(tvb,offset,-1,':');
1522 if(next_offset == -1)
1525 /* Attribute field name is token before ':' */
1526 tokenlen = next_offset - offset;
1527 proto_tree_add_item(sdp_media_attribute_tree,
1528 hf_media_attribute_field,
1529 tvb, offset, tokenlen, FALSE);
1530 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1531 sdp_media_attrbute_code = find_sdp_media_attribute_names(tvb, offset, tokenlen);
1534 offset = next_offset + 1;
1536 /* Value is the remainder of the line */
1537 attribute_value = tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
1541 /*********************************************/
1542 /* Special parsing for some field name types */
1544 switch (sdp_media_attrbute_code){
1546 /* decode the rtpmap to see if it is DynamicPayload to dissect them automatic */
1547 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1549 if(next_offset == -1)
1552 tokenlen = next_offset - offset;
1554 proto_tree_add_item(sdp_media_attribute_tree, hf_media_format, tvb,
1555 offset, tokenlen, FALSE);
1557 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1559 offset = next_offset + 1;
1561 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
1563 if(next_offset == -1){
1567 tokenlen = next_offset - offset;
1569 proto_tree_add_item(sdp_media_attribute_tree, hf_media_encoding_name, tvb,
1570 offset, tokenlen, FALSE);
1571 /* get_string is needed here as the string is "saved" in a hashtable */
1572 transport_info->encoding_name = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1574 key=g_malloc( sizeof(gint) );
1575 *key=atol((char*)payload_type);
1577 /* As per RFC2327 it is possible to have multiple Media Descriptions ("m=").
1580 a=rtpmap:101 G726-32/8000
1581 m=audio 49170 RTP/AVP 0 97
1582 a=rtpmap:97 telephone-event/8000
1583 m=audio 49172 RTP/AVP 97 101
1584 a=rtpmap:97 G726-24/8000
1586 The Media attributes ("a="s) after the "m=" only apply for that "m=".
1587 If there is an "a=" before the first "m=", that attribute applies for
1588 all the session (all the "m="s).
1591 /* so, if this "a=" appear before any "m=", we add it to all the dynamic
1594 if (transport_info->media_count == 0) {
1595 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++) {
1597 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1598 key, g_strdup(transport_info->encoding_name));
1599 else { /* we create a new key and encoding_name to assign to the other hash tables */
1601 key2=g_malloc( sizeof(gint) );
1602 *key2=atol((char*)payload_type);
1603 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1604 key2, g_strdup(transport_info->encoding_name));
1608 /* if the "a=" is after an "m=", only apply to this "m=" */
1610 /* in case there is an overflow in SDP_MAX_RTP_CHANNELS, we keep always the last "m=" */
1611 if (transport_info->media_count == SDP_MAX_RTP_CHANNELS-1)
1612 g_hash_table_insert(transport_info->media[ transport_info->media_count ].rtp_dyn_payload,
1613 key, g_strdup(transport_info->encoding_name));
1615 g_hash_table_insert(transport_info->media[ transport_info->media_count-1 ].rtp_dyn_payload,
1616 key, g_strdup(transport_info->encoding_name));
1619 if(sdp_media_attribute_tree){
1620 /* Reading the Format parameter(fmtp) */
1621 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1623 if(next_offset == -1)
1626 tokenlen = next_offset - offset;
1628 /* Media format extends to the next space */
1629 media_format_item = proto_tree_add_item(sdp_media_attribute_tree,
1630 hf_media_format, tvb, offset,
1632 /* Append encoding name to format if known */
1633 if (transport_info->encoding_name)
1634 proto_item_append_text(media_format_item, " [%s]",
1635 transport_info->encoding_name);
1637 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1638 /* Offset past space after ':' */
1639 offset = next_offset + 1;
1641 while(has_more_pars==TRUE){
1642 next_offset = tvb_find_guint8(tvb,offset,-1,';');
1643 offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
1645 if(next_offset == -1){
1646 has_more_pars = FALSE;
1647 next_offset= tvb_length(tvb);
1652 /* There are 2 - add the first parameter */
1653 tokenlen = next_offset - offset;
1654 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1655 hf_media_format_specific_parameter, tvb,
1656 offset, tokenlen, FALSE);
1658 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1660 decode_sdp_fmtp(fmtp_tree, tvb, pinfo, offset, tokenlen,
1661 (guint8 *)transport_info->encoding_name);
1663 /* Move offset past "; " and onto firts char */
1664 offset = next_offset + 1;
1669 /* msrp attributes that contain address needed for conversation */
1670 if (strncmp((char*)attribute_value, msrp_res, strlen(msrp_res)) == 0){
1671 int address_offset, port_offset, port_end_offset;
1673 /* Address starts here */
1674 address_offset = offset + strlen(msrp_res);
1676 /* Port is after next ':' */
1677 port_offset = tvb_find_guint8(tvb, address_offset, -1, ':');
1679 /* Port ends with '/' */
1680 port_end_offset = tvb_find_guint8(tvb, port_offset, -1, '/');
1682 /* Attempt to convert address */
1683 if (inet_pton(AF_INET, (char*)tvb_get_ephemeral_string(tvb, address_offset, port_offset-address_offset), &msrp_ipaddr) > 0) {
1684 /* Get port number */
1685 msrp_port_number = atoi((char*)tvb_get_ephemeral_string(tvb, port_offset+1, port_end_offset-port_offset-1));
1686 /* Set flag so this info can be used */
1687 msrp_transport_address_set = TRUE;
1692 /* Decode h248 item ITU-T Rec. H.248.12 (2001)/Amd.1 (11/2002)*/
1693 if (strncmp((char*)attribute_value, h324ext_h223lcparm, strlen(msrp_res)) == 0){
1694 /* A.5.1.3 H.223 Logical channel parameters
1695 * This property indicates the H.245
1696 * H223LogicalChannelsParameters structure encoded by applying the PER specified in
1697 * ITU-T Rec. X.691. Value encoded as per A.5.1.2. For text encoding the mechanism defined
1698 * in ITU-T Rec. H.248.15 is used.
1703 len = strlen(attribute_value);
1704 h245_tvb = ascii_bytes_to_tvb(tvb, pinfo, len, attribute_value);
1705 /* arbitrary maximum length */
1706 /* should go through a handle, however, the two h245 entry
1707 points are different, one is over tpkt and the other is raw
1710 asn1_ctx_init(&actx, ASN1_ENC_PER, TRUE, pinfo);
1711 dissect_h245_H223LogicalChannelParameters(h245_tvb, 0, &actx, sdp_media_attribute_tree, hf_SDPh223LogicalChannelParameters);
1716 /* No special treatment for values of this attribute type, just add as one item. */
1717 proto_tree_add_item(sdp_media_attribute_tree, hf_media_attribute_value,
1718 tvb, offset, -1, FALSE);
1724 proto_register_sdp(void)
1726 static hf_register_info hf[] = {
1727 { &hf_protocol_version,
1728 { "Session Description Protocol Version (v)",
1729 "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
1730 "Session Description Protocol Version", HFILL }},
1732 { "Owner/Creator, Session Id (o)",
1733 "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
1734 "Owner/Creator, Session Id", HFILL}},
1736 { "Session Name (s)",
1737 "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
1738 "Session Name", HFILL }},
1740 { "Session Information (i)",
1741 "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
1742 "Session Information", HFILL }},
1744 { "URI of Description (u)",
1745 "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
1746 "URI of Description", HFILL }},
1748 { "E-mail Address (e)",
1749 "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
1750 "E-mail Address", HFILL }},
1752 { "Phone Number (p)",
1753 "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
1754 "Phone Number", HFILL }},
1755 { &hf_connection_info,
1756 { "Connection Information (c)",
1757 "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
1758 "Connection Information", HFILL }},
1760 { "Bandwidth Information (b)",
1761 "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
1762 "Bandwidth Information", HFILL }},
1764 { "Time Zone Adjustments (z)",
1765 "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
1766 "Time Zone Adjustments", HFILL }},
1767 { &hf_encryption_key,
1768 { "Encryption Key (k)",
1769 "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
1770 "Encryption Key", HFILL }},
1771 { &hf_session_attribute,
1772 { "Session Attribute (a)",
1773 "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1774 "Session Attribute", HFILL }},
1775 { &hf_media_attribute,
1776 { "Media Attribute (a)",
1777 "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1778 "Media Attribute", HFILL }},
1780 { "Time Description, active time (t)",
1781 "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
1782 "Time Description, active time", HFILL }},
1784 { "Repeat Time (r)",
1785 "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
1786 "Repeat Time", HFILL }},
1788 { "Media Description, name and address (m)",
1789 "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
1790 "Media Description, name and address", HFILL }},
1792 { "Media Title (i)",
1793 "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
1794 "Media Title", HFILL }},
1797 "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
1798 "Unknown", HFILL }},
1801 "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
1802 "Invalid line", HFILL }},
1803 { &hf_owner_username,
1805 "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
1806 "Owner Username", HFILL }},
1807 { &hf_owner_sessionid,
1809 "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
1810 "Session ID", HFILL }},
1811 { &hf_owner_version,
1812 { "Session Version",
1813 "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
1814 "Session Version", HFILL }},
1815 { &hf_owner_network_type,
1816 { "Owner Network Type",
1817 "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1818 "Owner Network Type", HFILL }},
1819 { &hf_owner_address_type,
1820 { "Owner Address Type",
1821 "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1822 "Owner Address Type", HFILL }},
1823 { &hf_owner_address,
1825 "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
1826 "Owner Address", HFILL }},
1827 { &hf_connection_info_network_type,
1828 { "Connection Network Type",
1829 "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1830 "Connection Network Type", HFILL }},
1831 { &hf_connection_info_address_type,
1832 { "Connection Address Type",
1833 "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1834 "Connection Address Type", HFILL }},
1835 { &hf_connection_info_connection_address,
1836 { "Connection Address",
1837 "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
1838 "Connection Address", HFILL }},
1839 { &hf_connection_info_ttl,
1841 "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
1842 "Connection TTL", HFILL }},
1843 { &hf_connection_info_num_addr,
1844 { "Connection Number of Addresses",
1845 "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
1846 "Connection Number of Addresses", HFILL }},
1847 { &hf_bandwidth_modifier,
1848 { "Bandwidth Modifier",
1849 "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
1850 "Bandwidth Modifier", HFILL }},
1851 { &hf_bandwidth_value,
1852 { "Bandwidth Value",
1853 "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
1854 "Bandwidth Value (in kbits/s)", HFILL }},
1856 { "Session Start Time",
1857 "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
1858 "Session Start Time", HFILL }},
1860 { "Session Stop Time",
1861 "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
1862 "Session Stop Time", HFILL }},
1863 { &hf_repeat_time_interval,
1864 { "Repeat Interval",
1865 "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
1866 "Repeat Interval", HFILL }},
1867 { &hf_repeat_time_duration,
1868 { "Repeat Duration",
1869 "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
1870 "Repeat Duration", HFILL }},
1871 { &hf_repeat_time_offset,
1873 "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1874 "Repeat Offset", HFILL }},
1875 { &hf_timezone_time,
1877 "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
1878 "Timezone Time", HFILL }},
1879 { &hf_timezone_offset,
1880 { "Timezone Offset",
1881 "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1882 "Timezone Offset", HFILL }},
1883 { &hf_encryption_key_type,
1885 "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
1887 { &hf_encryption_key_data,
1889 "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
1891 { &hf_session_attribute_field,
1892 { "Session Attribute Fieldname",
1893 "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
1894 "Session Attribute Fieldname", HFILL }},
1895 { &hf_session_attribute_value,
1896 { "Session Attribute Value",
1897 "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
1898 "Session Attribute Value", HFILL }},
1901 "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
1902 "Media Type", HFILL }},
1905 "sdp.media.port",FT_UINT16, BASE_DEC, NULL, 0x0,
1906 "Media Port", HFILL }},
1907 { &hf_media_portcount,
1908 { "Media Port Count",
1909 "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
1910 "Media Port Count", HFILL }},
1913 "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
1914 "Media Protocol", HFILL }},
1917 "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
1918 "Media Format", HFILL }},
1919 { &hf_media_attribute_field,
1920 { "Media Attribute Fieldname",
1921 "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
1922 "Media Attribute Fieldname", HFILL }},
1923 { &hf_media_attribute_value,
1924 { "Media Attribute Value",
1925 "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
1926 "Media Attribute Value", HFILL }},
1927 { &hf_media_encoding_name,
1929 "sdp.mime.type",FT_STRING, BASE_NONE, NULL, 0x0,
1930 "SDP MIME Type", HFILL }},
1931 { &hf_media_format_specific_parameter,
1932 { "Media format specific parameters",
1933 "sdp.fmtp.parameter",FT_STRING, BASE_NONE, NULL, 0x0,
1934 "Format specific parameter(fmtp)", HFILL }},
1935 { &hf_ipbcp_version,
1936 { "IPBCP Protocol Version",
1937 "ipbcp.version",FT_STRING, BASE_NONE, NULL, 0x0,
1938 "IPBCP Protocol Version", HFILL }},
1940 { "IPBCP Command Type",
1941 "ipbcp.command",FT_STRING, BASE_NONE, NULL, 0x0,
1942 "IPBCP Command Type", HFILL }},
1943 {&hf_sdp_fmtp_mpeg4_profile_level_id,
1945 "sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mpeg4es_level_indication_vals), 0x0,
1946 "Level Code", HFILL }},
1947 { &hf_sdp_fmtp_h263_profile,
1949 "sdp.fmtp.h263profile",FT_UINT32, BASE_DEC,VALS(h263_profile_vals), 0x0,
1950 "Profile", HFILL }},
1951 { &hf_sdp_h264_packetization_mode,
1952 { "Packetization mode",
1953 "sdp.fmtp.h264_packetization_mode",FT_UINT32, BASE_DEC,VALS(h264_packetization_mode_vals), 0x0,
1954 "Packetization mode", HFILL }},
1955 { &hf_sdp_h264_sprop_parameter_sets,
1956 { "Sprop_parameter_sets",
1957 "sdp.h264.sprop_parameter_sets", FT_BYTES, BASE_NONE, NULL, 0x0,
1958 "Sprop_parameter_sets", HFILL }},
1959 { &hf_SDPh223LogicalChannelParameters,
1960 { "h223LogicalChannelParameters", "sdp.h223LogicalChannelParameters",
1961 FT_NONE, BASE_NONE, NULL, 0,
1962 "sdp.h223LogicalChannelParameters", HFILL }},
1963 { &hf_key_mgmt_att_value,
1965 "sdp.key_mgmt", FT_STRING, BASE_NONE, NULL, 0x0,
1966 "Key Management", HFILL }},
1967 { &hf_key_mgmt_prtcl_id,
1968 { "Key Management Protocol (kmpid)",
1969 "sdp.key_mgmt.kmpid", FT_STRING, BASE_NONE, NULL, 0x0,
1970 "Key Management Protocol", HFILL }},
1971 { &hf_key_mgmt_data,
1972 { "Key Management Data",
1973 "sdp.key_mgmt.data", FT_BYTES, BASE_NONE, NULL, 0x0,
1974 "Key Management Data", HFILL }},
1976 static gint *ett[] = {
1979 &ett_sdp_connection_info,
1982 &ett_sdp_repeat_time,
1984 &ett_sdp_encryption_key,
1985 &ett_sdp_session_attribute,
1987 &ett_sdp_media_attribute,
1992 module_t *sdp_module;
1994 proto_sdp = proto_register_protocol("Session Description Protocol",
1996 proto_register_field_array(proto_sdp, hf, array_length(hf));
1997 proto_register_subtree_array(ett, array_length(ett));
1999 key_mgmt_dissector_table = register_dissector_table("key_mgmt",
2000 "Key Management", FT_STRING, BASE_NONE);
2003 * Preferences registration
2005 sdp_module = prefs_register_protocol(proto_sdp, NULL);
2006 prefs_register_bool_preference(sdp_module, "establish_conversation",
2007 "Establish Media Conversation",
2008 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
2009 "upon port numbers found in SDP payload",
2010 &global_sdp_establish_conversation);
2013 * Register the dissector by name, so other dissectors can
2014 * grab it by name rather than just referring to it directly.
2016 register_dissector("sdp", dissect_sdp, proto_sdp);
2018 /* Register for tapping */
2019 sdp_tap = register_tap("sdp");
2023 proto_reg_handoff_sdp(void)
2025 dissector_handle_t sdp_handle;
2027 rtp_handle = find_dissector("rtp");
2028 rtcp_handle = find_dissector("rtcp");
2029 msrp_handle = find_dissector("msrp");
2030 t38_handle = find_dissector("t38");
2031 h264_handle = find_dissector("h264");
2033 sdp_handle = find_dissector("sdp");
2034 dissector_add_string("media_type", "application/sdp", sdp_handle);
2035 dissector_add("bctp.tpi", 0x20, sdp_handle);