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