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