More warnings
[obnox/wireshark/wip.git] / epan / dissectors / packet-sdp.c
1 /* packet-sdp.c
2  * Routines for SDP packet disassembly (RFC 2327)
3  *
4  * Jason Lango <jal@netapp.com>
5  * Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
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.
17  *
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.
22  *
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  */
27
28 #include "config.h"
29
30 #include <string.h>
31 #include <ctype.h>
32
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 # include <netinet/in.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43
44 #ifdef HAVE_WINSOCK2_H
45 #include <winsock2.h>           /* needed to define AF_ values on Windows */
46 #endif
47
48 #ifdef NEED_INET_V6DEFS_H
49 # include "inet_v6defs.h"
50 #endif
51
52 #include <glib.h> 
53 #include <epan/packet.h>
54 #include <epan/conversation.h>
55 #include <epan/strutil.h>
56 #include <epan/emem.h>
57
58 #include "tap.h"
59 #include "packet-sdp.h"
60
61 #include "packet-rtp.h"
62 #include <epan/rtp_pt.h>
63
64 #include <epan/prefs.h>
65
66 #include "packet-rtcp.h"
67 #include "packet-t38.h"
68 #include "packet-msrp.h"
69
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;
74
75 static int sdp_tap = -1;
76
77 static int proto_sdp = -1;
78
79 /* preference globals */
80 static gboolean global_sdp_establish_conversation = TRUE;
81
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;
104
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;
112
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;
119
120 /* hf_bandwidth subfields */
121 static int hf_bandwidth_modifier = -1;
122 static int hf_bandwidth_value = -1;
123
124 /* hf_time subfields */
125 static int hf_time_start = -1;
126 static int hf_time_stop = -1;
127
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;
132
133 /* hf_timezone subfields */
134 static int hf_timezone_time = -1;
135 static int hf_timezone_offset = -1;
136
137 /* hf_encryption_key subfields */
138 static int hf_encryption_key_type = -1;
139 static int hf_encryption_key_data = -1;
140
141 /* hf_session_attribute subfields */
142 static int hf_session_attribute_field = -1;
143 static int hf_session_attribute_value = -1;
144
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;
151
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;
158
159 /* trees */
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;
172
173
174 #define SDP_MAX_RTP_CHANNELS 4
175 #define SDP_MAX_RTP_PAYLOAD_TYPES 20
176
177 typedef struct {
178   gint32 pt[SDP_MAX_RTP_PAYLOAD_TYPES];
179   gint8 pt_count;
180   GHashTable *rtp_dyn_payload;
181 } transport_media_pt_t;
182
183 typedef struct {
184   char *connection_address;
185   char *connection_type;
186   char *encoding_name;
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];
190   gint8 media_count;
191 } transport_info_t;
192
193
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;
198
199
200 /* Protocol registration */
201 void proto_register_sdp(void);
202 void proto_reg_handoff_sdp(void);
203
204
205 /* static functions */
206
207 static void call_sdp_subdissector(tvbuff_t *tvb, int hf, proto_tree* ti,
208                                   transport_info_t *transport_info);
209
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);
223
224 static void
225 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
226 {
227   proto_tree  *sdp_tree;
228   proto_item  *ti, *sub_ti;
229   gint        offset = 0;
230   gint        next_offset;
231   int         linelen;
232   gboolean    in_media_description;
233   guchar      type;
234   guchar      delim;
235   int         datalen;
236   int         tokenoffset;
237   int         hf = -1;
238   char        *string;
239
240   address     src_addr;
241
242   transport_info_t transport_info;
243
244   guint32     port=0;
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;
251   guint32     ipaddr[4];
252   gint        n,i;
253   sdp_packet_info *sdp_pi;
254
255   /* Initialise packet info for passing to tap */
256   sdp_pi = ep_alloc(sizeof(sdp_packet_info));
257   sdp_pi->summary_str[0] = '\0';
258
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++)
264   {
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);
269   }
270   transport_info.media_count = 0;
271
272   /*
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."
280    *
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
284    * put there.
285    */
286   if (check_col(pinfo->cinfo, COL_PROTOCOL))
287     col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
288
289   if (check_col(pinfo->cinfo, COL_INFO)) {
290     /* XXX: Needs description. */
291     col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
292   }
293
294   ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
295   sdp_tree = proto_item_add_subtree(ti, ett_sdp);
296
297   /*
298    * Show the SDP message a line at a time.
299    */
300   in_media_description = FALSE;
301   while (tvb_reported_length_remaining(tvb, offset) > 0) {
302     /*
303      * Find the end of the line.
304      */
305     linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
306
307     /*
308      * Line must contain at least e.g. "v=".
309      */
310     if (linelen < 2)
311       break;
312
313     type = tvb_get_guint8(tvb,offset);
314     delim = tvb_get_guint8(tvb,offset + 1);
315     if (delim != '=') {
316       proto_tree_add_item(sdp_tree, hf_invalid, tvb, offset, linelen, FALSE);
317       offset = next_offset;
318       continue;
319     }
320
321     /*
322      * Attributes.
323      */
324     switch (type) {
325     case 'v':
326       hf = hf_protocol_version;
327       break;
328     case 'o':
329       hf = hf_owner;
330       break;
331     case 's':
332       hf = hf_session_name;
333       break;
334     case 'i':
335       if (in_media_description) {
336         hf = hf_media_title;
337       }
338       else{
339         hf = hf_session_info;
340       }
341       break;
342     case 'u':
343       hf = hf_uri;
344       break;
345     case 'e':
346       hf = hf_email;
347       break;
348     case 'p':
349       hf = hf_phone;
350       break;
351     case 'c':
352       hf = hf_connection_info;
353       break;
354     case 'b':
355       hf = hf_bandwidth;
356       break;
357     case 't':
358       hf = hf_time;
359       break;
360     case 'r':
361       hf = hf_repeat_time;
362       break;
363     case 'm':
364       hf = hf_media;
365       in_media_description = TRUE;
366       break;
367     case 'k':
368       hf = hf_encryption_key;
369       break;
370     case 'a':
371       if (in_media_description) {
372         hf = hf_media_attribute;
373       }
374       else{
375         hf = hf_session_attribute;
376       }
377       break;
378     case 'z':
379       hf = hf_timezone;
380       break;
381     default:
382       hf = hf_unknown;
383       break;
384     }
385     tokenoffset = 2;
386     if (hf == hf_unknown)
387       tokenoffset = 0;
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,
391                                    string);
392     call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
393                                          linelen-tokenoffset,
394                                          linelen-tokenoffset),
395                           hf,sub_ti,&transport_info),
396     offset = next_offset;
397   }
398
399
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!
404    */
405
406   for (n = 0; n < transport_info.media_count; n++)
407   {
408     if(transport_info.media_port[n]!=NULL) {
409       port = atol(transport_info.media_port[n]);
410     }
411     if(transport_info.media_proto[n]!=NULL) {
412       /* Check if media protocol is RTP
413        * and stream decoding is enabled in preferences 
414        */
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);
422        }
423     }
424     
425
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*/
431             is_ipv4_addr=TRUE;
432             src_addr.type=AT_IPv4;
433             src_addr.len=4;
434           }
435         }
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*/
439             is_ipv6_addr=TRUE;
440             src_addr.type=AT_IPv6;
441             src_addr.len=16;
442           }
443         }
444       }
445     }
446     set_rtp = FALSE;
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;
450       if(rtp_handle){
451         rtp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num,
452                         transport_info.media[n].rtp_dyn_payload);
453         set_rtp = TRUE;
454       }
455       if(rtcp_handle){
456         port++;
457         rtcp_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
458       }
459     }
460
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;
464       if(t38_handle){
465         t38_add_address(pinfo, &src_addr, port, 0, "SDP", pinfo->fd->num);
466       }
467     }
468
469     /* Add MSRP conversation.  Uses addresses discovered in attribute
470        rather than connection information of media session line */
471     if (is_msrp ){
472         if ((!pinfo->fd->flags.visited) && msrp_transport_address_set){
473             if(msrp_handle){
474                 src_addr.type=AT_IPv4;
475                 src_addr.len=4;
476                 src_addr.data=(char *)&msrp_ipaddr;
477                 msrp_add_address(pinfo, &src_addr, msrp_port_number, "SDP", pinfo->fd->num);
478             }
479         }
480     }
481
482     /* Create the RTP summary str for the Voip Call analysis */
483     for (i = 0; i < transport_info.media[n].pt_count; i++)
484     {
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]);
488         if (str_dyn_pt)
489           g_snprintf(sdp_pi->summary_str, 50, "%s %s", sdp_pi->summary_str, str_dyn_pt);
490         else
491           g_snprintf(sdp_pi->summary_str, 50, "%s %d", sdp_pi->summary_str, transport_info.media[n].pt[i]);
492       } else 
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"));
494     }
495
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);
499
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);  
502   }
503
504   /* Free the remainded hash tables not used */
505   for (n = transport_info.media_count; n < SDP_MAX_RTP_CHANNELS; n++)
506   {
507     rtp_free_hash_dyn_payload(transport_info.media[n].rtp_dyn_payload);
508   }
509
510
511   datalen = tvb_length_remaining(tvb, offset);
512   if (datalen > 0) {
513     proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)",
514                         datalen);
515   }
516
517   /* Report this packet to the tap */
518   tap_queue_packet(sdp_tap, pinfo, sdp_pi);
519 }
520
521 static void
522 call_sdp_subdissector(tvbuff_t *tvb, int hf, proto_tree* ti, transport_info_t *transport_info){
523   if(hf == hf_owner){
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);
543   }
544 }
545
546 static void
547 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
548   proto_tree *sdp_owner_tree;
549   gint offset,next_offset,tokenlen;
550
551   offset = 0;
552   next_offset = 0;
553   tokenlen = 0;
554
555   sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
556
557   /* Find the username */
558   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
559   if( next_offset == -1 )
560     return;
561   tokenlen = next_offset - offset;
562
563   proto_tree_add_item(sdp_owner_tree, hf_owner_username, tvb, offset, tokenlen,
564                       FALSE);
565   offset = next_offset  + 1;
566
567   /* Find the session id */
568   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
569   if( next_offset == -1 )
570     return;
571   tokenlen = next_offset - offset;
572
573   proto_tree_add_item(sdp_owner_tree, hf_owner_sessionid, tvb, offset,
574                       tokenlen, FALSE);
575   offset = next_offset + 1;
576
577   /* Find the version */
578   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
579   if( next_offset == -1 )
580     return;
581   tokenlen = next_offset - offset;
582
583   proto_tree_add_item(sdp_owner_tree, hf_owner_version, tvb, offset, tokenlen,
584                       FALSE);
585   offset = next_offset + 1;
586
587   /* Find the network type */
588   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
589   if( next_offset == -1 )
590     return;
591   tokenlen = next_offset - offset;
592
593   proto_tree_add_item(sdp_owner_tree, hf_owner_network_type, tvb, offset,
594                       tokenlen, FALSE);
595   offset = next_offset + 1;
596
597   /* Find the address type */
598   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
599   if( next_offset == -1 )
600     return;
601   tokenlen = next_offset - offset;
602
603   proto_tree_add_item(sdp_owner_tree, hf_owner_address_type, tvb, offset,
604                       tokenlen, FALSE);
605   offset = next_offset + 1;
606
607   /* Find the address */
608   proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
609 }
610
611 /*
612  * XXX - this can leak memory if an exception is thrown after we've fetched
613  * a string.
614  */
615 static void
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;
620
621   offset = 0;
622   next_offset = 0;
623   tokenlen = 0;
624
625   sdp_connection_info_tree = proto_item_add_subtree(ti,
626                                                     ett_sdp_connection_info);
627
628   /* Find the network type */
629   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
630   if( next_offset == -1 )
631     return;
632   tokenlen = next_offset - offset;
633
634   proto_tree_add_item(sdp_connection_info_tree,
635                       hf_connection_info_network_type, tvb, offset, tokenlen,
636                       FALSE);
637   offset = next_offset + 1;
638
639   /* Find the address type */
640   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
641   if( next_offset == -1 )
642     return;
643   tokenlen = next_offset - offset;
644   /* Save connection address type */
645   transport_info->connection_type = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
646
647
648   proto_tree_add_item(sdp_connection_info_tree,
649                       hf_connection_info_address_type, tvb, offset, tokenlen,
650                       FALSE);
651   offset = next_offset + 1;
652
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));
661   } else {
662     tokenlen = next_offset - offset;
663     /* Save connection address */
664     transport_info->connection_address = (char*)tvb_get_ephemeral_string(tvb, offset, tokenlen);
665   }
666
667   proto_tree_add_item(sdp_connection_info_tree,
668                       hf_connection_info_connection_address, tvb, offset,
669                       tokenlen, FALSE);
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 */
675     } else {
676       tokenlen = next_offset - offset;
677     }
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);
684     }
685   }
686 }
687
688 static void
689 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
690   proto_tree * sdp_bandwidth_tree;
691   gint offset, next_offset, tokenlen;
692
693   offset = 0;
694   next_offset = 0;
695   tokenlen = 0;
696
697   sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
698
699   /* find the modifier */
700   next_offset = tvb_find_guint8(tvb,offset,-1,':');
701
702   if( next_offset == -1)
703     return;
704
705   tokenlen = next_offset - offset;
706
707   proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier, tvb, offset,
708                       tokenlen, FALSE);
709
710   offset = next_offset + 1;
711
712   proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value, tvb, offset, -1,
713                       FALSE);
714 }
715
716 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
717   proto_tree *sdp_time_tree;
718   gint offset,next_offset, tokenlen;
719
720   offset = 0;
721   next_offset = 0;
722   tokenlen = 0;
723
724   sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
725
726   /* get start time */
727   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
728   if( next_offset == -1 )
729     return;
730
731   tokenlen = next_offset - offset;
732   proto_tree_add_item(sdp_time_tree, hf_time_start, tvb, offset, tokenlen,
733                       FALSE);
734
735   /* get stop time */
736   offset = next_offset + 1;
737   proto_tree_add_item(sdp_time_tree, hf_time_stop, tvb, offset, -1, FALSE);
738 }
739
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;
743
744   offset = 0;
745   next_offset = 0;
746   tokenlen = 0;
747
748   sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
749
750   /* get interval */
751   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
752   if( next_offset == -1 )
753     return;
754
755   tokenlen = next_offset - offset;
756   proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
757                       offset, tokenlen, FALSE);
758
759   /* get duration */
760   offset = next_offset + 1;
761   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
762   if( next_offset == -1 )
763     return;
764
765   tokenlen = next_offset - offset;
766   proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
767                       offset, tokenlen, FALSE);
768
769   /* get offsets */
770   do{
771     offset = next_offset +1;
772     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
773     if(next_offset != -1){
774       tokenlen = next_offset - offset;
775     } else {
776       tokenlen = -1; /* end of tvbuff */
777     }
778     proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
779                         tvb, offset, tokenlen, FALSE);
780   } while( next_offset != -1 );
781
782 }
783 static void
784 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
785   proto_tree* sdp_timezone_tree;
786   gint offset, next_offset, tokenlen;
787   offset = 0;
788   next_offset = 0;
789   tokenlen = 0;
790
791   sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
792
793   do{
794     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
795     if(next_offset == -1)
796       break;
797     tokenlen = next_offset - offset;
798
799     proto_tree_add_item(sdp_timezone_tree, hf_timezone_time, tvb, offset,
800                         tokenlen, FALSE);
801     offset = next_offset + 1;
802     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
803     if(next_offset != -1){
804       tokenlen = next_offset - offset;
805     } else {
806       tokenlen = -1; /* end of tvbuff */
807     }
808     proto_tree_add_item(sdp_timezone_tree, hf_timezone_offset, tvb, offset,
809                         tokenlen, FALSE);
810     offset = next_offset + 1;
811   } while (next_offset != -1);
812
813 }
814
815
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;
819
820   offset = 0;
821   next_offset = 0;
822   tokenlen = 0;
823
824   sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
825
826   next_offset = tvb_find_guint8(tvb,offset,-1,':');
827
828   if(next_offset == -1)
829     return;
830
831   tokenlen = next_offset - offset;
832
833   proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
834                       tvb, offset, tokenlen, FALSE);
835
836   offset = next_offset + 1;
837   proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
838                       tvb, offset, -1, FALSE);
839 }
840
841
842
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;
846   guint8 *field_name;
847   
848   offset = 0;
849   next_offset = 0;
850   tokenlen = 0;
851
852   sdp_session_attribute_tree = proto_item_add_subtree(ti,
853                                                       ett_sdp_session_attribute);
854
855   next_offset = tvb_find_guint8(tvb,offset,-1,':');
856
857   if(next_offset == -1)
858     return;
859
860   tokenlen = next_offset - offset;
861
862   proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_field,
863                       tvb, offset, tokenlen, FALSE);
864
865   field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
866   
867   offset = next_offset + 1;
868
869   if (strcmp((char*)field_name, "ipbcp") == 0) {
870     offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"0123456789");
871
872     if (offset == -1)
873       return;
874     
875     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
876     
877     if (next_offset == -1)
878       return;
879     
880     tokenlen = next_offset - offset;
881     
882     proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_version,tvb,offset,tokenlen,FALSE);
883
884     offset = tvb_pbrk_guint8(tvb,offset,-1,(guint8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
885
886     if (offset == -1)
887       return;
888
889     tokenlen = tvb_find_line_end(tvb,offset,-1, &next_offset, FALSE);
890     
891     if (tokenlen == -1) 
892       return;
893     
894     proto_tree_add_item(sdp_session_attribute_tree,hf_ipbcp_type,tvb,offset,tokenlen,FALSE);
895     
896   } else {
897     proto_tree_add_item(sdp_session_attribute_tree, hf_session_attribute_value,
898                         tvb, offset, -1, FALSE);
899   }
900 }
901
902 static void
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;
908
909   offset = 0;
910   next_offset = 0;
911   tokenlen = 0;
912
913   /* Re-initialise for a new media description */
914   msrp_transport_address_set = FALSE;
915
916   sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
917
918   next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
919
920   if(next_offset == -1)
921     return;
922
923   tokenlen = next_offset - offset;
924
925   proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, offset, tokenlen,
926                       FALSE);
927
928   offset = next_offset + 1;
929
930   next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
931   if(next_offset == -1)
932     return;
933   tokenlen = next_offset - offset;
934   next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
935
936   if(next_offset != -1){
937     tokenlen = next_offset - offset;
938     /* Save port info */
939     transport_info->media_port[transport_info->media_count] = tvb_get_ephemeral_string(tvb, offset, tokenlen);
940
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)
946       return;
947     tokenlen = next_offset - offset;
948     proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb, offset,
949                         tokenlen, FALSE);
950     offset = next_offset + 1;
951   } else {
952     next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
953
954     if(next_offset == -1)
955       return;
956     tokenlen = next_offset - offset;
957     /* Save port info */
958     transport_info->media_port[transport_info->media_count] = tvb_get_ephemeral_string(tvb, offset, tokenlen);
959
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;
964   }
965
966   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
967
968   if( next_offset == -1)
969     return;
970
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);
974
975   /* XXX Remember Protocol */
976   proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb, offset, tokenlen,
977                       FALSE);
978
979   do{
980     offset = next_offset + 1;
981     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
982
983     if(next_offset == -1){
984       tokenlen = tvb_length_remaining(tvb, offset); /* End of tvbuff */
985       if (tokenlen == 0)
986         break; /* Nothing more left */
987     } else {
988       tokenlen = next_offset - offset;
989     }
990     
991     if (strcmp(transport_info->media_proto[transport_info->media_count],
992                "RTP/AVP") == 0) {
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++;
1000     } else {
1001       proto_tree_add_item(sdp_media_tree, hf_media_format, tvb, offset,
1002                           tokenlen, FALSE);
1003     }
1004   } while (next_offset != -1);
1005
1006   /* Increase the count of media channels, but don't walk off the end
1007      of the arrays. */
1008   if (transport_info->media_count < (SDP_MAX_RTP_CHANNELS-1)){
1009     transport_info->media_count++;
1010   }
1011
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.
1017    */
1018
1019 }
1020
1021 /*
1022 14496-2, Annex G, Table G-1.
1023 Table G-1 FLC table for profile_and_level_indication Profile/Level Code 
1024 */
1025 static const value_string mpeg4es_level_indication_vals[] =
1026 {
1027   { 0,    "Reserved" },
1028   { 1,    "Simple Profile/Level 1" },
1029   { 2,    "Simple Profile/Level 2" },
1030   { 3,    "Reserved" },
1031   { 4,    "Reserved" },
1032   { 5,    "Reserved" },
1033   { 6,    "Reserved" },
1034   { 7,    "Reserved" },
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" },
1108   { 0, NULL },
1109 };
1110 /* 
1111  * TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
1112  */
1113 static void
1114 decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, gint offset, gint tokenlen, guint8 *mime_type){
1115   gint next_offset;
1116   gint end_offset;
1117   guint8 *field_name;
1118   guint8 *format_specific_parameter;
1119   proto_item *item;
1120
1121   end_offset = offset + tokenlen;
1122
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)
1127   {
1128     /* Give up (and avoid exception) if '=' not found */
1129     return;
1130   }
1131
1132   /* Find the name of the parameter */
1133   tokenlen = next_offset - offset;
1134   field_name = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1135
1136   offset = next_offset;
1137
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) {
1141       offset++;
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);
1147     }
1148   }
1149 #if 0
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) {
1153       char **endptr;
1154
1155       offset++;
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));
1160         }
1161   }
1162 #endif
1163 }
1164
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;
1168   guint8 *field_name;
1169   guint8 *payload_type;
1170   guint8 *attribute_value;
1171   gint   *key;
1172
1173   offset = 0;
1174   next_offset = 0;
1175   tokenlen = 0;
1176
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,':');
1182
1183   if(next_offset == -1)
1184     return;
1185
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);
1192
1193   /* Skip colon */
1194   offset = next_offset + 1;
1195
1196   /* Value is the remainder of the line */
1197   attribute_value = tvb_get_string(tvb, offset, tvb_length_remaining(tvb, offset));
1198
1199
1200   /*********************************************/
1201   /* Special parsing for some field name types */
1202   
1203   /* decode the rtpmap to see if it is DynamicPayload to dissect them automatic */
1204   if (strcmp((char*)field_name, "rtpmap") == 0) {
1205
1206     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1207
1208     if(next_offset == -1)
1209       return;
1210
1211     tokenlen = next_offset - offset;
1212
1213     proto_tree_add_item(sdp_media_attribute_tree, hf_media_format, tvb,
1214                         offset, tokenlen, FALSE);
1215
1216     payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1217
1218     offset = next_offset + 1;
1219
1220     next_offset = tvb_find_guint8(tvb,offset,-1,'/');
1221
1222     if(next_offset == -1){
1223         return;
1224     }
1225
1226     tokenlen = next_offset - offset;
1227
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,
1232                                                              tokenlen);
1233
1234     key=g_malloc( sizeof(gint) );
1235     *key=atol((char*)payload_type);
1236
1237     /* As per RFC2327 it is possible to have multiple Media Descriptions ("m=").
1238        For example:
1239
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
1245
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).
1249     */
1250
1251     /* so, if this "a=" appear before any "m=", we add it to all the dynamic
1252        hash tables */ 
1253     if (transport_info->media_count == 0) {
1254         for (n=0; n < SDP_MAX_RTP_CHANNELS; n++) {
1255             if (n==0)
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 */
1259                 gint *key2;
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);
1264             }
1265         }
1266         return;
1267
1268     /* if the "a=" is after an "m=", only apply to this "m=" */
1269     } else 
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);
1274         else
1275             g_hash_table_insert(transport_info->media[ transport_info->media_count-1 ].rtp_dyn_payload,
1276                                 key, transport_info->encoding_name);
1277
1278         return;
1279   }
1280
1281   if (strcmp((char*)field_name, "fmtp") == 0) {
1282     proto_item *fmtp_item, *media_format_item;
1283     proto_tree *fmtp_tree;
1284
1285     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
1286
1287     if(next_offset == -1)
1288       return;
1289
1290     tokenlen = next_offset - offset;
1291
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,
1295                                             tokenlen, FALSE);
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);
1300
1301     payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
1302
1303     offset = next_offset + 1;
1304
1305     /* There may be 2 parameters given
1306      * TODO: Handle arbitary number of parameters.
1307      */
1308     next_offset = tvb_find_guint8(tvb,offset,-1,';');
1309
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);
1316
1317       fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1318
1319       decode_sdp_fmtp(fmtp_tree, tvb, offset, tokenlen,
1320                       (guint8 *)transport_info->encoding_name);
1321
1322       offset = next_offset + 1;
1323     }
1324
1325     /* Now add remaining (or only) parameter */
1326     tokenlen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1327
1328     fmtp_item = proto_tree_add_item(sdp_media_attribute_tree,
1329                                     hf_media_format_specific_parameter, tvb,
1330                                     offset, tokenlen, FALSE);
1331
1332     fmtp_tree = proto_item_add_subtree(fmtp_item, ett_sdp_fmtp);
1333
1334     decode_sdp_fmtp(fmtp_tree, tvb, offset, tokenlen,
1335                     (guint8 *)transport_info->encoding_name);
1336     return;
1337   }
1338
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;
1344
1345       /* Address starts here */
1346       address_offset = offset + strlen(msrp_res);
1347
1348       /* Port is after next ':' */
1349       port_offset = tvb_find_guint8(tvb, address_offset, -1, ':');
1350
1351       /* Port ends with '/' */
1352       port_end_offset = tvb_find_guint8(tvb, port_offset, -1, '/');
1353       
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));
1358
1359         /* Set flag so this info can be used */
1360         msrp_transport_address_set = TRUE;
1361       }
1362     }
1363   }
1364
1365
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);
1369 }
1370
1371 void
1372 proto_register_sdp(void)
1373 {
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 }},
1379     { &hf_owner,
1380       { "Owner/Creator, Session Id (o)",
1381         "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
1382         "Owner/Creator, Session Id", HFILL}},
1383     { &hf_session_name,
1384       { "Session Name (s)",
1385         "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
1386         "Session Name", HFILL }},
1387     { &hf_session_info,
1388       { "Session Information (i)",
1389         "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
1390         "Session Information", HFILL }},
1391     { &hf_uri,
1392       { "URI of Description (u)",
1393         "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
1394         "URI of Description", HFILL }},
1395     { &hf_email,
1396       { "E-mail Address (e)",
1397         "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
1398         "E-mail Address", HFILL }},
1399     { &hf_phone,
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 }},
1407     { &hf_bandwidth,
1408       { "Bandwidth Information (b)",
1409         "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
1410         "Bandwidth Information", HFILL }},
1411     { &hf_timezone,
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 }},
1427     { &hf_time,
1428       { "Time Description, active time (t)",
1429         "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
1430         "Time Description, active time", HFILL }},
1431     { &hf_repeat_time,
1432       { "Repeat Time (r)",
1433         "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
1434         "Repeat Time", HFILL }},
1435     { &hf_media,
1436       { "Media Description, name and address (m)",
1437         "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
1438         "Media Description, name and address", HFILL }},
1439     { &hf_media_title,
1440       { "Media Title (i)",
1441         "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
1442         "Media Title", HFILL }},
1443     { &hf_unknown,
1444       { "Unknown",
1445         "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
1446         "Unknown", HFILL }},
1447     { &hf_invalid,
1448       { "Invalid line",
1449         "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
1450         "Invalid line", HFILL }},
1451     { &hf_owner_username,
1452       { "Owner Username",
1453         "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
1454         "Owner Username", HFILL }},
1455     { &hf_owner_sessionid,
1456       { "Session ID",
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,
1472       { "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,
1488       { "Connection 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 }},
1503     { &hf_time_start,
1504       { "Session Start Time",
1505         "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
1506         "Session Start Time", HFILL }},
1507     { &hf_time_stop,
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,
1520       { "Repeat Offset",
1521         "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
1522         "Repeat Offset", HFILL }},
1523     { &hf_timezone_time,
1524       { "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,
1532       { "Key Type",
1533         "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
1534         "Type", HFILL }},
1535     { &hf_encryption_key_data,
1536       { "Key Data",
1537         "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
1538         "Data", HFILL }},
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 }},
1547     { &hf_media_media,
1548       { "Media Type",
1549         "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
1550         "Media Type", HFILL }},
1551     { &hf_media_port,
1552       { "Media Port",
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 }},
1559     { &hf_media_proto,
1560       { "Media Proto",
1561         "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
1562         "Media Protocol", HFILL }},
1563     { &hf_media_format,
1564       { "Media Format",
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,
1576       { "MIME Type",
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 }},
1587     { &hf_ipbcp_type,
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,
1592       { "Level Code",
1593         "sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mpeg4es_level_indication_vals), 0x0,
1594         "Level Code", HFILL }},
1595   };
1596   static gint *ett[] = {
1597     &ett_sdp,
1598     &ett_sdp_owner,
1599     &ett_sdp_connection_info,
1600     &ett_sdp_bandwidth,
1601     &ett_sdp_time,
1602     &ett_sdp_repeat_time,
1603     &ett_sdp_timezone,
1604     &ett_sdp_encryption_key,
1605     &ett_sdp_session_attribute,
1606     &ett_sdp_media,
1607     &ett_sdp_media_attribute,
1608     &ett_sdp_fmtp,
1609   };
1610
1611   module_t *sdp_module;
1612
1613   proto_sdp = proto_register_protocol("Session Description Protocol",
1614                                       "SDP", "sdp");
1615   proto_register_field_array(proto_sdp, hf, array_length(hf));
1616   proto_register_subtree_array(ett, array_length(ett));
1617
1618   /*
1619    * Preferences registration
1620    */
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);
1627  
1628   /*
1629    * Register the dissector by name, so other dissectors can
1630    * grab it by name rather than just referring to it directly.
1631    */
1632   register_dissector("sdp", dissect_sdp, proto_sdp);
1633
1634   /* Register for tapping */
1635   sdp_tap = register_tap("sdp");
1636 }
1637
1638 void
1639 proto_reg_handoff_sdp(void)
1640 {
1641   dissector_handle_t sdp_handle;
1642
1643   rtp_handle = find_dissector("rtp");
1644   rtcp_handle = find_dissector("rtcp");
1645   msrp_handle = find_dissector("msrp");
1646   t38_handle = find_dissector("t38");
1647
1648   sdp_handle = find_dissector("sdp");
1649   dissector_add_string("media_type", "application/sdp", sdp_handle);
1650 }