dfilter2pod.pl and ethereal-filter.pod.template are in $(srcdir) (which
[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.34 2003/06/12 08:33:29 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 = tvb_get_string(tvb, offset + tokenoffset,
278                     linelen - tokenoffset);
279                 sub_ti = proto_tree_add_string_format(sdp_tree,hf,tvb, offset,
280                                                linelen, string,
281                                                "%s: %s",
282                                                proto_registrar_get_name(hf),
283                                                format_text(string,
284                                                  linelen - tokenoffset));
285                 g_free(string);
286                 call_sdp_subdissector(tvb_new_subset(tvb,offset+tokenoffset,
287                                                      linelen-tokenoffset,-1),
288                                       hf,sub_ti);
289                 offset = next_offset;
290         }
291
292         datalen = tvb_length_remaining(tvb, offset);
293         if (datalen > 0) {
294                 proto_tree_add_text(sdp_tree, tvb, offset, datalen,
295                     "Data (%d bytes)", datalen);
296         }
297 }
298
299 static void
300 call_sdp_subdissector(tvbuff_t *tvb, int hf, proto_tree* ti){
301   if(hf == hf_owner){
302     dissect_sdp_owner(tvb,ti);
303   } else if ( hf == hf_connection_info) {
304     dissect_sdp_connection_info(tvb,ti);
305   } else if ( hf == hf_bandwidth) {
306     dissect_sdp_bandwidth(tvb,ti);
307   } else if ( hf == hf_time) {
308     dissect_sdp_time(tvb,ti);
309   } else if ( hf == hf_repeat_time ){
310     dissect_sdp_repeat_time(tvb,ti);
311   } else if ( hf == hf_timezone ) {
312     dissect_sdp_timezone(tvb,ti);
313   } else if ( hf == hf_encryption_key ) {
314     dissect_sdp_encryption_key(tvb,ti);
315   } else if ( hf == hf_session_attribute ){
316     dissect_sdp_session_attribute(tvb,ti);
317   } else if ( hf == hf_media ) {
318     dissect_sdp_media(tvb,ti);
319   } else if ( hf == hf_media_attribute ){
320     dissect_sdp_media_attribute(tvb,ti);
321   }
322 }
323
324 static void
325 dissect_sdp_owner(tvbuff_t *tvb, proto_item *ti){
326   proto_tree *sdp_owner_tree;
327   gint offset,next_offset,tokenlen;
328
329   offset = 0;
330   next_offset = 0;
331   tokenlen = 0;
332
333   sdp_owner_tree = proto_item_add_subtree(ti,ett_sdp_owner);
334
335   /* Find the username */
336   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
337   if( next_offset == -1 )
338     return;
339   tokenlen = next_offset - offset;
340
341   proto_tree_add_item(sdp_owner_tree,hf_owner_username,tvb, offset,tokenlen,
342                       FALSE);
343   offset = next_offset  + 1;
344
345   /* Find the session id */
346   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
347   if( next_offset == -1 )
348     return;
349   tokenlen = next_offset - offset;
350
351   proto_tree_add_item(sdp_owner_tree,hf_owner_sessionid, tvb,
352                       offset,tokenlen,FALSE);
353   offset = next_offset + 1;
354
355   /* Find the version */
356   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
357   if( next_offset == -1 )
358     return;
359   tokenlen = next_offset - offset;
360
361   proto_tree_add_item(sdp_owner_tree,hf_owner_version, tvb,
362                       offset,tokenlen,FALSE);
363   offset = next_offset + 1;
364
365   /* Find the network type */
366   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
367   if( next_offset == -1 )
368     return;
369   tokenlen = next_offset - offset;
370
371   proto_tree_add_item(sdp_owner_tree,hf_owner_network_type, tvb,
372                       offset,tokenlen,FALSE);
373   offset = next_offset + 1;
374
375   /* Find the address type */
376   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
377   if( next_offset == -1 )
378     return;
379   tokenlen = next_offset - offset;
380
381   proto_tree_add_item(sdp_owner_tree,hf_owner_address_type, tvb,
382                       offset,tokenlen,FALSE);
383   offset = next_offset + 1;
384
385   /* Find the address */
386   proto_tree_add_item(sdp_owner_tree,hf_owner_address, tvb, offset, -1, FALSE);
387 }
388
389 static void
390 dissect_sdp_connection_info(tvbuff_t *tvb, proto_item* ti){
391   proto_tree *sdp_connection_info_tree;
392   gint offset,next_offset,tokenlen;
393
394   offset = 0;
395   next_offset = 0;
396   tokenlen = 0;
397
398   sdp_connection_info_tree = proto_item_add_subtree(ti,
399                                                     ett_sdp_connection_info);
400
401   /* Find the network type */
402   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
403   if( next_offset == -1 )
404     return;
405   tokenlen = next_offset - offset;
406
407   proto_tree_add_item(sdp_connection_info_tree,
408                       hf_connection_info_network_type,tvb,
409                       offset,tokenlen,FALSE);
410   offset = next_offset + 1;
411
412   /* Find the address type */
413   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
414   if( next_offset == -1 )
415     return;
416   tokenlen = next_offset - offset;
417
418   proto_tree_add_item(sdp_connection_info_tree,
419                       hf_connection_info_address_type,tvb,
420                       offset,tokenlen,FALSE);
421   offset = next_offset + 1;
422
423   /* Find the connection address */
424   next_offset = tvb_find_guint8(tvb,offset,-1,'/');
425   if( next_offset == -1){
426     tokenlen = -1;      /* end of tvbuff */
427   } else {
428     tokenlen = next_offset - offset;
429   }
430   proto_tree_add_item(sdp_connection_info_tree,
431                       hf_connection_info_connection_address, tvb,
432                       offset,tokenlen,FALSE);
433   if(next_offset != -1){
434     offset = next_offset + 1;
435     next_offset = tvb_find_guint8(tvb,offset,-1,'/');
436     if( next_offset == -1){
437       tokenlen = -1;    /* end of tvbuff */
438     } else {
439       tokenlen = next_offset - offset;
440     }
441     proto_tree_add_item(sdp_connection_info_tree,
442                         hf_connection_info_ttl,tvb,offset,tokenlen,FALSE);
443     if(next_offset != -1){
444       offset = next_offset + 1;
445       proto_tree_add_item(sdp_connection_info_tree,
446                           hf_connection_info_num_addr, tvb,
447                           offset, -1, FALSE);
448     }
449   }
450 }
451
452 static void
453 dissect_sdp_bandwidth(tvbuff_t *tvb, proto_item *ti){
454   proto_tree * sdp_bandwidth_tree;
455   gint offset, next_offset, tokenlen;
456
457   offset = 0;
458   next_offset = 0;
459   tokenlen = 0;
460
461   sdp_bandwidth_tree = proto_item_add_subtree(ti,ett_sdp_bandwidth);
462
463   /* find the modifier */
464   next_offset = tvb_find_guint8(tvb,offset,-1,':');
465
466   if( next_offset == -1)
467     return;
468
469   tokenlen = next_offset - offset;
470
471   proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_modifier,
472                       tvb, offset, tokenlen, FALSE);
473
474   offset = next_offset + 1;
475
476   proto_tree_add_item(sdp_bandwidth_tree, hf_bandwidth_value,
477                       tvb, offset, -1, FALSE);
478
479 }
480
481 static void dissect_sdp_time(tvbuff_t *tvb, proto_item* ti){
482   proto_tree *sdp_time_tree;
483   gint offset,next_offset, tokenlen;
484
485   offset = 0;
486   next_offset = 0;
487   tokenlen = 0;
488
489   sdp_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
490
491   /* get start time */
492   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
493   if( next_offset == -1 )
494     return;
495
496   tokenlen = next_offset - offset;
497   proto_tree_add_item(sdp_time_tree, hf_time_start, tvb,
498                       offset, tokenlen, FALSE);
499
500   /* get stop time */
501   offset = next_offset + 1;
502   proto_tree_add_item(sdp_time_tree,hf_time_start, tvb,
503                       offset, -1, FALSE);
504 }
505
506 static void dissect_sdp_repeat_time(tvbuff_t *tvb, proto_item* ti){
507   proto_tree *sdp_repeat_time_tree;
508   gint offset,next_offset, tokenlen;
509
510   offset = 0;
511   next_offset = 0;
512   tokenlen = 0;
513
514   sdp_repeat_time_tree = proto_item_add_subtree(ti,ett_sdp_time);
515
516   /* get interval */
517   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
518   if( next_offset == -1 )
519     return;
520
521   tokenlen = next_offset - offset;
522   proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_interval, tvb,
523                       offset, tokenlen, FALSE);
524
525   /* get duration */
526   offset = next_offset + 1;
527   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
528   if( next_offset == -1 )
529     return;
530
531   tokenlen = next_offset - offset;
532   proto_tree_add_item(sdp_repeat_time_tree,hf_repeat_time_duration, tvb,
533                       offset, tokenlen, FALSE);
534
535   /* get offsets */
536   do{
537     offset = next_offset +1;
538     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
539     if(next_offset != -1){
540       tokenlen = next_offset - offset;
541     } else {
542       tokenlen = -1;    /* end of tvbuff */
543     }
544     proto_tree_add_item(sdp_repeat_time_tree, hf_repeat_time_offset,
545                         tvb, offset, tokenlen, FALSE);
546   } while( next_offset != -1 );
547
548 }
549 static void
550 dissect_sdp_timezone(tvbuff_t *tvb, proto_item* ti){
551   proto_tree* sdp_timezone_tree;
552   gint offset, next_offset, tokenlen;
553   offset = 0;
554   next_offset = 0;
555   tokenlen = 0;
556
557   sdp_timezone_tree = proto_item_add_subtree(ti,ett_sdp_timezone);
558
559   do{
560     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
561     if(next_offset == -1)
562       break;
563     tokenlen = next_offset - offset;
564
565     proto_tree_add_item(sdp_timezone_tree,hf_timezone_time,tvb,
566                         offset, tokenlen, FALSE);
567     offset = next_offset + 1;
568     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
569     if(next_offset != -1){
570       tokenlen = next_offset - offset;
571     } else {
572       tokenlen = -1;    /* end of tvbuff */
573     }
574     proto_tree_add_item(sdp_timezone_tree,hf_timezone_offset,tvb,
575                         offset, tokenlen, FALSE);
576     offset = next_offset + 1;
577   } while (next_offset != -1);
578
579 }
580
581
582 static void dissect_sdp_encryption_key(tvbuff_t *tvb, proto_item * ti){
583   proto_tree *sdp_encryption_key_tree;
584   gint offset, next_offset, tokenlen;
585
586   offset = 0;
587   next_offset = 0;
588   tokenlen = 0;
589
590   sdp_encryption_key_tree = proto_item_add_subtree(ti,ett_sdp_encryption_key);
591
592   next_offset = tvb_find_guint8(tvb,offset,-1,':');
593
594   if(next_offset == -1)
595     return;
596
597   tokenlen = next_offset - offset;
598
599   proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_type,
600                       tvb, offset, tokenlen, FALSE);
601
602   offset = next_offset + 1;
603   proto_tree_add_item(sdp_encryption_key_tree,hf_encryption_key_data,
604                       tvb, offset, -1, FALSE);
605
606 }
607
608
609
610 static void dissect_sdp_session_attribute(tvbuff_t *tvb, proto_item * ti){
611   proto_tree *sdp_session_attribute_tree;
612   gint offset, next_offset, tokenlen;
613
614   offset = 0;
615   next_offset = 0;
616   tokenlen = 0;
617
618   sdp_session_attribute_tree = proto_item_add_subtree(ti,
619                                                       ett_sdp_session_attribute);
620
621   next_offset = tvb_find_guint8(tvb,offset,-1,':');
622
623   if(next_offset == -1)
624     return;
625
626   tokenlen = next_offset - offset;
627
628   proto_tree_add_item(sdp_session_attribute_tree,
629                       hf_session_attribute_field,
630                       tvb, offset, tokenlen, FALSE);
631
632   offset = next_offset + 1;
633   proto_tree_add_item(sdp_session_attribute_tree,
634                       hf_session_attribute_value,
635                       tvb, offset, -1, FALSE);
636
637 }
638
639 static void
640 dissect_sdp_media(tvbuff_t *tvb, proto_item *ti){
641   proto_tree *sdp_media_tree;
642   gint offset, next_offset, tokenlen;
643
644   offset = 0;
645   next_offset = 0;
646   tokenlen = 0;
647
648   sdp_media_tree = proto_item_add_subtree(ti,ett_sdp_media);
649
650   next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
651
652   if(next_offset == -1)
653     return;
654
655   tokenlen = next_offset - offset;
656
657   proto_tree_add_item(sdp_media_tree, hf_media_media, tvb,
658                       offset, tokenlen, FALSE);
659
660   offset = next_offset + 1;
661
662   next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
663   if(next_offset == -1)
664     return;
665   tokenlen = next_offset - offset;
666   next_offset = tvb_find_guint8(tvb,offset, tokenlen, '/');
667
668   if(next_offset != -1){
669     tokenlen = next_offset - offset;
670
671     proto_tree_add_item(sdp_media_tree, hf_media_port, tvb,
672                         offset, tokenlen, FALSE);
673     offset = next_offset + 1;
674     next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
675     if(next_offset == -1)
676       return;
677     tokenlen = next_offset - offset;
678     proto_tree_add_item(sdp_media_tree, hf_media_portcount, tvb,
679                         offset, tokenlen, FALSE);
680     offset = next_offset + 1;
681   } else {
682     next_offset = tvb_find_guint8(tvb,offset, -1, ' ');
683
684     if(next_offset == -1)
685       return;
686     tokenlen = next_offset - offset;
687
688     proto_tree_add_item(sdp_media_tree, hf_media_port, tvb,
689                         offset, tokenlen, FALSE);
690     offset = next_offset + 1;
691   }
692
693   next_offset = tvb_find_guint8(tvb,offset,-1,' ');
694
695   if( next_offset == -1)
696     return;
697
698   tokenlen = next_offset - offset;
699
700   proto_tree_add_item(sdp_media_tree, hf_media_proto, tvb,
701                       offset, tokenlen, FALSE);
702
703   do{
704     offset = next_offset + 1;
705     next_offset = tvb_find_guint8(tvb,offset,-1,' ');
706
707     if(next_offset == -1){
708       tokenlen = -1;    /* End of tvbuff */
709     } else {
710       tokenlen = next_offset - offset;
711     }
712
713     proto_tree_add_item(sdp_media_tree, hf_media_format, tvb,
714                         offset, tokenlen, FALSE);
715   } while (next_offset != -1);
716
717 }
718
719 static void dissect_sdp_media_attribute(tvbuff_t *tvb, proto_item * ti){
720   proto_tree *sdp_media_attribute_tree;
721   gint offset, next_offset, tokenlen;
722
723   offset = 0;
724   next_offset = 0;
725   tokenlen = 0;
726
727   sdp_media_attribute_tree = proto_item_add_subtree(ti,
728                                                       ett_sdp_media_attribute);
729
730   next_offset = tvb_find_guint8(tvb,offset,-1,':');
731
732   if(next_offset == -1)
733     return;
734
735   tokenlen = next_offset - offset;
736
737   proto_tree_add_item(sdp_media_attribute_tree,
738                       hf_media_attribute_field,
739                       tvb, offset, tokenlen, FALSE);
740
741   offset = next_offset + 1;
742   proto_tree_add_item(sdp_media_attribute_tree,
743                       hf_media_attribute_value,
744                       tvb, offset, -1, FALSE);
745
746 }
747
748 void
749 proto_register_sdp(void)
750 {
751   static hf_register_info hf[] = {
752     { &hf_protocol_version,
753       { "Session Description Protocol Version (v)",
754         "sdp.version", FT_STRING, BASE_NONE,NULL,0x0,
755         "Session Description Protocol Version", HFILL }},
756     { &hf_owner,
757       { "Owner/Creator, Session Id (o)",
758         "sdp.owner", FT_STRING, BASE_NONE, NULL, 0x0,
759         "Owner/Creator, Session Id", HFILL}},
760     { &hf_session_name,
761       { "Session Name (s)",
762         "sdp.session_name", FT_STRING, BASE_NONE,NULL, 0x0,
763         "Session Name", HFILL }},
764     { &hf_session_info,
765       { "Session Information (i)",
766         "sdp.session_info", FT_STRING, BASE_NONE, NULL, 0x0,
767         "Session Information", HFILL }},
768     { &hf_uri,
769       { "URI of Description (u)",
770         "sdp.uri", FT_STRING, BASE_NONE,NULL, 0x0,
771         "URI of Description", HFILL }},
772     { &hf_email,
773       { "E-mail Address (e)",
774         "sdp.email", FT_STRING, BASE_NONE, NULL, 0x0,
775         "E-mail Address", HFILL }},
776     { &hf_phone,
777       { "Phone Number (p)",
778         "sdp.phone", FT_STRING, BASE_NONE, NULL, 0x0,
779         "Phone Number", HFILL }},
780     { &hf_connection_info,
781       { "Connection Information (c)",
782         "sdp.connection_info", FT_STRING, BASE_NONE, NULL, 0x0,
783         "Connection Information", HFILL }},
784     { &hf_bandwidth,
785       { "Bandwidth Information (b)",
786         "sdp.bandwidth", FT_STRING, BASE_NONE, NULL, 0x0,
787         "Bandwidth Information", HFILL }},
788     { &hf_timezone,
789       { "Time Zone Adjustments (z)",
790         "sdp.timezone", FT_STRING, BASE_NONE, NULL, 0x0,
791         "Time Zone Adjustments", HFILL }},
792     { &hf_encryption_key,
793       { "Encryption Key (k)",
794         "sdp.encryption_key", FT_STRING, BASE_NONE, NULL, 0x0,
795         "Encryption Key", HFILL }},
796     { &hf_session_attribute,
797       { "Session Attribute (a)",
798         "sdp.session_attr", FT_STRING, BASE_NONE, NULL, 0x0,
799         "Session Attribute", HFILL }},
800     { &hf_media_attribute,
801       { "Media Attribute (a)",
802         "sdp.media_attr", FT_STRING, BASE_NONE, NULL, 0x0,
803         "Media Attribute", HFILL }},
804     { &hf_time,
805       { "Time Description, active time (t)",
806         "sdp.time", FT_STRING, BASE_NONE, NULL, 0x0,
807         "Time Description, active time", HFILL }},
808     { &hf_repeat_time,
809       { "Repeat Time (r)",
810         "sdp.repeat_time", FT_STRING, BASE_NONE, NULL, 0x0,
811         "Repeat Time", HFILL }},
812     { &hf_media,
813       { "Media Description, name and address (m)",
814         "sdp.media", FT_STRING, BASE_NONE, NULL, 0x0,
815         "Media Description, name and address", HFILL }},
816     { &hf_media_title,
817       { "Media Title (i)",
818         "sdp.media_title",FT_STRING, BASE_NONE, NULL, 0x0,
819         "Media Title", HFILL }},
820     { &hf_unknown,
821       { "Unknown",
822         "sdp.unknown",FT_STRING, BASE_NONE, NULL, 0x0,
823         "Unknown", HFILL }},
824     { &hf_invalid,
825       { "Invalid line",
826         "sdp.invalid",FT_STRING, BASE_NONE, NULL, 0x0,
827         "Invalid line", HFILL }},
828     { &hf_owner_username,
829       { "Owner Username",
830         "sdp.owner.username",FT_STRING, BASE_NONE, NULL, 0x0,
831         "Owner Username", HFILL }},
832     { &hf_owner_sessionid,
833       { "Session ID",
834         "sdp.owner.sessionid",FT_STRING, BASE_NONE, NULL, 0x0,
835         "Session ID", HFILL }},
836     { &hf_owner_version,
837       { "Session Version",
838         "sdp.owner.version",FT_STRING, BASE_NONE, NULL, 0x0,
839         "Session Version", HFILL }},
840     { &hf_owner_network_type,
841       { "Owner Network Type",
842         "sdp.owner.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
843         "Owner Network Type", HFILL }},
844     { &hf_owner_address_type,
845       { "Owner Address Type",
846         "sdp.owner.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
847         "Owner Address Type", HFILL }},
848     { &hf_owner_address,
849       { "Owner Address",
850         "sdp.owner.address",FT_STRING, BASE_NONE, NULL, 0x0,
851         "Owner Address", HFILL }},
852     { &hf_connection_info_network_type,
853       { "Connection Network Type",
854         "sdp.connection_info.network_type",FT_STRING, BASE_NONE, NULL, 0x0,
855         "Connection Network Type", HFILL }},
856     { &hf_connection_info_address_type,
857       { "Connection Address Type",
858         "sdp.connection_info.address_type",FT_STRING, BASE_NONE, NULL, 0x0,
859         "Connection Address Type", HFILL }},
860     { &hf_connection_info_connection_address,
861       { "Connection Address",
862         "sdp.connection_info.address",FT_STRING, BASE_NONE, NULL, 0x0,
863         "Connection Address", HFILL }},
864     { &hf_connection_info_ttl,
865       { "Connection TTL",
866         "sdp.connection_info.ttl",FT_STRING, BASE_NONE, NULL, 0x0,
867         "Connection TTL", HFILL }},
868     { &hf_connection_info_num_addr,
869       { "Connection Number of Addresses",
870         "sdp.connection_info.num_addr",FT_STRING, BASE_NONE, NULL, 0x0,
871         "Connection Number of Addresses", HFILL }},
872     { &hf_bandwidth_modifier,
873       { "Bandwidth Modifier",
874         "sdp.bandwidth.modifier",FT_STRING, BASE_NONE, NULL, 0x0,
875         "Bandwidth Modifier", HFILL }},
876     { &hf_bandwidth_value,
877       { "Bandwidth Value",
878         "sdp.bandwidth.value",FT_STRING, BASE_NONE, NULL, 0x0,
879         "Bandwidth Value", HFILL }},
880     { &hf_time_start,
881       { "Session Start Time",
882         "sdp.time.start",FT_STRING, BASE_NONE, NULL, 0x0,
883         "Session Start Time", HFILL }},
884     { &hf_time_stop,
885       { "Session Stop Time",
886         "sdp.time.stop",FT_STRING, BASE_NONE, NULL, 0x0,
887         "Session Stop Time", HFILL }},
888     { &hf_repeat_time_interval,
889       { "Repeat Interval",
890         "sdp.repeat_time.interval",FT_STRING, BASE_NONE, NULL, 0x0,
891         "Repeat Interval", HFILL }},
892     { &hf_repeat_time_duration,
893       { "Repeat Duration",
894         "sdp.repeat_time.duration",FT_STRING, BASE_NONE, NULL, 0x0,
895         "Repeat Duration", HFILL }},
896     { &hf_repeat_time_offset,
897       { "Repeat Offset",
898         "sdp.repeat_time.offset",FT_STRING, BASE_NONE, NULL, 0x0,
899         "Repeat Offset", HFILL }},
900     { &hf_timezone_time,
901       { "Timezone Time",
902         "sdp.timezone.time",FT_STRING, BASE_NONE, NULL, 0x0,
903         "Timezone Time", HFILL }},
904     { &hf_timezone_offset,
905       { "Timezone Offset",
906         "sdp.timezone.offset",FT_STRING, BASE_NONE, NULL, 0x0,
907         "Timezone Offset", HFILL }},
908     { &hf_encryption_key_type,
909       { "Key Type",
910         "sdp.encryption_key.type",FT_STRING, BASE_NONE, NULL, 0x0,
911         "Type", HFILL }},
912     { &hf_encryption_key_data,
913       { "Key Data",
914         "sdp.encryption_key.data",FT_STRING, BASE_NONE, NULL, 0x0,
915         "Data", HFILL }},
916     { &hf_session_attribute_field,
917       { "Session Attribute Fieldname",
918         "sdp.session_attr.field",FT_STRING, BASE_NONE, NULL, 0x0,
919         "Session Attribute Fieldname", HFILL }},
920     { &hf_session_attribute_value,
921       { "Session Attribute Value",
922         "sdp.session_attr.value",FT_STRING, BASE_NONE, NULL, 0x0,
923         "Session Attribute Value", HFILL }},
924     { &hf_media_media,
925       { "Media Type",
926         "sdp.media.media",FT_STRING, BASE_NONE, NULL, 0x0,
927         "Media Type", HFILL }},
928     { &hf_media_port,
929       { "Media Port",
930         "sdp.media.port",FT_STRING, BASE_NONE, NULL, 0x0,
931         "Media Port", HFILL }},
932     { &hf_media_portcount,
933       { "Media Port Count",
934         "sdp.media.portcount",FT_STRING, BASE_NONE, NULL, 0x0,
935         "Media Port Count", HFILL }},
936     { &hf_media_proto,
937       { "Media Proto",
938         "sdp.media.proto",FT_STRING, BASE_NONE, NULL, 0x0,
939         "Media Proto", HFILL }},
940     { &hf_media_format,
941       { "Media Format",
942         "sdp.media.format",FT_STRING, BASE_NONE, NULL, 0x0,
943         "Media Format", HFILL }},
944     { &hf_media_attribute_field,
945       { "Media Attribute Fieldname",
946         "sdp.media_attribute.field",FT_STRING, BASE_NONE, NULL, 0x0,
947         "Media Attribute Fieldname", HFILL }},
948     { &hf_media_attribute_value,
949       { "Media Attribute Value",
950         "sdp.media_attribute.value",FT_STRING, BASE_NONE, NULL, 0x0,
951         "Media Attribute Value", HFILL }},
952
953   };
954   static gint *ett[] = {
955     &ett_sdp,
956     &ett_sdp_owner,
957     &ett_sdp_connection_info,
958     &ett_sdp_bandwidth,
959     &ett_sdp_time,
960     &ett_sdp_repeat_time,
961     &ett_sdp_timezone,
962     &ett_sdp_encryption_key,
963     &ett_sdp_session_attribute,
964     &ett_sdp_media,
965     &ett_sdp_media_attribute,
966   };
967
968   proto_sdp = proto_register_protocol("Session Description Protocol",
969                                       "SDP", "sdp");
970   proto_register_field_array(proto_sdp, hf, array_length(hf));
971   proto_register_subtree_array(ett, array_length(ett));
972
973   /*
974    * Register the dissector by name, so other dissectors can
975    * grab it by name rather than just referring to it directly
976    * (you can't refer to it directly from a plugin dissector
977    * on Windows without stuffing it into the Big Transfer Vector).
978    */
979   register_dissector("sdp", dissect_sdp, proto_sdp);
980 }