Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / 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: packet-sdp.c,v 1.32 2002/08/19 12:57:12 guy Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
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 <glib.h>
34 #include <epan/packet.h>
35 #include <epan/strutil.h>
36
37 static int proto_sdp = -1;
38
39 /* Top level fields */
40 static int hf_protocol_version = -1;
41 static int hf_owner = -1;
42 static int hf_session_name = -1;
43 static int hf_session_info = -1;
44 static int hf_uri = -1;
45 static int hf_email = -1;
46 static int hf_phone = -1;
47 static int hf_connection_info = -1;
48 static int hf_bandwidth = -1;
49 static int hf_timezone = -1;
50 static int hf_encryption_key = -1;
51 static int hf_session_attribute = -1;
52 static int hf_media_attribute = -1;
53 static int hf_time = -1;
54 static int hf_repeat_time = -1;
55 static int hf_media = -1;
56 static int hf_media_title = -1;
57 static int hf_unknown = -1;
58 static int hf_invalid = -1;
59
60 /* hf_owner subfields*/
61 static int hf_owner_username = -1;
62 static int hf_owner_sessionid = -1;
63 static int hf_owner_version = -1;
64 static int hf_owner_network_type = -1;
65 static int hf_owner_address_type = -1;
66 static int hf_owner_address = -1;
67
68 /* hf_connection_info subfields */
69 static int hf_connection_info_network_type = -1;
70 static int hf_connection_info_address_type = -1;
71 static int hf_connection_info_connection_address = -1;
72 static int hf_connection_info_ttl = -1;
73 static int hf_connection_info_num_addr = -1;
74
75 /* hf_bandwidth subfields */
76 static int hf_bandwidth_modifier = -1;
77 static int hf_bandwidth_value = -1;
78
79 /* hf_time subfields */
80 static int hf_time_start = -1;
81 static int hf_time_stop = -1;
82
83 /* hf_repeat_time subfield */
84 static int hf_repeat_time_interval = -1;
85 static int hf_repeat_time_duration = -1;
86 static int hf_repeat_time_offset = -1;
87
88 /* hf_timezone subfields */
89 static int hf_timezone_time = -1;
90 static int hf_timezone_offset = -1;
91
92 /* hf_encryption_key subfields */
93 static int hf_encryption_key_type = -1;
94 static int hf_encryption_key_data = -1;
95
96 /* hf_session_attribute subfields */
97 static int hf_session_attribute_field = -1;
98 static int hf_session_attribute_value = -1;
99
100 /* hf_media subfields */
101 static int hf_media_media = -1;
102 static int hf_media_port = -1;
103 static int hf_media_portcount = -1;
104 static int hf_media_proto = -1;
105 static int hf_media_format = -1;
106
107 /* hf_session_attribute subfields */
108 static int hf_media_attribute_field = -1;
109 static int hf_media_attribute_value = -1;
110
111 /* trees */
112 static int ett_sdp = -1;
113 static int ett_sdp_owner = -1;
114 static int ett_sdp_connection_info = -1;
115 static int ett_sdp_bandwidth = -1;
116 static int ett_sdp_time = -1;
117 static int ett_sdp_repeat_time = -1;
118 static int ett_sdp_timezone = -1;
119 static int ett_sdp_encryption_key = -1;
120 static int ett_sdp_session_attribute = -1;
121 static int ett_sdp_media = -1;
122 static int ett_sdp_media_attribute = -1;
123
124 /* static functions */
125
126 static void call_sdp_subdissector(tvbuff_t *tvb, int hf, proto_tree* ti);
127
128 /* Subdissector functions */
129 static void dissect_sdp_owner(tvbuff_t *tvb, proto_item* ti);
130 static void dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti);
131 static void dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti);
132 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti);
133 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti);
134 static void dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti);
135 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti);
136 static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item *ti);
137 static void dissect_sdp_media(tvbuff_t *tvb, proto_item *ti);
138 static void dissect_sdp_media_attribute(tvbuff_t *tvb, proto_item *ti);
139
140 static void
141 dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
142 {
143         proto_tree      *sdp_tree;
144         proto_item      *ti, *sub_ti;
145         gint            offset = 0;
146         gint            next_offset;
147         int             linelen;
148         gboolean        in_media_description;
149         guchar          type;
150         guchar          delim;
151         int             datalen;
152         int             tokenoffset;
153         int             hf = -1;
154         char            *string;
155
156         /*
157          * As RFC 2327 says, "SDP is purely a format for session
158          * description - it does not incorporate a transport protocol,
159          * and is intended to use different transport protocols as
160          * appropriate including the Session Announcement Protocol,
161          * Session Initiation Protocol, Real-Time Streaming Protocol,
162          * electronic mail using the MIME extensions, and the
163          * Hypertext Transport Protocol."
164          *
165          * We therefore don't set the protocol or info columns;
166          * instead, we append to them, so that we don't erase
167          * what the protocol inside which the SDP stuff resides
168          * put there.
169          */
170         if (check_col(pinfo->cinfo, COL_PROTOCOL))
171                 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/SDP");
172
173         if (check_col(pinfo->cinfo, COL_INFO)) {
174                 /* XXX: Needs description. */
175                 col_append_str(pinfo->cinfo, COL_INFO, ", with session description");
176         }
177
178         if (!tree)
179                 return;
180
181         ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, -1, FALSE);
182         sdp_tree = proto_item_add_subtree(ti, ett_sdp);
183
184         /*
185          * Show the SDP message a line at a time.
186          */
187         in_media_description = FALSE;
188         while (tvb_offset_exists(tvb, offset)) {
189                 /*
190                  * Find the end of the line.
191                  */
192                 linelen = tvb_find_line_end_unquoted(tvb, offset, -1,
193                     &next_offset);
194
195                 /*
196                  * Line must contain at least e.g. "v=".
197                  */
198                 if (linelen < 2)
199                         break;
200
201                 type = tvb_get_guint8(tvb,offset);
202                 delim = tvb_get_guint8(tvb,offset + 1);
203                 if (delim != '=') {
204                         proto_tree_add_item(sdp_tree,hf_invalid,tvb, offset,
205                                               linelen, FALSE);
206                         offset = next_offset;
207                         continue;
208                 }
209
210                 /*
211                  * Attributes.
212                  */
213                 switch (type) {
214                 case 'v':
215                         hf = hf_protocol_version;
216                         break;
217                 case 'o':
218                         hf = hf_owner;
219                         break;
220                 case 's':
221                         hf = hf_session_name;
222                         break;
223                 case 'i':
224                         if (in_media_description) {
225                                 hf = hf_media_title;
226                         }
227                         else{
228                                 hf = hf_session_info;
229                         }
230                         break;
231                 case 'u':
232                         hf = hf_uri;
233                         break;
234                 case 'e':
235                         hf = hf_email;
236                         break;
237                 case 'p':
238                         hf = hf_phone;
239                         break;
240                 case 'c':
241                         hf = hf_connection_info;
242                         break;
243                 case 'b':
244                         hf = hf_bandwidth;
245                         break;
246                 case 't':
247                         hf = hf_time;
248                         break;
249                 case 'r':
250                         hf = hf_repeat_time;
251                         break;
252                 case 'm':
253                         hf = hf_media;
254                         in_media_description = TRUE;
255                         break;
256                 case 'k':
257                         hf = hf_encryption_key;
258                         break;
259                 case 'a':
260                         if (in_media_description) {
261                                 hf = hf_media_attribute;
262                         }
263                         else{
264                                 hf = hf_session_attribute; 
265                         }
266                         break;
267                 case 'z':
268                         hf = hf_timezone;
269                         break;
270                 default:
271                         hf = hf_unknown;
272                         break;
273                 }
274                 tokenoffset = 2;
275                 if( hf == hf_unknown )
276                   tokenoffset = 0;
277                 string = g_malloc(linelen - tokenoffset + 1);
278                 CLEANUP_PUSH(g_free, string);
279                 tvb_memcpy(tvb, (guint8 *)string, offset + tokenoffset,
280                     linelen - tokenoffset);
281                 string[linelen - tokenoffset] = '\0';
282                 sub_ti = proto_tree_add_string_format(sdp_tree,hf,tvb, offset, 
283                                                linelen, string,
284                                                "%s: %s",
285                                                proto_registrar_get_name(hf),
286                                                format_text(string,
287                                                  linelen - tokenoffset));
288                 CLEANUP_CALL_AND_POP;
289                 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
290                                                      linelen-tokenoffset,-1),
291                                       hf,sub_ti);
292                 offset = next_offset;
293         }
294
295         datalen = tvb_length_remaining(tvb, offset);
296         if (datalen > 0) {
297                 proto_tree_add_text(sdp_tree, tvb, offset, datalen,
298                     "Data (%d bytes)", datalen);
299         }
300 }
301
302 static void 
303 call_sdp_subdissector(tvbuff_t *tvb, int hf, proto_tree* ti){
304   if(hf == hf_owner){
305     dissect_sdp_owner(tvb,ti);
306   } else if ( hf == hf_connection_info) {
307     dissect_sdp_connection_info(tvb,ti);
308   } else if ( hf == hf_bandwidth) {
309     dissect_sdp_bandwidth(tvb,ti);
310   } else if ( hf == hf_time) {
311     dissect_sdp_time(tvb,ti);
312   } else if ( hf == hf_repeat_time ){
313     dissect_sdp_repeat_time(tvb,ti);
314   } else if ( hf == hf_timezone ) {
315     dissect_sdp_timezone(tvb,ti);
316   } else if ( hf == hf_encryption_key ) {
317     dissect_sdp_encryption_key(tvb,ti);
318   } else if ( hf == hf_session_attribute ){
319     dissect_sdp_session_attribute(tvb,ti);
320   } else if ( hf == hf_media ) {
321     dissect_sdp_media(tvb,ti);
322   } else if ( hf == hf_media_attribute ){
323     dissect_sdp_media_attribute(tvb,ti);
324   }
325 }
326
327 static void 
328 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
329   proto_tree *sdp_owner_tree;
330   gint offset,next_offset,tokenlen;
331
332   offset = 0;
333   next_offset = 0;
334   tokenlen = 0;
335
336   sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
337   
338   /* Find the username */
339   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
340   if( next_offset == -1 )
341     return;
342   tokenlen = next_offset - offset;
343
344   proto_tree_add_item(sdp_owner_tree,hf_owner_username,tvb, offset,tokenlen,
345                       FALSE);
346   offset = next_offset  + 1;
347
348   /* Find the session id */
349   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
350   if( next_offset == -1 )
351     return;
352   tokenlen = next_offset - offset;
353
354   proto_tree_add_item(sdp_owner_tree,hf_owner_sessionid, tvb, 
355                       offset,tokenlen,FALSE);
356   offset = next_offset + 1;
357
358   /* Find the version */
359   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
360   if( next_offset == -1 )
361     return;
362   tokenlen = next_offset - offset;
363
364   proto_tree_add_item(sdp_owner_tree,hf_owner_version, tvb,
365                       offset,tokenlen,FALSE);
366   offset = next_offset + 1;
367
368   /* Find the network type */
369   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
370   if( next_offset == -1 )
371     return;
372   tokenlen = next_offset - offset;
373
374   proto_tree_add_item(sdp_owner_tree,hf_owner_network_type, tvb, 
375                       offset,tokenlen,FALSE);
376   offset = next_offset + 1;
377   
378   /* Find the address type */
379   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
380   if( next_offset == -1 )
381     return;
382   tokenlen = next_offset - offset;
383
384   proto_tree_add_item(sdp_owner_tree,hf_owner_address_type, tvb, 
385                       offset,tokenlen,FALSE);
386   offset = next_offset + 1;
387
388   /* Find the address */
389   proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
390 }
391
392 static void 
393 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti){
394   proto_tree *sdp_connection_info_tree;
395   gint offset,next_offset,tokenlen;
396
397   offset = 0;
398   next_offset = 0;
399   tokenlen = 0;
400   
401   sdp_connection_info_tree = proto_item_add_subtree(ti,
402                                                     ett_sdp_connection_info);
403   
404   /* Find the network type */
405   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
406   if( next_offset == -1 )
407     return;
408   tokenlen = next_offset - offset;
409
410   proto_tree_add_item(sdp_connection_info_tree,
411                       hf_connection_info_network_type,tvb, 
412                       offset,tokenlen,FALSE);
413   offset = next_offset + 1;
414
415   /* Find the address type */
416   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
417   if( next_offset == -1 )
418     return;
419   tokenlen = next_offset - offset;
420
421   proto_tree_add_item(sdp_connection_info_tree,
422                       hf_connection_info_address_type,tvb, 
423                       offset,tokenlen,FALSE);
424   offset = next_offset + 1;
425
426   /* Find the connection address */
427   next_offset = tvb_find_guint8(tvb,offset,-1,'/');
428   if( next_offset == -1){
429     tokenlen = -1;      /* end of tvbuff */
430   } else {
431     tokenlen = next_offset - offset;
432   }
433   proto_tree_add_item(sdp_connection_info_tree,
434                       hf_connection_info_connection_address, tvb, 
435                       offset,tokenlen,FALSE);
436   if(next_offset != -1){
437     offset = next_offset + 1;
438     next_offset = tvb_find_guint8(tvb,offset,-1,'/');
439     if( next_offset == -1){
440       tokenlen = -1;    /* end of tvbuff */
441     } else {
442       tokenlen = next_offset - offset;
443     }
444     proto_tree_add_item(sdp_connection_info_tree,
445                         hf_connection_info_ttl,tvb,offset,tokenlen,FALSE);
446     if(next_offset != -1){
447       offset = next_offset + 1;
448       proto_tree_add_item(sdp_connection_info_tree,
449                           hf_connection_info_num_addr, tvb,
450                           offset, -1, FALSE);
451     }
452   }
453 }
454
455 static void 
456 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
457   proto_tree * sdp_bandwidth_tree;
458   gint offset, next_offset, tokenlen;
459   
460   offset = 0;
461   next_offset = 0;
462   tokenlen = 0;
463
464   sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
465
466   /* find the modifier */
467   next_offset = tvb_find_guint8(tvb,offset,-1,':');
468
469   if( next_offset == -1)
470     return;
471   
472   tokenlen = next_offset - offset;
473   
474   proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier,
475                       tvb, offset, tokenlen, FALSE);
476
477   offset = next_offset + 1;
478   
479   proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value,
480                       tvb, offset, -1, FALSE);
481
482 }
483
484 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
485   proto_tree *sdp_time_tree;
486   gint offset,next_offset, tokenlen;
487
488   offset = 0;
489   next_offset = 0;
490   tokenlen = 0;
491   
492   sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
493
494   /* get start time */
495   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
496   if( next_offset == -1 )
497     return;
498
499   tokenlen = next_offset - offset;
500   proto_tree_add_item(sdp_time_tree, hf_time_start, tvb,
501                       offset, tokenlen, FALSE);
502
503   /* get stop time */
504   offset = next_offset + 1;
505   proto_tree_add_item(sdp_time_tree,hf_time_start, tvb,
506                       offset, -1, FALSE);
507 }
508
509 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
510   proto_tree *sdp_repeat_time_tree;
511   gint offset,next_offset, tokenlen;
512
513   offset = 0;
514   next_offset = 0;
515   tokenlen = 0;
516   
517   sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
518
519   /* get interval */
520   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
521   if( next_offset == -1 )
522     return;
523
524   tokenlen = next_offset - offset;
525   proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
526                       offset, tokenlen, FALSE);
527
528   /* get duration */
529   offset = next_offset + 1;
530   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
531   if( next_offset == -1 )
532     return;
533
534   tokenlen = next_offset - offset;
535   proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
536                       offset, tokenlen, FALSE);
537
538   /* get offsets */
539   do{
540     offset = next_offset +1;
541     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
542     if(next_offset != -1){
543       tokenlen = next_offset - offset;
544     } else {
545       tokenlen = -1;    /* end of tvbuff */
546     }
547     proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
548                         tvb, offset, tokenlen, FALSE);
549   } while( next_offset != -1 );
550   
551 }
552 static void 
553 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
554   proto_tree* sdp_timezone_tree;
555   gint offset, next_offset, tokenlen;
556   offset = 0;
557   next_offset = 0;
558   tokenlen = 0;
559   
560   sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
561   
562   do{
563     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
564     if(next_offset == -1)
565       break;
566     tokenlen = next_offset - offset;
567     
568     proto_tree_add_item(sdp_timezone_tree,hf_timezone_time,tvb,
569                         offset, tokenlen, FALSE);
570     offset = next_offset + 1;
571     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
572     if(next_offset != -1){
573       tokenlen = next_offset - offset;
574     } else {
575       tokenlen = -1;    /* end of tvbuff */
576     }
577     proto_tree_add_item(sdp_timezone_tree,hf_timezone_offset,tvb,
578                         offset, tokenlen, FALSE);
579     offset = next_offset + 1;
580   } while (next_offset != -1);
581     
582 }
583
584
585 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
586   proto_tree *sdp_encryption_key_tree;
587   gint offset, next_offset, tokenlen;
588
589   offset = 0;
590   next_offset = 0;
591   tokenlen = 0;
592
593   sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
594
595   next_offset = tvb_find_guint8(tvb,offset,-1,':');
596
597   if(next_offset == -1)
598     return;
599
600   tokenlen = next_offset - offset;
601   
602   proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
603                       tvb, offset, tokenlen, FALSE);
604   
605   offset = next_offset + 1;
606   proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
607                       tvb, offset, -1, FALSE);
608
609 }
610
611
612
613 static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item * ti){
614   proto_tree *sdp_session_attribute_tree;
615   gint offset, next_offset, tokenlen;
616
617   offset = 0;
618   next_offset = 0;
619   tokenlen = 0;
620
621   sdp_session_attribute_tree = proto_item_add_subtree(ti,
622                                                       ett_sdp_session_attribute);
623
624   next_offset = tvb_find_guint8(tvb,offset,-1,':');
625
626   if(next_offset == -1)
627     return;
628
629   tokenlen = next_offset - offset;
630   
631   proto_tree_add_item(sdp_session_attribute_tree,
632                       hf_session_attribute_field,
633                       tvb, offset, tokenlen, FALSE);
634   
635   offset = next_offset + 1;
636   proto_tree_add_item(sdp_session_attribute_tree,
637                       hf_session_attribute_value,
638                       tvb, offset, -1, FALSE);
639
640 }
641
642 static void 
643 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti){
644   proto_tree *sdp_media_tree;
645   gint offset, next_offset, tokenlen;
646
647   offset = 0;
648   next_offset = 0;
649   tokenlen = 0;
650
651   sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
652
653   next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
654   
655   if(next_offset == -1)
656     return;
657
658   tokenlen = next_offset - offset;
659   
660   proto_tree_add_item(sdp_media_tree, hf_media_media, tvb, 
661                       offset, tokenlen, FALSE);
662
663   offset = next_offset + 1;
664
665   next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
666   if(next_offset == -1)
667     return;
668   tokenlen = next_offset - offset;
669   next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
670   
671   if(next_offset != -1){
672     tokenlen = next_offset - offset;
673   
674     proto_tree_add_item(sdp_media_tree, hf_media_port, tvb, 
675                         offset, tokenlen, FALSE);
676     offset = next_offset + 1;
677     next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
678     if(next_offset == -1)
679       return;
680     tokenlen = next_offset - offset;
681     proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb,
682                         offset, tokenlen, FALSE);
683     offset = next_offset + 1;
684   } else {
685     next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
686     
687     if(next_offset == -1)
688       return;
689     tokenlen = next_offset - offset;
690     
691     proto_tree_add_item(sdp_media_tree, hf_media_port, tvb,
692                         offset, tokenlen, FALSE);
693     offset = next_offset + 1;
694   }
695
696   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
697   
698   if( next_offset == -1)
699     return;
700   
701   tokenlen = next_offset - offset;
702
703   proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb,
704                       offset, tokenlen, FALSE);
705
706   do{
707     offset = next_offset + 1;
708     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
709     
710     if(next_offset == -1){
711       tokenlen = -1;    /* End of tvbuff */
712     } else {
713       tokenlen = next_offset - offset;
714     }
715
716     proto_tree_add_item(sdp_media_tree, hf_media_format, tvb,
717                         offset, tokenlen, FALSE);
718   } while (next_offset != -1);
719
720 }
721
722 static void dissect_sdp_media_attribute(tvbuff_t *tvb, proto_item * ti){
723   proto_tree *sdp_media_attribute_tree;
724   gint offset, next_offset, tokenlen;
725
726   offset = 0;
727   next_offset = 0;
728   tokenlen = 0;
729
730   sdp_media_attribute_tree = proto_item_add_subtree(ti,
731                                                       ett_sdp_media_attribute);
732
733   next_offset = tvb_find_guint8(tvb,offset,-1,':');
734
735   if(next_offset == -1)
736     return;
737
738   tokenlen = next_offset - offset;
739   
740   proto_tree_add_item(sdp_media_attribute_tree,
741                       hf_media_attribute_field,
742                       tvb, offset, tokenlen, FALSE);
743   
744   offset = next_offset + 1;
745   proto_tree_add_item(sdp_media_attribute_tree,
746                       hf_media_attribute_value,
747                       tvb, offset, -1, FALSE);
748
749 }
750
751 void
752 proto_register_sdp(void)
753 {
754   static hf_register_info hf[] = {
755     { &hf_protocol_version,
756       { "Session Description Protocol Version (v)",
757         "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
758         "Session Description Protocol Version", HFILL }},
759     { &hf_owner, 
760       { "Owner/Creator, Session Id (o)",
761         "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
762         "Owner/Creator, Session Id", HFILL}},
763     { &hf_session_name,
764       { "Session Name (s)",
765         "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
766         "Session Name", HFILL }},
767     { &hf_session_info,
768       { "Session Information (i)", 
769         "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
770         "Session Information", HFILL }},
771     { &hf_uri,
772       { "URI of Description (u)",
773         "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
774         "URI of Description", HFILL }},
775     { &hf_email,
776       { "E-mail Address (e)", 
777         "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
778         "E-mail Address", HFILL }},
779     { &hf_phone,
780       { "Phone Number (p)",
781         "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
782         "Phone Number", HFILL }},
783     { &hf_connection_info,
784       { "Connection Information (c)",
785         "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
786         "Connection Information", HFILL }},
787     { &hf_bandwidth,
788       { "Bandwidth Information (b)",
789         "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
790         "Bandwidth Information", HFILL }},
791     { &hf_timezone,
792       { "Time Zone Adjustments (z)",
793         "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
794         "Time Zone Adjustments", HFILL }},
795     { &hf_encryption_key,
796       { "Encryption Key (k)",
797         "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
798         "Encryption Key", HFILL }},
799     { &hf_session_attribute, 
800       { "Session Attribute (a)", 
801         "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
802         "Session Attribute", HFILL }},
803     { &hf_media_attribute, 
804       { "Media Attribute (a)", 
805         "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
806         "Media Attribute", HFILL }},
807     { &hf_time,
808       { "Time Description, active time (t)",
809         "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
810         "Time Description, active time", HFILL }},
811     { &hf_repeat_time,
812       { "Repeat Time (r)",
813         "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
814         "Repeat Time", HFILL }},
815     { &hf_media,
816       { "Media Description, name and address (m)",
817         "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
818         "Media Description, name and address", HFILL }},
819     { &hf_media_title,
820       { "Media Title (i)",
821         "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
822         "Media Title", HFILL }},
823     { &hf_unknown,
824       { "Unknown",
825         "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
826         "Unknown", HFILL }},
827     { &hf_invalid,
828       { "Invalid line",
829         "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
830         "Invalid line", HFILL }},
831     { &hf_owner_username,
832       { "Owner Username",
833         "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
834         "Owner Username", HFILL }},
835     { &hf_owner_sessionid,
836       { "Session ID",
837         "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
838         "Session ID", HFILL }},
839     { &hf_owner_version,
840       { "Session Version",
841         "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
842         "Session Version", HFILL }},
843     { &hf_owner_network_type,
844       { "Owner Network Type",
845         "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
846         "Owner Network Type", HFILL }},
847     { &hf_owner_address_type,
848       { "Owner Address Type",
849         "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
850         "Owner Address Type", HFILL }},
851     { &hf_owner_address,
852       { "Owner Address",
853         "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
854         "Owner Address", HFILL }},
855     { &hf_connection_info_network_type,
856       { "Connection Network Type",
857         "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
858         "Connection Network Type", HFILL }},
859     { &hf_connection_info_address_type,
860       { "Connection Address Type",
861         "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
862         "Connection Address Type", HFILL }},
863     { &hf_connection_info_connection_address,
864       { "Connection Address",
865         "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
866         "Connection Address", HFILL }},
867     { &hf_connection_info_ttl,
868       { "Connection TTL",
869         "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
870         "Connection TTL", HFILL }},
871     { &hf_connection_info_num_addr,
872       { "Connection Number of Addresses",
873         "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
874         "Connection Number of Addresses", HFILL }},
875     { &hf_bandwidth_modifier,
876       { "Bandwidth Modifier",
877         "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
878         "Bandwidth Modifier", HFILL }},    
879     { &hf_bandwidth_value,
880       { "Bandwidth Value",
881         "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
882         "Bandwidth Value", HFILL }},    
883     { &hf_time_start,
884       { "Session Start Time",
885         "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
886         "Session Start Time", HFILL }},
887     { &hf_time_stop,
888       { "Session Stop Time",
889         "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
890         "Session Stop Time", HFILL }},
891     { &hf_repeat_time_interval,
892       { "Repeat Interval",
893         "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
894         "Repeat Interval", HFILL }},
895     { &hf_repeat_time_duration,
896       { "Repeat Duration",
897         "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
898         "Repeat Duration", HFILL }},
899     { &hf_repeat_time_offset,
900       { "Repeat Offset",
901         "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
902         "Repeat Offset", HFILL }},
903     { &hf_timezone_time,
904       { "Timezone Time",
905         "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
906         "Timezone Time", HFILL }},
907     { &hf_timezone_offset,
908       { "Timezone Offset",
909         "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
910         "Timezone Offset", HFILL }},
911     { &hf_encryption_key_type,
912       { "Key Type",
913         "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
914         "Type", HFILL }},
915     { &hf_encryption_key_data,
916       { "Key Data",
917         "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
918         "Data", HFILL }},
919     { &hf_session_attribute_field,
920       { "Session Attribute Fieldname",
921         "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
922         "Session Attribute Fieldname", HFILL }},
923     { &hf_session_attribute_value,
924       { "Session Attribute Value",
925         "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
926         "Session Attribute Value", HFILL }},
927     { &hf_media_media,
928       { "Media Type",
929         "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
930         "Media Type", HFILL }},
931     { &hf_media_port,
932       { "Media Port",
933         "sdp.media.port",FT_STRING, BASE_NONE, NULL, 0x0,
934         "Media Port", HFILL }},
935     { &hf_media_portcount,
936       { "Media Port Count",
937         "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
938         "Media Port Count", HFILL }},
939     { &hf_media_proto,
940       { "Media Proto",
941         "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
942         "Media Proto", HFILL }},
943     { &hf_media_format,
944       { "Media Format",
945         "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
946         "Media Format", HFILL }},
947     { &hf_media_attribute_field,
948       { "Media Attribute Fieldname",
949         "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
950         "Media Attribute Fieldname", HFILL }},
951     { &hf_media_attribute_value,
952       { "Media Attribute Value",
953         "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
954         "Media Attribute Value", HFILL }},
955
956   };
957   static gint *ett[] = {
958     &ett_sdp,
959     &ett_sdp_owner,
960     &ett_sdp_connection_info,
961     &ett_sdp_bandwidth,
962     &ett_sdp_time,
963     &ett_sdp_repeat_time,
964     &ett_sdp_timezone,
965     &ett_sdp_encryption_key,
966     &ett_sdp_session_attribute,
967     &ett_sdp_media,
968     &ett_sdp_media_attribute,
969   };
970   
971   proto_sdp = proto_register_protocol("Session Description Protocol",
972                                       "SDP", "sdp");
973   proto_register_field_array(proto_sdp, hf, array_length(hf));
974   proto_register_subtree_array(ett, array_length(ett));
975         
976   /*
977    * Register the dissector by name, so other dissectors can
978    * grab it by name rather than just referring to it directly
979    * (you can't refer to it directly from a plugin dissector
980    * on Windows without stuffing it into the Big Transfer Vector).
981    */
982   register_dissector("sdp", dissect_sdp, proto_sdp);
983 }