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.
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
37 #ifdef HAVE_NETINET_IN_H
38 # include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
44 #ifdef HAVE_WINSOCK2_H
45 #include <winsock2.h> /* needed to define AF_ values on Windows */
48 #ifdef NEED_INET_V6DEFS_H
49 # include "inet_v6defs.h"
53 #include <epan/packet.h>
54 #include <epan/conversation.h>
55 #include <epan/strutil.h>
56 #include <epan/emem.h>
59 #include "packet-sdp.h"
61 #include "packet-rtp.h"
62 #include <epan/rtp_pt.h>
64 #include <epan/prefs.h>
66 #include "packet-rtcp.h"
67 #include "packet-t38.h"
68 #include "packet-msrp.h"
70 static dissector_handle_t rtp_handle=NULL;
71 static dissector_handle_t rtcp_handle=NULL;
72 static dissector_handle_t t38_handle=NULL;
73 static dissector_handle_t msrp_handle=NULL;
75 static int sdp_tap = -1;
77 static int proto_sdp = -1;
79 /* preference globals */
80 static gboolean global_sdp_establish_conversation = TRUE;
82 /* Top level fields */
83 static int hf_protocol_version = -1;
84 static int hf_owner = -1;
85 static int hf_session_name = -1;
86 static int hf_session_info = -1;
87 static int hf_uri = -1;
88 static int hf_email = -1;
89 static int hf_phone = -1;
90 static int hf_connection_info = -1;
91 static int hf_bandwidth = -1;
92 static int hf_timezone = -1;
93 static int hf_encryption_key = -1;
94 static int hf_session_attribute = -1;
95 static int hf_media_attribute = -1;
96 static int hf_time = -1;
97 static int hf_repeat_time = -1;
98 static int hf_media = -1;
99 static int hf_media_title = -1;
100 static int hf_unknown = -1;
101 static int hf_invalid = -1;
102 static int hf_ipbcp_version = -1;
103 static int hf_ipbcp_type = -1;
105 /* hf_owner subfields*/
106 static int hf_owner_username = -1;
107 static int hf_owner_sessionid = -1;
108 static int hf_owner_version = -1;
109 static int hf_owner_network_type = -1;
110 static int hf_owner_address_type = -1;
111 static int hf_owner_address = -1;
113 /* hf_connection_info subfields */
114 static int hf_connection_info_network_type = -1;
115 static int hf_connection_info_address_type = -1;
116 static int hf_connection_info_connection_address = -1;
117 static int hf_connection_info_ttl = -1;
118 static int hf_connection_info_num_addr = -1;
120 /* hf_bandwidth subfields */
121 static int hf_bandwidth_modifier = -1;
122 static int hf_bandwidth_value = -1;
124 /* hf_time subfields */
125 static int hf_time_start = -1;
126 static int hf_time_stop = -1;
128 /* hf_repeat_time subfield */
129 static int hf_repeat_time_interval = -1;
130 static int hf_repeat_time_duration = -1;
131 static int hf_repeat_time_offset = -1;
133 /* hf_timezone subfields */
134 static int hf_timezone_time = -1;
135 static int hf_timezone_offset = -1;
137 /* hf_encryption_key subfields */
138 static int hf_encryption_key_type = -1;
139 static int hf_encryption_key_data = -1;
141 /* hf_session_attribute subfields */
142 static int hf_session_attribute_field = -1;
143 static int hf_session_attribute_value = -1;
145 /* hf_media subfields */
146 static int hf_media_media = -1;
147 static int hf_media_port = -1;
148 static int hf_media_portcount = -1;
149 static int hf_media_proto = -1;
150 static int hf_media_format = -1;
152 /* hf_session_attribute subfields */
153 static int hf_media_attribute_field = -1;
154 static int hf_media_attribute_value = -1;
155 static int hf_media_encoding_name = -1;
156 static int hf_media_format_specific_parameter = -1;
157 static int hf_sdp_fmtp_profile_level_id = -1;
160 static int ett_sdp = -1;
161 static int ett_sdp_owner = -1;
162 static int ett_sdp_connection_info = -1;
163 static int ett_sdp_bandwidth = -1;
164 static int ett_sdp_time = -1;
165 static int ett_sdp_repeat_time = -1;
166 static int ett_sdp_timezone = -1;
167 static int ett_sdp_encryption_key = -1;
168 static int ett_sdp_session_attribute = -1;
169 static int ett_sdp_media = -1;
170 static int ett_sdp_media_attribute = -1;
171 static int ett_sdp_fmtp = -1;
174 #define SDP_MAX_RTP_CHANNELS 4
175 #define SDP_MAX_RTP_PAYLOAD_TYPES 20
178 gint32 pt[SDP_MAX_RTP_PAYLOAD_TYPES];
180 GHashTable *rtp_dyn_payload;
181 } transport_media_pt_t;
184 char *connection_address;
185 char *connection_type;
187 char *media_port[SDP_MAX_RTP_CHANNELS];
188 char *media_proto[SDP_MAX_RTP_CHANNELS];
189 transport_media_pt_t media[SDP_MAX_RTP_CHANNELS];
194 /* MSRP transport info (as set while parsing path attribute) */
195 static gboolean msrp_transport_address_set = FALSE;
196 static guint32 msrp_ipaddr[4];
197 static guint16 msrp_port_number;
200 /* Protocol registration */
201 void proto_register_sdp(void);
202 void proto_reg_handoff_sdp(void);
205 /* static functions */
207 static void call_sdp_subdissector(tvbuff_t *tvb, int hf, proto_tree* ti,
208 transport_info_t *transport_info);
210 /* Subdissector functions */
211 static void dissect_sdp_owner(tvbuff_t *tvb, proto_item* ti);
212 static void dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
213 transport_info_t *transport_info);
214 static void dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti);
215 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti);
216 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti);
217 static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti);
218 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti);
219 static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item *ti);
220 static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
221 transport_info_t *transport_info);
222 static void dissect_sdp_media_attribute(tvbuff_t *tvb, proto_item *ti, transport_info_t *transport_info);
225 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
227 proto_tree *sdp_tree;
228 proto_item *ti, *sub_ti;
232 gboolean in_media_description;
242 transport_info_t transport_info;
245 gboolean is_rtp=FALSE;
246 gboolean is_t38=FALSE;
247 gboolean is_msrp=FALSE;
248 gboolean set_rtp=FALSE;
249 gboolean is_ipv4_addr=FALSE;
250 gboolean is_ipv6_addr=FALSE;
253 sdp_packet_info *sdp_pi;
255 /* Initialise packet info for passing to tap */
256 sdp_pi = ep_alloc(sizeof(sdp_packet_info));
257 sdp_pi->summary_str[0] = '\0';
259 /* Initialise RTP channel info */
260 transport_info.connection_address=NULL;
261 transport_info.connection_type=NULL;
262 transport_info.encoding_name=NULL;
263 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++)
265 transport_info.media_port[n]=NULL;
266 transport_info.media_proto[n]=NULL;
267 transport_info.media[n].pt_count = 0;
268 transport_info.media[n].rtp_dyn_payload = g_hash_table_new( g_int_hash, g_int_equal);
270 transport_info.media_count = 0;
273 * As RFC 2327 says, "SDP is purely a format for session
274 * description - it does not incorporate a transport protocol,
275 * and is intended to use different transport protocols as
276 * appropriate including the Session Announcement Protocol,
277 * Session Initiation Protocol, Real-Time Streaming Protocol,
278 * electronic mail using the MIME extensions, and the
279 * Hypertext Transport Protocol."
281 * We therefore don't set the protocol or info columns;
282 * instead, we append to them, so that we don't erase
283 * what the protocol inside which the SDP stuff resides
286 if (check_col(pinfo->cinfo, COL_PROTOCOL))
287 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
289 if (check_col(pinfo->cinfo, COL_INFO)) {
290 /* XXX: Needs description. */
291 col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
294 ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
295 sdp_tree = proto_item_add_subtree(ti, ett_sdp);
298 * Show the SDP message a line at a time.
300 in_media_description = FALSE;
301 while (tvb_reported_length_remaining(tvb, offset) > 0) {
303 * Find the end of the line.
305 linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
308 * Line must contain at least e.g. "v=".
313 type = tvb_get_guint8(tvb,offset);
314 delim = tvb_get_guint8(tvb,offset + 1);
316 proto_tree_add_item(sdp_tree, hf_invalid, tvb, offset, linelen, FALSE);
317 offset = next_offset;
326 hf = hf_protocol_version;
332 hf = hf_session_name;
335 if (in_media_description) {
339 hf = hf_session_info;
352 hf = hf_connection_info;
365 in_media_description = TRUE;
368 hf = hf_encryption_key;
371 if (in_media_description) {
372 hf = hf_media_attribute;
375 hf = hf_session_attribute;
386 if (hf == hf_unknown)
388 string = (char*)tvb_get_ephemeral_string(tvb, offset + tokenoffset,
389 linelen - tokenoffset);
390 sub_ti = proto_tree_add_string(sdp_tree, hf, tvb, offset, linelen,
392 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
394 linelen-tokenoffset),
395 hf,sub_ti,&transport_info),
396 offset = next_offset;
400 /* Now look, if we have strings collected.
401 * Try to convert ipv4 addresses and ports into binary format,
402 * so we can use them to detect rtp and rtcp streams.
403 * Don't forget to free the strings!
406 for (n = 0; n < transport_info.media_count; n++)
408 if(transport_info.media_port[n]!=NULL) {
409 port = atol(transport_info.media_port[n]);
411 if(transport_info.media_proto[n]!=NULL) {
412 /* Check if media protocol is RTP
413 * and stream decoding is enabled in preferences
415 if(global_sdp_establish_conversation){
416 /* Check if media protocol is RTP */
417 is_rtp = (strcmp(transport_info.media_proto[n],"RTP/AVP")==0);
418 /* Check if media protocol is T38 */
419 is_t38 = ( (strcmp(transport_info.media_proto[n],"UDPTL")==0) || (strcmp(transport_info.media_proto[n],"udptl")==0) );
420 /* Check if media protocol is MSRP/TCP */
421 is_msrp = (strcmp(transport_info.media_proto[n],"msrp/tcp")==0);
426 if(transport_info.connection_address!=NULL) {
427 if(transport_info.connection_type!=NULL) {
428 if (strcmp(transport_info.connection_type,"IP4")==0) {
429 if(inet_pton(AF_INET,transport_info.connection_address, &ipaddr)==1 ) {
430 /* connection_address could be converted to a valid ipv4 address*/
432 src_addr.type=AT_IPv4;
436 else if (strcmp(transport_info.connection_type,"IP6")==0){
437 if (inet_pton(AF_INET6, transport_info.connection_address, &ipaddr)==1){
438 /* connection_address could be converted to a valid ipv6 address*/
440 src_addr.type=AT_IPv6;
447 /* Add rtp and rtcp conversation, if available (overrides t38 if conversation already set) */
448 if((!pinfo->fd->flags.visited) && port!=0 && is_rtp && (is_ipv4_addr || is_ipv6_addr)){
449 src_addr.data=(char *)&ipaddr;
451 rtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num,
452 transport_info.media[n].rtp_dyn_payload);
457 rtcp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
461 /* Add t38 conversation, if available and only if no rtp */
462 if((!pinfo->fd->flags.visited) && port!=0 && !set_rtp && is_t38 && is_ipv4_addr){
463 src_addr.data=(char *)&ipaddr;
465 t38_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
469 /* Add MSRP conversation. Uses addresses discovered in attribute
470 rather than connection information of media session line */
472 if ((!pinfo->fd->flags.visited) && msrp_transport_address_set){
474 src_addr.type=AT_IPv4;
476 src_addr.data=(char *)&msrp_ipaddr;
477 msrp_add_address(pinfo, &src_addr, msrp_port_number, "SDP", pinfo->fd->num);
482 /* Create the RTP summary str for the Voip Call analysis */
483 for (i = 0; i < transport_info.media[n].pt_count; i++)
485 /* if the payload type is dynamic (96 to 127), check the hash table to add the desc in the SDP summary */
486 if ( (transport_info.media[n].pt[i] >=96) && (transport_info.media[n].pt[i] <=127) ) {
487 gchar *str_dyn_pt = g_hash_table_lookup(transport_info.media[n].rtp_dyn_payload, &transport_info.media[n].pt[i]);
489 g_snprintf(sdp_pi->summary_str, 50, "%s %s", sdp_pi->summary_str, str_dyn_pt);
491 g_snprintf(sdp_pi->summary_str, 50, "%s %d", sdp_pi->summary_str, transport_info.media[n].pt[i]);
493 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"));
496 /* Free the hash table if we did't assigned it to a conv use it */
497 if (set_rtp == FALSE)
498 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
500 /* Create the T38 summary str for the Voip Call analysis */
501 if (is_t38) g_snprintf(sdp_pi->summary_str, 50, "%s t38", sdp_pi->summary_str);
504 /* Free the remainded hash tables not used */
505 for (n = transport_info.media_count; n < SDP_MAX_RTP_CHANNELS; n++)
507 rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
511 datalen = tvb_length_remaining(tvb, offset);
513 proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)",
517 /* Report this packet to the tap */
518 tap_queue_packet(sdp_tap, pinfo, sdp_pi);
522 call_sdp_subdissector(tvbuff_t *tvb, int hf, proto_tree* ti, transport_info_t *transport_info){
524 dissect_sdp_owner(tvb,ti);
525 } else if ( hf == hf_connection_info) {
526 dissect_sdp_connection_info(tvb,ti,transport_info);
527 } else if ( hf == hf_bandwidth) {
528 dissect_sdp_bandwidth(tvb,ti);
529 } else if ( hf == hf_time) {
530 dissect_sdp_time(tvb,ti);
531 } else if ( hf == hf_repeat_time ){
532 dissect_sdp_repeat_time(tvb,ti);
533 } else if ( hf == hf_timezone ) {
534 dissect_sdp_timezone(tvb,ti);
535 } else if ( hf == hf_encryption_key ) {
536 dissect_sdp_encryption_key(tvb,ti);
537 } else if ( hf == hf_session_attribute ){
538 dissect_sdp_session_attribute(tvb,ti);
539 } else if ( hf == hf_media ) {
540 dissect_sdp_media(tvb,ti,transport_info);
541 } else if ( hf == hf_media_attribute ){
542 dissect_sdp_media_attribute(tvb,ti,transport_info);
547 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
548 proto_tree *sdp_owner_tree;
549 gint offset,next_offset,tokenlen;
555 sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
557 /* Find the username */
558 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
559 if( next_offset == -1 )
561 tokenlen = next_offset - offset;
563 proto_tree_add_item(sdp_owner_tree, hf_owner_username, tvb, offset, tokenlen,
565 offset = next_offset + 1;
567 /* Find the session id */
568 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
569 if( next_offset == -1 )
571 tokenlen = next_offset - offset;
573 proto_tree_add_item(sdp_owner_tree, hf_owner_sessionid, tvb, offset,
575 offset = next_offset + 1;
577 /* Find the version */
578 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
579 if( next_offset == -1 )
581 tokenlen = next_offset - offset;
583 proto_tree_add_item(sdp_owner_tree, hf_owner_version, tvb, offset, tokenlen,
585 offset = next_offset + 1;
587 /* Find the network type */
588 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
589 if( next_offset == -1 )
591 tokenlen = next_offset - offset;
593 proto_tree_add_item(sdp_owner_tree, hf_owner_network_type, tvb, offset,
595 offset = next_offset + 1;
597 /* Find the address type */
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_address_type, tvb, offset,
605 offset = next_offset + 1;
607 /* Find the address */
608 proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
612 * XXX - this can leak memory if an exception is thrown after we've fetched
616 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti,
617 transport_info_t *transport_info){
618 proto_tree *sdp_connection_info_tree;
619 gint offset,next_offset,tokenlen;
625 sdp_connection_info_tree = proto_item_add_subtree(ti,
626 ett_sdp_connection_info);
628 /* Find the network type */
629 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
630 if( next_offset == -1 )
632 tokenlen = next_offset - offset;
634 proto_tree_add_item(sdp_connection_info_tree,
635 hf_connection_info_network_type, tvb, offset, tokenlen,
637 offset = next_offset + 1;
639 /* Find the address type */
640 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
641 if( next_offset == -1 )
643 tokenlen = next_offset - offset;
644 /* Save connection address type */
645 transport_info->connection_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
648 proto_tree_add_item(sdp_connection_info_tree,
649 hf_connection_info_address_type, tvb, offset, tokenlen,
651 offset = next_offset + 1;
653 /* Find the connection address */
654 /* XXX - what if there's a <number of addresses> value? */
655 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
656 if( next_offset == -1){
657 tokenlen = -1; /* end of tvbuff */
658 /* Save connection address */
659 transport_info->connection_address =
660 (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
662 tokenlen = next_offset - offset;
663 /* Save connection address */
664 transport_info->connection_address = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
667 proto_tree_add_item(sdp_connection_info_tree,
668 hf_connection_info_connection_address, tvb, offset,
670 if(next_offset != -1){
671 offset = next_offset + 1;
672 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
673 if( next_offset == -1){
674 tokenlen = -1; /* end of tvbuff */
676 tokenlen = next_offset - offset;
678 proto_tree_add_item(sdp_connection_info_tree,
679 hf_connection_info_ttl, tvb, offset, tokenlen, FALSE);
680 if(next_offset != -1){
681 offset = next_offset + 1;
682 proto_tree_add_item(sdp_connection_info_tree,
683 hf_connection_info_num_addr, tvb, offset, -1, FALSE);
689 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
690 proto_tree * sdp_bandwidth_tree;
691 gint offset, next_offset, tokenlen;
697 sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
699 /* find the modifier */
700 next_offset = tvb_find_guint8(tvb,offset,-1,':');
702 if( next_offset == -1)
705 tokenlen = next_offset - offset;
707 proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier, tvb, offset,
710 offset = next_offset + 1;
712 proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value, tvb, offset, -1,
716 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
717 proto_tree *sdp_time_tree;
718 gint offset,next_offset, tokenlen;
724 sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
727 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
728 if( next_offset == -1 )
731 tokenlen = next_offset - offset;
732 proto_tree_add_item(sdp_time_tree, hf_time_start, tvb, offset, tokenlen,
736 offset = next_offset + 1;
737 proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb, offset, -1, FALSE);
740 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
741 proto_tree *sdp_repeat_time_tree;
742 gint offset,next_offset, tokenlen;
748 sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
751 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
752 if( next_offset == -1 )
755 tokenlen = next_offset - offset;
756 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
757 offset, tokenlen, FALSE);
760 offset = next_offset + 1;
761 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
762 if( next_offset == -1 )
765 tokenlen = next_offset - offset;
766 proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
767 offset, tokenlen, FALSE);
771 offset = next_offset +1;
772 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
773 if(next_offset != -1){
774 tokenlen = next_offset - offset;
776 tokenlen = -1; /* end of tvbuff */
778 proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
779 tvb, offset, tokenlen, FALSE);
780 } while( next_offset != -1 );
784 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
785 proto_tree* sdp_timezone_tree;
786 gint offset, next_offset, tokenlen;
791 sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
794 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
795 if(next_offset == -1)
797 tokenlen = next_offset - offset;
799 proto_tree_add_item(sdp_timezone_tree, hf_timezone_time, tvb, offset,
801 offset = next_offset + 1;
802 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
803 if(next_offset != -1){
804 tokenlen = next_offset - offset;
806 tokenlen = -1; /* end of tvbuff */
808 proto_tree_add_item(sdp_timezone_tree, hf_timezone_offset, tvb, offset,
810 offset = next_offset + 1;
811 } while (next_offset != -1);
816 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
817 proto_tree *sdp_encryption_key_tree;
818 gint offset, next_offset, tokenlen;
824 sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
826 next_offset = tvb_find_guint8(tvb,offset,-1,':');
828 if(next_offset == -1)
831 tokenlen = next_offset - offset;
833 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
834 tvb, offset, tokenlen, FALSE);
836 offset = next_offset + 1;
837 proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
838 tvb, offset, -1, FALSE);
843 static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item * ti){
844 proto_tree *sdp_session_attribute_tree;
845 gint offset, next_offset, tokenlen;
852 sdp_session_attribute_tree = proto_item_add_subtree(ti,
853 ett_sdp_session_attribute);
855 next_offset = tvb_find_guint8(tvb,offset,-1,':');
857 if(next_offset == -1)
860 tokenlen = next_offset - offset;
862 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_field,
863 tvb, offset, tokenlen, FALSE);
865 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
867 offset = next_offset + 1;
869 if (strcmp((char*)field_name, "ipbcp") == 0) {
870 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"0123456789");
875 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
877 if (next_offset == -1)
880 tokenlen = next_offset - offset;
882 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_version,tvb,offset,tokenlen,FALSE);
884 offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
889 tokenlen = tvb_find_line_end(tvb,offset,-1, &next_offset, FALSE);
894 proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE);
897 proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value,
898 tvb, offset, -1, FALSE);
903 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti,
904 transport_info_t *transport_info){
905 proto_tree *sdp_media_tree;
906 gint offset, next_offset, tokenlen, index;
907 guint8 *media_format;
913 /* Re-initialise for a new media description */
914 msrp_transport_address_set = FALSE;
916 sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
918 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
920 if(next_offset == -1)
923 tokenlen = next_offset - offset;
925 proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, offset, tokenlen,
928 offset = next_offset + 1;
930 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
931 if(next_offset == -1)
933 tokenlen = next_offset - offset;
934 next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
936 if(next_offset != -1){
937 tokenlen = next_offset - offset;
939 transport_info->media_port[transport_info->media_count] = tvb_get_ephemeral_string(tvb, offset, tokenlen);
941 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
942 atoi((char*)tvb_get_string(tvb, offset, tokenlen)));
943 offset = next_offset + 1;
944 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
945 if(next_offset == -1)
947 tokenlen = next_offset - offset;
948 proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb, offset,
950 offset = next_offset + 1;
952 next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
954 if(next_offset == -1)
956 tokenlen = next_offset - offset;
958 transport_info->media_port[transport_info->media_count] = tvb_get_ephemeral_string(tvb, offset, tokenlen);
960 /* XXX Remember Port */
961 proto_tree_add_uint(sdp_media_tree, hf_media_port, tvb, offset, tokenlen,
962 atoi((char*)tvb_get_string(tvb, offset, tokenlen)));
963 offset = next_offset + 1;
966 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
968 if( next_offset == -1)
971 tokenlen = next_offset - offset;
972 /* Save port protocol */
973 transport_info->media_proto[transport_info->media_count] = tvb_get_ephemeral_string(tvb, offset, tokenlen);
975 /* XXX Remember Protocol */
976 proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb, offset, tokenlen,
980 offset = next_offset + 1;
981 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
983 if(next_offset == -1){
984 tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
986 break; /* Nothing more left */
988 tokenlen = next_offset - offset;
991 if (strcmp(transport_info->media_proto[transport_info->media_count],
993 media_format = tvb_get_ephemeral_string(tvb, offset, tokenlen);
994 proto_tree_add_string(sdp_media_tree, hf_media_format, tvb, offset,
995 tokenlen, val_to_str(atol((char*)media_format), rtp_payload_type_vals, "%u"));
996 index = transport_info->media[transport_info->media_count].pt_count;
997 transport_info->media[transport_info->media_count].pt[index] = atol((char*)media_format);
998 if (index < (SDP_MAX_RTP_PAYLOAD_TYPES-1))
999 transport_info->media[transport_info->media_count].pt_count++;
1001 proto_tree_add_item(sdp_media_tree, hf_media_format, tvb, offset,
1004 } while (next_offset != -1);
1006 /* Increase the count of media channels, but don't walk off the end
1008 if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
1009 transport_info->media_count++;
1012 /* XXX Dissect traffic to "Port" as "Protocol"
1013 * Remember this Port/Protocol pair so we can tear it down again later
1014 * Actually, it's harder than that:
1015 * We need to find out the address of the other side first and it
1016 * looks like that info can be found in SIP headers only.
1022 14496-2, Annex G, Table G-1.
1023 Table G-1 FLC table for profile_and_level_indication Profile/Level Code
1025 static const value_string mpeg4es_level_indication_vals[] =
1028 { 1, "Simple Profile/Level 1" },
1029 { 2, "Simple Profile/Level 2" },
1035 { 8, "Simple Profile/Level 0" },
1036 { 9, "Simple Profile/Level 0b" },
1037 /* Reserved 00001001 - 00010000 */
1038 { 0x11, "Simple Scalable Profile/Level 1" },
1039 { 0x12, "Simple Scalable Profile/Level 2" },
1040 /* Reserved 00010011 - 00100000 */
1041 { 0x21, "Core Profile/Level 1" },
1042 { 0x22, "Core Profile/Level 2" },
1043 /* Reserved 00100011 - 00110001 */
1044 { 0x32, "Main Profile/Level 2" },
1045 { 0x33, "Main Profile/Level 3" },
1046 { 0x34, "Main Profile/Level 4" },
1047 /* Reserved 00110101 - 01000001 */
1048 { 0x42, "N-bit Profile/Level 2" },
1049 /* Reserved 01000011 - 01010000 */
1050 { 0x51, "Scalable Texture Profile/Level 1" },
1051 /* Reserved 01010010 - 01100000 */
1052 { 0x61, "Simple Face Animation Profile/Level 1" },
1053 { 0x62, "Simple Face Animation Profile/Level 2" },
1054 { 0x63, "Simple FBA Profile/Level 1" },
1055 { 0x64, "Simple FBA Profile/Level 2" },
1056 /* Reserved 01100101 - 01110000 */
1057 { 0x71, "Basic Animated Texture Profile/Level 1" },
1058 { 0x72, "Basic Animated Texture Profile/Level 2" },
1059 /* Reserved 01110011 - 10000000 */
1060 { 0x81, "Hybrid Profile/Level 1" },
1061 { 0x82, "Hybrid Profile/Level 2" },
1062 /* Reserved 10000011 - 10010000 */
1063 { 0x91, "Advanced Real Time Simple Profile/Level 1" },
1064 { 0x92, "Advanced Real Time Simple Profile/Level 2" },
1065 { 0x93, "Advanced Real Time Simple Profile/Level 3" },
1066 { 0x94, "Advanced Real Time Simple Profile/Level 4" },
1067 /* Reserved 10010101 - 10100000 */
1068 { 0xa1, "Core Scalable Profile/Level 1" },
1069 { 0xa2, "Core Scalable Profile/Level 2" },
1070 { 0xa3, "Core Scalable Profile/Level 3" },
1071 /* Reserved 10100100 - 10110000 */
1072 { 0xb1, "Advanced Coding Efficiency Profile/Level 1" },
1073 { 0xb2, "Advanced Coding Efficiency Profile/Level 2" },
1074 { 0xb3, "Advanced Coding Efficiency Profile/Level 3" },
1075 { 0xb4, "Advanced Coding Efficiency Profile/Level 4" },
1076 /* Reserved 10110101 - 11000000 */
1077 { 0xc1, "Advanced Core Profile/Level 1" },
1078 { 0xc2, "Advanced Core Profile/Level 2" },
1079 /* Reserved 11000011 - 11010000 */
1080 { 0xd1, "Advanced Scalable Texture/Level 1" },
1081 { 0xd2, "Advanced Scalable Texture/Level 2" },
1082 { 0xd3, "Advanced Scalable Texture/Level 3" },
1083 /* Reserved 11010100 - 11100000 */
1084 { 0xe1, "Simple Studio Profile/Level 1" },
1085 { 0xe2, "Simple Studio Profile/Level 2" },
1086 { 0xe3, "Simple Studio Profile/Level 3" },
1087 { 0xe4, "Simple Studio Profile/Level 4" },
1088 { 0xe5, "Core Studio Profile/Level 1" },
1089 { 0xe6, "Core Studio Profile/Level 2" },
1090 { 0xe7, "Core Studio Profile/Level 3" },
1091 { 0xe8, "Core Studio Profile/Level 4" },
1092 /* Reserved 11101001 - 11101111 */
1093 { 0xf0, "Advanced Simple Profile/Level 0" },
1094 { 0xf1, "Advanced Simple Profile/Level 1" },
1095 { 0xf2, "Advanced Simple Profile/Level 2" },
1096 { 0xf3, "Advanced Simple Profile/Level 3" },
1097 { 0xf4, "Advanced Simple Profile/Level 4" },
1098 { 0xf5, "Advanced Simple Profile/Level 5" },
1099 /* Reserved 11110110 - 11110111 */
1100 { 0xf8, "Fine Granularity Scalable Profile/Level 0" },
1101 { 0xf9, "Fine Granularity Scalable Profile/Level 1" },
1102 { 0xfa, "Fine Granularity Scalable Profile/Level 2" },
1103 { 0xfb, "Fine Granularity Scalable Profile/Level 3" },
1104 { 0xfc, "Fine Granularity Scalable Profile/Level 4" },
1105 { 0xfd, "Fine Granularity Scalable Profile/Level 5" },
1106 { 0xfe, "Reserved" },
1107 { 0xff, "Reserved for Escape" },
1111 * TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
1114 decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, gint offset, gint tokenlen, guint8 *mime_type){
1118 guint8 *format_specific_parameter;
1121 end_offset = offset + tokenlen;
1123 /* Look for an '=' within this value - this may indicate that there is a
1124 profile-level-id parameter to find if the MPEG4 media type is in use */
1125 next_offset = tvb_find_guint8(tvb,offset,-1,'=');
1126 if (next_offset == -1)
1128 /* Give up (and avoid exception) if '=' not found */
1132 /* Find the name of the parameter */
1133 tokenlen = next_offset - offset;
1134 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1136 offset = next_offset;
1138 /* Dissect the MPEG4 profile-level-id parameter if present */
1139 if (mime_type != NULL && strcmp((char*)mime_type, "MP4V-ES") == 0) {
1140 if (strcmp((char*)field_name, "profile-level-id") == 0) {
1142 tokenlen = end_offset - offset;
1143 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1144 item = proto_tree_add_uint(tree, hf_sdp_fmtp_profile_level_id, tvb, offset, tokenlen,
1145 atol((char*)format_specific_parameter));
1146 PROTO_ITEM_SET_GENERATED(item);
1150 /* TODO: Add code to dissect H264 fmtp parameters wehen an example can be found */
1151 if (mime_type != NULL && strcmp(mime_type, "H264") == 0) {
1152 if (strcmp(field_name, "profile-level-id") == 0) {
1156 tokenlen = end_offset - offset;
1157 format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1158 proto_tree_add_text(tree, tvb, offset, tokenlen,
1159 "Test %u", strtoul(format_specific_parameter, endptr, 16));
1165 static void dissect_sdp_media_attribute(tvbuff_t *tvb, proto_item * ti, transport_info_t *transport_info){
1166 proto_tree *sdp_media_attribute_tree;
1167 gint offset, next_offset, tokenlen, n;
1169 guint8 *payload_type;
1170 guint8 *attribute_value;
1177 /* Create attribute tree */
1178 sdp_media_attribute_tree = proto_item_add_subtree(ti,
1179 ett_sdp_media_attribute);
1180 /* Find end of field */
1181 next_offset = tvb_find_guint8(tvb,offset,-1,':');
1183 if(next_offset == -1)
1186 /* Attribute field name is token before ':' */
1187 tokenlen = next_offset - offset;
1188 proto_tree_add_item(sdp_media_attribute_tree,
1189 hf_media_attribute_field,
1190 tvb, offset, tokenlen, FALSE);
1191 field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1194 offset = next_offset + 1;
1196 /* Value is the remainder of the line */
1197 attribute_value = tvb_get_string(tvb, offset, tvb_length_remaining(tvb, offset));
1200 /*********************************************/
1201 /* Special parsing for some field name types */
1203 /* decode the rtpmap to see if it is DynamicPayload to dissect them automatic */
1204 if (strcmp((char*)field_name, "rtpmap") == 0) {
1206 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1208 if(next_offset == -1)
1211 tokenlen = next_offset - offset;
1213 proto_tree_add_item(sdp_media_attribute_tree, hf_media_format, tvb,
1214 offset, tokenlen, FALSE);
1216 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1218 offset = next_offset + 1;
1220 next_offset = tvb_find_guint8(tvb,offset,-1,'/');
1222 if(next_offset == -1){
1226 tokenlen = next_offset - offset;
1228 proto_tree_add_item(sdp_media_attribute_tree, hf_media_encoding_name, tvb,
1229 offset, tokenlen, FALSE);
1230 /* get_string is needed here as the string is "saved" in a hashtable */
1231 transport_info->encoding_name = tvb_get_string(tvb, offset,
1234 key=g_malloc( sizeof(gint) );
1235 *key=atol((char*)payload_type);
1237 /* As per RFC2327 it is possible to have multiple Media Descriptions ("m=").
1240 a=rtpmap:101 G726-32/8000
1241 m=audio 49170 RTP/AVP 0 97
1242 a=rtpmap:97 telephone-event/8000
1243 m=audio 49172 RTP/AVP 97 101
1244 a=rtpmap:97 G726-24/8000
1246 The Media attributes ("a="s) after the "m=" only apply for that "m=".
1247 If there is an "a=" before the first "m=", that attribute applies for
1248 all the session (all the "m="s).
1251 /* so, if this "a=" appear before any "m=", we add it to all the dynamic
1253 if (transport_info->media_count == 0) {
1254 for (n=0; n < SDP_MAX_RTP_CHANNELS; n++) {
1256 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1257 key, transport_info->encoding_name);
1258 else { /* we create a new key and encoding_name to assign to the other hash tables */
1260 key2=g_malloc( sizeof(gint) );
1261 *key2=atol((char*)payload_type);
1262 g_hash_table_insert(transport_info->media[n].rtp_dyn_payload,
1263 key2, transport_info->encoding_name);
1268 /* if the "a=" is after an "m=", only apply to this "m=" */
1270 /* in case there is an overflow in SDP_MAX_RTP_CHANNELS, we keep always the last "m=" */
1271 if (transport_info->media_count == SDP_MAX_RTP_CHANNELS-1)
1272 g_hash_table_insert(transport_info->media[ transport_info->media_count ].rtp_dyn_payload,
1273 key, transport_info->encoding_name);
1275 g_hash_table_insert(transport_info->media[ transport_info->media_count-1 ].rtp_dyn_payload,
1276 key, transport_info->encoding_name);
1281 if (strcmp((char*)field_name, "fmtp") == 0) {
1282 proto_item *fmtp_item, *media_format_item;
1283 proto_tree *fmtp_tree;
1285 next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1287 if(next_offset == -1)
1290 tokenlen = next_offset - offset;
1292 /* Media format extends to the next space */
1293 media_format_item = proto_tree_add_item(sdp_media_attribute_tree,
1294 hf_media_format, tvb, offset,
1296 /* Append encoding name to format if known */
1297 if (transport_info->encoding_name)
1298 proto_item_append_text(media_format_item, " [%s]",
1299 transport_info->encoding_name);
1301 payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1303 offset = next_offset + 1;
1305 /* There may be 2 parameters given
1306 * TODO: Handle arbitary number of parameters.
1308 next_offset = tvb_find_guint8(tvb,offset,-1,';');
1310 if(next_offset != -1){
1311 /* There are 2 - add the first parameter */
1312 tokenlen = next_offset - offset;
1313 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1314 hf_media_format_specific_parameter, tvb,
1315 offset, tokenlen, FALSE);
1317 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1319 decode_sdp_fmtp(fmtp_tree, tvb, offset, tokenlen,
1320 (guint8 *)transport_info->encoding_name);
1322 offset = next_offset + 1;
1325 /* Now add remaining (or only) parameter */
1326 tokenlen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1328 fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1329 hf_media_format_specific_parameter, tvb,
1330 offset, tokenlen, FALSE);
1332 fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1334 decode_sdp_fmtp(fmtp_tree, tvb, offset, tokenlen,
1335 (guint8 *)transport_info->encoding_name);
1339 /* msrp attributes that contain address needed for conversation */
1340 if (strcmp((char*)field_name, "path") == 0) {
1341 const char *msrp_res = "msrp://";
1342 if (strncmp((char*)attribute_value, msrp_res, strlen(msrp_res)) == 0){
1343 int address_offset, port_offset, port_end_offset;
1345 /* Address starts here */
1346 address_offset = offset + strlen(msrp_res);
1348 /* Port is after next ':' */
1349 port_offset = tvb_find_guint8(tvb, address_offset, -1, ':');
1351 /* Port ends with '/' */
1352 port_end_offset = tvb_find_guint8(tvb, port_offset, -1, '/');
1354 /* Attempt to convert address */
1355 if (inet_pton(AF_INET, (char*)tvb_get_ephemeral_string(tvb, address_offset, port_offset-address_offset), &msrp_ipaddr) > 0) {
1356 /* Get port number */
1357 msrp_port_number = atoi((char*)tvb_get_ephemeral_string(tvb, port_offset+1, port_end_offset-port_offset-1));
1359 /* Set flag so this info can be used */
1360 msrp_transport_address_set = TRUE;
1366 /* No special treatment for values of this attribute type, just add as one item. */
1367 proto_tree_add_item(sdp_media_attribute_tree, hf_media_attribute_value,
1368 tvb, offset, -1, FALSE);
1372 proto_register_sdp(void)
1374 static hf_register_info hf[] = {
1375 { &hf_protocol_version,
1376 { "Session Description Protocol Version (v)",
1377 "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
1378 "Session Description Protocol Version", HFILL }},
1380 { "Owner/Creator, Session Id (o)",
1381 "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
1382 "Owner/Creator, Session Id", HFILL}},
1384 { "Session Name (s)",
1385 "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
1386 "Session Name", HFILL }},
1388 { "Session Information (i)",
1389 "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
1390 "Session Information", HFILL }},
1392 { "URI of Description (u)",
1393 "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
1394 "URI of Description", HFILL }},
1396 { "E-mail Address (e)",
1397 "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
1398 "E-mail Address", HFILL }},
1400 { "Phone Number (p)",
1401 "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
1402 "Phone Number", HFILL }},
1403 { &hf_connection_info,
1404 { "Connection Information (c)",
1405 "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
1406 "Connection Information", HFILL }},
1408 { "Bandwidth Information (b)",
1409 "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
1410 "Bandwidth Information", HFILL }},
1412 { "Time Zone Adjustments (z)",
1413 "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
1414 "Time Zone Adjustments", HFILL }},
1415 { &hf_encryption_key,
1416 { "Encryption Key (k)",
1417 "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
1418 "Encryption Key", HFILL }},
1419 { &hf_session_attribute,
1420 { "Session Attribute (a)",
1421 "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1422 "Session Attribute", HFILL }},
1423 { &hf_media_attribute,
1424 { "Media Attribute (a)",
1425 "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
1426 "Media Attribute", HFILL }},
1428 { "Time Description, active time (t)",
1429 "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
1430 "Time Description, active time", HFILL }},
1432 { "Repeat Time (r)",
1433 "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
1434 "Repeat Time", HFILL }},
1436 { "Media Description, name and address (m)",
1437 "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
1438 "Media Description, name and address", HFILL }},
1440 { "Media Title (i)",
1441 "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
1442 "Media Title", HFILL }},
1445 "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
1446 "Unknown", HFILL }},
1449 "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
1450 "Invalid line", HFILL }},
1451 { &hf_owner_username,
1453 "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
1454 "Owner Username", HFILL }},
1455 { &hf_owner_sessionid,
1457 "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
1458 "Session ID", HFILL }},
1459 { &hf_owner_version,
1460 { "Session Version",
1461 "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
1462 "Session Version", HFILL }},
1463 { &hf_owner_network_type,
1464 { "Owner Network Type",
1465 "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1466 "Owner Network Type", HFILL }},
1467 { &hf_owner_address_type,
1468 { "Owner Address Type",
1469 "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1470 "Owner Address Type", HFILL }},
1471 { &hf_owner_address,
1473 "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
1474 "Owner Address", HFILL }},
1475 { &hf_connection_info_network_type,
1476 { "Connection Network Type",
1477 "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
1478 "Connection Network Type", HFILL }},
1479 { &hf_connection_info_address_type,
1480 { "Connection Address Type",
1481 "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
1482 "Connection Address Type", HFILL }},
1483 { &hf_connection_info_connection_address,
1484 { "Connection Address",
1485 "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
1486 "Connection Address", HFILL }},
1487 { &hf_connection_info_ttl,
1489 "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
1490 "Connection TTL", HFILL }},
1491 { &hf_connection_info_num_addr,
1492 { "Connection Number of Addresses",
1493 "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
1494 "Connection Number of Addresses", HFILL }},
1495 { &hf_bandwidth_modifier,
1496 { "Bandwidth Modifier",
1497 "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
1498 "Bandwidth Modifier", HFILL }},
1499 { &hf_bandwidth_value,
1500 { "Bandwidth Value",
1501 "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
1502 "Bandwidth Value (in kbits/s)", HFILL }},
1504 { "Session Start Time",
1505 "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
1506 "Session Start Time", HFILL }},
1508 { "Session Stop Time",
1509 "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
1510 "Session Stop Time", HFILL }},
1511 { &hf_repeat_time_interval,
1512 { "Repeat Interval",
1513 "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
1514 "Repeat Interval", HFILL }},
1515 { &hf_repeat_time_duration,
1516 { "Repeat Duration",
1517 "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
1518 "Repeat Duration", HFILL }},
1519 { &hf_repeat_time_offset,
1521 "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1522 "Repeat Offset", HFILL }},
1523 { &hf_timezone_time,
1525 "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
1526 "Timezone Time", HFILL }},
1527 { &hf_timezone_offset,
1528 { "Timezone Offset",
1529 "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1530 "Timezone Offset", HFILL }},
1531 { &hf_encryption_key_type,
1533 "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
1535 { &hf_encryption_key_data,
1537 "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
1539 { &hf_session_attribute_field,
1540 { "Session Attribute Fieldname",
1541 "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
1542 "Session Attribute Fieldname", HFILL }},
1543 { &hf_session_attribute_value,
1544 { "Session Attribute Value",
1545 "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
1546 "Session Attribute Value", HFILL }},
1549 "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
1550 "Media Type", HFILL }},
1553 "sdp.media.port",FT_UINT16, BASE_DEC, NULL, 0x0,
1554 "Media Port", HFILL }},
1555 { &hf_media_portcount,
1556 { "Media Port Count",
1557 "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
1558 "Media Port Count", HFILL }},
1561 "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
1562 "Media Protocol", HFILL }},
1565 "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
1566 "Media Format", HFILL }},
1567 { &hf_media_attribute_field,
1568 { "Media Attribute Fieldname",
1569 "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
1570 "Media Attribute Fieldname", HFILL }},
1571 { &hf_media_attribute_value,
1572 { "Media Attribute Value",
1573 "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
1574 "Media Attribute Value", HFILL }},
1575 { &hf_media_encoding_name,
1577 "sdp.mime.type",FT_STRING, BASE_NONE, NULL, 0x0,
1578 "SDP MIME Type", HFILL }},
1579 { &hf_media_format_specific_parameter,
1580 { "Media format specific parameters",
1581 "sdp.fmtp.parameter",FT_STRING, BASE_NONE, NULL, 0x0,
1582 "Format specific parameter(fmtp)", HFILL }},
1583 { &hf_ipbcp_version,
1584 { "IPBCP Protocol Version",
1585 "ipbcp.version",FT_STRING, BASE_NONE, NULL, 0x0,
1586 "IPBCP Protocol Version", HFILL }},
1588 { "IPBCP Command Type",
1589 "ipbcp.command",FT_STRING, BASE_NONE, NULL, 0x0,
1590 "IPBCP Command Type", HFILL }},
1591 {&hf_sdp_fmtp_profile_level_id,
1593 "sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mpeg4es_level_indication_vals), 0x0,
1594 "Level Code", HFILL }},
1596 static gint *ett[] = {
1599 &ett_sdp_connection_info,
1602 &ett_sdp_repeat_time,
1604 &ett_sdp_encryption_key,
1605 &ett_sdp_session_attribute,
1607 &ett_sdp_media_attribute,
1611 module_t *sdp_module;
1613 proto_sdp = proto_register_protocol("Session Description Protocol",
1615 proto_register_field_array(proto_sdp, hf, array_length(hf));
1616 proto_register_subtree_array(ett, array_length(ett));
1619 * Preferences registration
1621 sdp_module = prefs_register_protocol(proto_sdp, NULL);
1622 prefs_register_bool_preference(sdp_module, "establish_conversation",
1623 "Establish Media Conversation",
1624 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
1625 "upon port numbers found in SIP/SDP payload",
1626 &global_sdp_establish_conversation);
1629 * Register the dissector by name, so other dissectors can
1630 * grab it by name rather than just referring to it directly.
1632 register_dissector("sdp", dissect_sdp, proto_sdp);
1634 /* Register for tapping */
1635 sdp_tap = register_tap("sdp");
1639 proto_reg_handoff_sdp(void)
1641 dissector_handle_t sdp_handle;
1643 rtp_handle = find_dissector("rtp");
1644 rtcp_handle = find_dissector("rtcp");
1645 msrp_handle = find_dissector("msrp");
1646 t38_handle = find_dissector("t38");
1648 sdp_handle = find_dissector("sdp");
1649 dissector_add_string("media_type", "application/sdp", sdp_handle);