some compilers dont like unnamed unions and structs
[obnox/wireshark/wip.git] / epan / dissectors / packet-btsdp.c
1 /* packet-btsdp.c
2  * Routines for Bluetooth SDP dissection
3  * Copyright 2002, Wolfgang Hansmann <hansmann@cs.uni-bonn.de>
4  *
5  * Refactored for wireshark checkin
6  *   Ronnie Sahlberg 2006
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  * 
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <glib.h>
35
36 #include <epan/packet.h>
37 #include <epan/value_string.h>
38 #include <epan/emem.h>
39 #include <etypes.h>
40 #include "packet-btl2cap.h"
41
42 /* Initialize the protocol and registered fields */
43 static int proto_btsdp = -1;
44 static int hf_pduid = -1;
45 static int hf_tid = -1;
46 static int hf_plen = -1;
47 static int hf_ssr_total_count = -1;
48 static int hf_ssr_current_count = -1;
49 static int hf_error_code = -1;
50 static int hf_ssares_al_bytecount = -1;
51
52
53 /* Initialize the subtree pointers */
54 static gint ett_btsdp = -1;
55 static gint ett_btsdp_ssr = -1;
56 static gint ett_btsdp_des = -1;
57 static gint ett_btsdp_attribute = -1;
58 static gint ett_btsdp_service_search_pattern = -1;
59 static gint ett_btsdp_attribute_idlist = -1;
60
61 static const value_string vs_pduid[] = {
62         {0x1, "SDP_ErrorResponse"},
63         {0x2, "SDP_ServiceSearchRequest"},
64         {0x3, "SDP_ServiceSearchResponse"},
65         {0x4, "SDP_ServiceAttributeRequest"},
66         {0x5, "SDP_ServiceAttributeResponse"},
67         {0x6, "SDP_ServiceSearchAttributeRequest"},
68         {0x7, "SDP_ServiceSearchAttributeResponse"},
69         {0, NULL}
70 };
71
72 static const value_string vs_error_code[] = {
73         {0x0001, "Invalid/unsupported SDP version"},
74         {0x0002, "Invalid Service Record Handle"},
75         {0x0003, "Invalid request syntax"},
76         {0x0004, "Invalid PDU size"},
77         {0x0005, "Invalid Continuation State"},
78         {0x0006, "Insufficient Resources to satisfy Request"},
79         {0, NULL}
80 };
81
82 static const value_string vs_general_attribute_id[] = {
83         {0x0000, "ServiceRecordHandle"},
84         {0x0001, "ServiceClassIDList"},
85         {0x0002, "ServiceRecordState"},
86         {0x0003, "ServiceID"},
87         {0x0004, "ProtocolDescriptorList"},
88         {0x0005, "BrowseGroupList"},
89         {0x0006, "LanguageBaseAttributeIDList"},
90         {0x0007, "ServiceinfoTimeToLive"},
91         {0x0008, "ServiceAvailability"},
92         {0x0009, "BluetoothProfileDescriptorList"},
93         {0x000a, "DocumentationURL"},
94         {0x000b, "ClientExecutableURL"},
95         {0x000c, "IconURL"},
96         {0x0100, "Service Name"},
97         {0x0101, "Service Description"},
98         {0x0102, "Service Provider"},
99         {0, NULL}
100 };
101
102
103 static const value_string vs_protocols[] = {
104         {0x0001, "SDP"},
105         {0x0002, "UDP"},
106         {0x0003, "RFCOMM"},
107         {0x0004, "TCP"},
108         {0x0005, "TCS-BIN"},
109         {0x0006, "TCS-AT"},
110         {0x0008, "OBEX"},
111         {0x0009, "IP"},
112         {0x000A, "FTP"},
113         {0x000C, "HTTP"},
114         {0x000E, "WSP"},
115         {0x000F, "BNEP"},
116         {0x0010, "UPNP"},
117         {0x0011, "HIDP"},
118         {0x0012, "HardcopyControlChannel"},
119         {0x0014, "HardcopyDataChannel"},
120         {0x0016, "HardcopyNotification"},
121         {0x0017, "AVCTP"},
122         {0x0019, "AVDTP"},
123         {0x001B, "CMPT"},
124         {0x001D, "UDI_C-Plane"},
125         {0x0100, "L2CAP"},
126         {0, NULL}
127 };
128
129 static const value_string vs_service_classes[] = {
130
131         {0x0001, "SDP"},
132         {0x0002, "UDP"},
133         {0x0003, "RFCOMM"},
134         {0x0004, "TCP"},
135         {0x0005, "TCS-BIN"},
136         {0x0006, "TCS-AT"},
137         {0x0008, "OBEX"},
138         {0x0009, "IP"},
139         {0x000A, "FTP"},
140         {0x000C, "HTTP"},
141         {0x000E, "WSP"},
142         {0x000F, "BNEP"},
143         {0x0010, "UPNP"},
144         {0x0011, "HIDP"},
145         {0x0012, "HardcopyControlChannel"},
146         {0x0014, "HardcopyDataChannel"},
147         {0x0016, "HardcopyNotification"},
148         {0x0017, "AVCTP"},
149         {0x0019, "AVDTP"},
150         {0x001B, "CMPT"},
151         {0x001D, "UDI_C-Plane"},
152         {0x0100, "L2CAP"},
153         {0x1000, "ServiceDiscoveryServerServiceClassID"},
154         {0x1001, "BrowseGroupDescriptorServiceClassID"},
155         {0x1002, "PublicBrowseGroup"},
156         {0x1101, "SerialPort"},
157         {0x1102, "LANAccessUsingPPP"},
158         {0x1103, "DialupNetworking"},
159         {0x1104, "IrMCSync"},
160         {0x1105, "OBEXObjectPush"},
161         {0x1106, "OBEXFileTransfer"},
162         {0x1107, "IrMCSyncCommand"},
163         {0x1108, "Headset"},
164         {0x1109, "CordlessTelephony"},
165         {0x110A, "AudioSource"},
166         {0x110B, "AudioSink"},
167         {0x110C, "A/V_RemoteControlTarget"},
168         {0x110D, "AdvancedAudioDistribution"},
169         {0x110E, "A/V_RemoteControl"},
170         {0x110F, "VideoConferencing"},
171         {0x1110, "Intercom"},
172         {0x1111, "Fax"},
173         {0x1112, "HeadsetAudioGateway"},
174         {0x1113, "WAP"},
175         {0x1114, "WAP_CLIENT"},
176         {0x1115, "PANU"},
177         {0x1116, "NAP"},
178         {0x1117, "GN"},
179         {0x1118, "DirectPrinting"},
180         {0x1119, "ReferencePrinting"},
181         {0x111A, "Imaging"},
182         {0x111B, "ImagingResponder"},
183         {0x111C, "ImagingAutomaticArchive"},
184         {0x111D, "ImagingReferencedObjects"},
185         {0x1115, "PANU"},
186         {0x1116, "NAP"},
187         {0x1117, "GN"},
188         {0x1118, "DirectPrinting"},
189         {0x1119, "ReferencePrinting"},
190         {0x111A, "Imaging"},
191         {0x111B, "ImagingResponder"},
192         {0x111C, "ImagingAutomaticArchive"},
193         {0x111D, "ImagingReferencedObjects"},
194         {0x111E, "Handsfree"},
195         {0x111F, "HandsfreeAudioGateway"},
196         {0x1120, "DirectPrintingReferenceObjectsService"},
197         {0x1121, "ReflectedUI"},
198         {0x1122, "BasicPrinting"},
199         {0x1123, "PrintingStatus"},
200         {0x1124, "HumanInterfaceDeviceService"},
201         {0x1125, "HardcopyCableReplacement"},
202         {0x1126, "HCR_Print"},
203         {0x1127, "HCR_Scan"},
204         {0x1128, "Common_ISDN_Access"},
205         {0x1129, "VideoConferencingGW"},
206         {0x112A, "UDI_MT"},
207         {0x112B, "UDI_TA"},
208         {0x112C, "Audio/Video"},
209         {0x112D, "SIM_Access"},
210         {0x1200, "PnPInformation"},
211         {0x1201, "GenericNetworking"},
212         {0x1202, "GenericFileTransfer"},
213         {0x1203, "GenericAudio"},
214         {0x1204, "GenericTelephony"},
215         {0x1205, "UPNP_Service"},
216         {0x1206, "UPNP_IP_Service"},
217         {0x1300, "ESDP_UPNP_IP_PAN"},
218         {0x1301, "ESDP_UPNP_IP_LAP"},
219         {0x1302, "ESDP_UPNP_L2CAP"},
220         {0, NULL}
221 };
222
223
224
225 static int 
226 get_type_length(tvbuff_t *tvb, int offset, int *length)
227 {
228         int size = 0;
229         guint8 byte0 = tvb_get_guint8(tvb, offset);
230         offset++;
231         
232         switch (byte0 & 0x07) {
233         case 0:
234                 size = (byte0 >> 3) == 0 ? 0 : 1;
235                 break;
236         case 1:
237                 size = 2;
238                 break;
239         case 2:
240                 size = 4;
241                 break;
242         case 3:         
243                 size = 8;
244                 break;
245         case 4:
246                 size = 16;
247                 break;
248         case 5:
249                 size = tvb_get_guint8(tvb, offset);
250                 offset++;
251                 break;
252         case 6:
253                 size = tvb_get_ntohs(tvb, offset);
254                 offset += 2;
255                 break;
256         case 7:
257                 size = tvb_get_ntohl(tvb, offset);
258                 offset += 4;
259                 break;          
260         }
261
262         *length = size;
263         return offset;
264 }
265
266
267 static guint32 
268 get_uint_by_size(tvbuff_t *tvb, int off, int size) 
269 {
270         switch(size) {
271         case 0:
272                 return tvb_get_guint8(tvb, off);
273         case 1:
274                 return tvb_get_ntohs(tvb, off);
275         case 2:
276                 return tvb_get_ntohl(tvb, off);
277         default:
278                 return 0xffffffff;
279         }
280 }
281
282
283 static gint32 
284 get_int_by_size(tvbuff_t *tvb, int off, int size) 
285 {
286         switch(size) {
287         case 0:
288                 return tvb_get_guint8(tvb, off);
289         case 1:
290                 return tvb_get_ntohs(tvb, off);
291         case 2:
292                 return tvb_get_ntohl(tvb, off);
293         default:
294                 return -1;
295         }
296 }
297
298
299 static int 
300 dissect_attribute_id_list(proto_tree *t, tvbuff_t *tvb, int offset)
301 {
302         proto_item *ti;
303         proto_tree *st;
304         int start_offset, bytes_to_go;
305
306         start_offset=offset;
307         ti = proto_tree_add_text(t, tvb, offset, 2, "AttributeIDList");
308         st = proto_item_add_subtree(ti, ett_btsdp_attribute_idlist);
309
310         offset = get_type_length(tvb, offset, &bytes_to_go);
311         proto_item_set_len(ti, offset - start_offset + bytes_to_go);
312
313         while(bytes_to_go>0){
314                 guint8 byte0 = tvb_get_guint8(tvb, offset);
315
316                 if (byte0 == 0x09) { /* 16 bit attribute id */
317
318                         proto_tree_add_text(st, tvb, offset, 3, "0x%04x", 
319                                             tvb_get_ntohs(tvb, offset + 1));
320                         offset+=3;
321                         bytes_to_go-=3;
322                 } else if (byte0 == 0x0a) { /* 32 bit attribute range */
323
324                         proto_tree_add_text(st, tvb, offset, 5, "0x%04x - 0x%04x", 
325                                             tvb_get_ntohs(tvb, offset + 1),
326                                             tvb_get_ntohs(tvb, offset + 3));
327                         offset+=5;
328                         bytes_to_go-=5;
329                 }
330         }
331         return offset - start_offset;
332 }
333
334
335 static int
336 dissect_sdp_error_response(proto_tree *t, tvbuff_t *tvb, int offset) {
337         
338         proto_tree_add_item(t, hf_error_code, tvb, offset, 2, FALSE);
339         offset+=2;
340
341         return offset;
342 }
343
344
345 static int
346 dissect_sdp_type(proto_tree *t, tvbuff_t *tvb, int offset, char **attr_val)
347 {
348 #define MAX_SDP_LEN 1024
349         int strpos=0, size, start_offset, type_size;
350         char *str;
351         guint8 byte0;
352         guint8 type;
353         guint8 size_index;
354
355
356         str=ep_alloc(MAX_SDP_LEN+1);
357         *attr_val=str;
358         str[0]=0;
359
360         byte0=tvb_get_guint8(tvb, offset);
361         type=(byte0>>3)&0x1f;
362         size_index=byte0&0x07;
363
364         start_offset=offset;
365         offset = get_type_length(tvb, offset, &size);
366         type_size = offset - start_offset + size;
367
368
369         switch (type) {
370         case 0:
371                 proto_tree_add_text(t, tvb, start_offset, type_size, "Nil ");
372                 if(strpos<MAX_SDP_LEN){
373                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "Nil ");
374                 }
375                 break;
376         case 1: {
377                 guint32 val = get_uint_by_size(tvb, offset, size_index);
378                 proto_tree_add_text(t, tvb, start_offset, type_size, 
379                                     "unsigned int %d ", val);
380                 if(strpos<MAX_SDP_LEN){
381                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "%u ", val);
382                 }
383                 break;
384         }
385         case 2: {
386                 guint32 val = get_int_by_size(tvb, offset, size_index);
387                 proto_tree_add_text(t, tvb, start_offset, type_size, 
388                                     "signed int %d ", val);
389                 if(strpos<MAX_SDP_LEN){
390                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "%d ", val);
391                 }
392                 break;
393         }
394         case 3: {
395                 char *ptr = tvb_bytes_to_str(tvb, offset, size);
396
397                 if(size == 2){
398
399                         guint16 id = tvb_get_ntohs(tvb, offset);        
400                         const char *uuid_name = val_to_str(id, vs_service_classes, "Unknown");
401
402                         proto_tree_add_text(t, tvb, start_offset, type_size,
403                                             "%s(0x%s) ", uuid_name, ptr);
404                         if(strpos<MAX_SDP_LEN){
405                                 strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "UUID:%s (0x%s) ", uuid_name, ptr);
406                         }
407                 } else {
408
409                         proto_tree_add_text(t, tvb, start_offset, type_size, 
410                                             "UUID 0x%s ", ptr);
411                         if(strpos<MAX_SDP_LEN){
412                                 strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "0x%s ", ptr);
413                         }
414                 }
415                 break;
416         }
417         case 8: /* fall through */
418         case 4: {
419                 char *ptr = tvb_get_ephemeral_string(tvb, offset, size);
420                 
421                 proto_tree_add_text(t, tvb, start_offset, type_size, "%s \"%s\"", 
422                                     type == 8 ? "URL" : "String", ptr);
423                 if(strpos<MAX_SDP_LEN){
424                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "%s ", ptr);
425                 }
426                 break;
427         }
428         case 5: {
429                 guint8 var = tvb_get_guint8(tvb, offset);
430
431                 proto_tree_add_text(t, tvb, start_offset, type_size, "%s", 
432                                     var ? "true" : "false");
433                 if(strpos<MAX_SDP_LEN){
434                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "%s ", var?"true":"false");
435                 }
436                 break;
437         }
438         case 6: /* Data Element sequence */
439         case 7: /* Data Element alternative */ {
440                 proto_tree *st;
441                 proto_item *ti;
442                 int bytes_to_go = size;
443                 int first = 1;
444                 char *substr;
445
446                 ti = proto_tree_add_text(t, tvb, start_offset, type_size, "%s", 
447                                          type == 6 ? "Data Element sequence" : 
448                                          "Data Element alternative");
449                 st = proto_item_add_subtree(ti, ett_btsdp_des);
450
451                 if(strpos<MAX_SDP_LEN){
452                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "{ ");
453                 }
454
455                 while(bytes_to_go > 0){
456                         if(!first){
457                                 if(strpos<MAX_SDP_LEN){
458                                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, ", ");
459                                 }
460                         } else {
461                                 first = 0;
462                         }
463
464                         size = dissect_sdp_type(st, tvb, offset, &substr);
465                         if(strpos<MAX_SDP_LEN){
466                                 strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "%s ", substr);
467                         }
468                         offset += size;
469                         bytes_to_go -= size;
470                 }
471
472                 if(strpos<MAX_SDP_LEN){
473                         strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "} ");
474                 }
475                 break;
476         }
477         }
478
479         /* make sure the string is 0 terminated */
480         str[MAX_SDP_LEN]=0;
481
482         return type_size;
483 }
484
485
486
487
488 static int 
489 dissect_sdp_service_attribute(proto_tree *tree, tvbuff_t *tvb, int offset)
490 {
491
492         proto_tree *st, *ti_sa, *ti_av;
493         int size;
494         const char *att_name;
495         guint16 id;
496         char *attr_val;
497
498         id = tvb_get_ntohs(tvb, offset+1);
499         att_name = val_to_str(id, vs_general_attribute_id, "Unknown");
500         
501         ti_sa = proto_tree_add_text(tree, tvb, offset, -1, 
502                                     "Service Attribute: id = %s (0x%x)", att_name, id);
503         st = proto_item_add_subtree(ti_sa, ett_btsdp_attribute);
504         
505
506         proto_tree_add_text(st, tvb, offset, 3, "Attribute ID: %s (0x%x)", att_name, id);
507         ti_av = proto_tree_add_text(st, tvb, offset + 3, -1, "Attribute Value");
508         st = proto_item_add_subtree(ti_av, ett_btsdp_attribute);
509
510
511         size = dissect_sdp_type(st, tvb, offset + 3, &attr_val);
512         proto_item_append_text(ti_sa, ", value = %s", attr_val);
513
514
515         proto_item_set_len(ti_sa, size + 3);
516         proto_item_set_len(ti_av, size);
517
518         return offset+size+3;
519 }
520
521
522 static int 
523 dissect_sdp_service_attribute_list(proto_tree *tree, tvbuff_t *tvb, int offset)
524 {
525         proto_item *ti;
526         proto_tree *st;
527         int start_offset = offset, len;
528
529         offset = get_type_length(tvb, offset, &len);
530
531         ti = proto_tree_add_text(tree, tvb, start_offset, -1, "AttributeList");
532         st = proto_item_add_subtree(ti, ett_btsdp_attribute);
533
534         if(!len){
535                 return offset;
536         }
537
538         while (offset - start_offset < len) {
539                 offset = dissect_sdp_service_attribute(st, tvb, offset);
540         }
541
542         proto_item_set_len(ti, offset - start_offset);
543         return offset;
544 }
545
546
547
548 static int 
549 dissect_sdp_service_attribute_list_array(proto_tree *tree, tvbuff_t *tvb, int offset)
550 {
551         proto_item *ti;
552         proto_tree *st;
553         int start_offset, len;
554         
555         start_offset=offset;
556         offset = get_type_length(tvb, offset, &len);
557         ti = proto_tree_add_text(tree, tvb, start_offset, offset-start_offset+len, "AttributeLists");
558         st = proto_item_add_subtree(ti, ett_btsdp_attribute);
559
560         start_offset=offset;
561         while(offset-start_offset < len) {
562                 offset = dissect_sdp_service_attribute_list(st, tvb, offset);
563         }
564
565         return offset;
566 }
567
568
569
570 static int
571 dissect_sdp_service_search_attribute_response(proto_tree *tree, tvbuff_t *tvb, int offset) 
572 {
573
574         proto_tree_add_item(tree, hf_ssares_al_bytecount, tvb, offset, 2, FALSE);
575         offset += 2;
576
577         offset += dissect_sdp_service_attribute_list_array(tree, tvb, offset);
578
579         return offset;
580 }
581
582
583 static int
584 dissect_sdp_service_search_attribute_request(proto_tree *t, tvbuff_t *tvb, int offset)
585 {
586         proto_tree *st;
587         proto_item *ti;
588         int start_offset;
589         int size, bytes_to_go;
590         char *str;
591
592         start_offset = offset;
593         ti = proto_tree_add_text(t, tvb, offset, 2, "ServiceSearchPattern");
594         st = proto_item_add_subtree(ti, ett_btsdp_attribute);
595
596         offset = get_type_length(tvb, offset, &bytes_to_go);
597         proto_item_set_len(ti, offset - start_offset + bytes_to_go);
598
599
600         while(bytes_to_go>0) {
601                 size = dissect_sdp_type(st, tvb, offset, &str);
602                 proto_item_append_text(st, " %s", str);
603                 offset+=size;
604                 bytes_to_go-=size;
605         }
606
607         /* dissect maximum attribute byte count */
608         proto_tree_add_text(t, tvb, offset, 2, "MaximumAttributeByteCount: %d", tvb_get_ntohs(tvb, offset));
609         offset+=2;
610
611
612         offset += dissect_attribute_id_list(t, tvb, offset);
613
614         proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
615
616         return offset;
617 }
618
619 static int 
620 dissect_sdp_service_attribute_response(proto_tree *t, tvbuff_t *tvb, int offset)
621 {
622         proto_tree_add_text(t, tvb, offset, 2, "AttributeListByteCount: %d",
623                             tvb_get_ntohs(tvb, offset));
624         offset+=2;
625         
626         offset = dissect_sdp_service_attribute_list(t, tvb, offset);
627
628         proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
629         offset+=tvb_length_remaining(tvb, offset);
630
631         return offset;
632 }
633
634
635 static int 
636 dissect_sdp_service_attribute_request(proto_tree *t, tvbuff_t *tvb, int offset)
637 {
638         proto_tree_add_text(t, tvb, offset, 4, "ServiceRecordHandle: 0x%x", 
639                             tvb_get_ntohl(tvb, offset));
640         offset+=4;
641
642         proto_tree_add_text(t, tvb, offset, 2, "MaximumAttributeByteCount: %d", 
643                             tvb_get_ntohs(tvb, offset));
644         offset+=2;
645
646         offset += dissect_attribute_id_list(t, tvb, offset);
647
648         proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
649         offset+=tvb_length_remaining(tvb, offset);
650         return offset;
651 }
652
653
654 static int 
655 dissect_sdp_service_search_request(proto_tree *t, tvbuff_t *tvb, int offset)
656 {
657         int start_offset, bytes_to_go, size;
658         proto_item *ti;
659         proto_tree *st;
660   
661         start_offset=offset;
662         ti = proto_tree_add_text(t, tvb, offset, 2, "ServiceSearchPattern");
663         st = proto_item_add_subtree(ti, ett_btsdp_service_search_pattern);
664
665         offset = get_type_length(tvb, offset, &bytes_to_go);
666         proto_item_set_len(ti, offset - start_offset + bytes_to_go);
667
668         while(bytes_to_go>0){
669                 char *str;
670                 size = dissect_sdp_type(st, tvb, offset, &str);
671                 proto_item_append_text(st, " %s", str);
672                 offset+=size;
673                 bytes_to_go-=size;
674         }
675
676         /* dissect maximum service record count */
677
678         proto_tree_add_text(t, tvb, offset, 2, "MaximumServiceRecordCount: %d", 
679                             tvb_get_ntohs(tvb, offset));
680         offset+=2;
681
682         proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
683         offset+=tvb_length_remaining(tvb, offset);
684         return offset;
685 }
686
687
688 static int 
689 dissect_sdp_service_search_response(proto_tree *t, tvbuff_t *tvb, int offset)
690 {
691         proto_tree *st;
692         proto_item *ti;
693         guint16 curr_count;
694         
695         proto_tree_add_item(t, hf_ssr_total_count, tvb, offset, 2, FALSE);
696         offset+=2;
697
698         curr_count = tvb_get_ntohs(tvb, offset);
699         proto_tree_add_item(t, hf_ssr_current_count, tvb, offset, 2, FALSE);
700         offset+=2;
701
702         ti = proto_tree_add_text(t, tvb, offset, 
703                                  curr_count * 4, "ServiceRecordHandleList");
704         st = proto_item_add_subtree(ti, ett_btsdp_ssr);
705         offset+=4;
706
707         while(curr_count>0){
708                 proto_tree_add_text(st, tvb, offset, 4, "0x%x", tvb_get_ntohl(tvb, offset));
709                 offset+=4;
710                 curr_count--;
711         }
712
713         proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
714         offset+=tvb_length_remaining(tvb, offset);
715
716         return offset;
717 }
718
719
720 static void 
721 dissect_btsdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
722 {
723         proto_item *ti;
724         proto_tree *st;
725         guint8 pdu;
726         guint16 plen;
727         const char *pdu_name;
728         int offset=0;
729
730         if (check_col(pinfo->cinfo, COL_PROTOCOL))
731                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SDP");
732
733         ti = proto_tree_add_item(tree, proto_btsdp, tvb, 0, -1, FALSE);
734         st = proto_item_add_subtree(ti, ett_btsdp);
735
736         /* pdu id */
737         pdu = tvb_get_guint8(tvb, offset);
738         proto_tree_add_item(st, hf_pduid, tvb, offset, 1, FALSE);
739         pdu_name = val_to_str(pdu, vs_pduid, "Unknown");
740         if (check_col(pinfo->cinfo, COL_INFO)) {
741                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s ",pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd", pdu_name);
742         }
743         proto_item_append_text(ti, ": %s (0x%x)", pdu_name, pdu);
744         offset++;
745
746         /* tid */
747         proto_tree_add_item(st, hf_tid, tvb, offset, 2, FALSE);
748         offset+=2;
749
750         /* plen */
751         plen = tvb_get_ntohs(tvb, offset);
752         proto_tree_add_item(st, hf_plen, tvb, offset, 2, FALSE);
753         offset+=2;
754
755         switch(pdu) {
756         case 0x1:
757                 offset=dissect_sdp_error_response(st, tvb, offset);
758                 break;
759         case 0x2:
760                 offset=dissect_sdp_service_search_request(st, tvb, offset);
761                 break;
762         case 0x3:
763                 offset=dissect_sdp_service_search_response(st, tvb, offset);
764                 break;
765         case 0x4:
766                 offset=dissect_sdp_service_attribute_request(st, tvb, offset);
767                 break;
768         case 0x5:
769                 offset=dissect_sdp_service_attribute_response(st, tvb, offset);
770                 break;
771         case 0x6:
772                 offset=dissect_sdp_service_search_attribute_request(st, tvb, offset);
773                 break;
774         case 07:
775                 offset=dissect_sdp_service_search_attribute_response(st, tvb, offset);
776                 break;
777         }
778 }
779
780
781 void 
782 proto_register_btsdp(void)
783 {                   
784         static hf_register_info hf[] = {
785                 {&hf_pduid,
786                         {"PDU", "btsdp.pdu",
787                         FT_UINT8, BASE_HEX, VALS(vs_pduid), 0,          
788                         "PDU type", HFILL}
789                 },
790                 {&hf_tid,
791                         {"TransactionID", "btsdp.tid",
792                         FT_UINT16, BASE_HEX, NULL, 0,          
793                         "Transaction ID", HFILL}
794                 },
795                 {&hf_plen,
796                         {"ParameterLength", "btsdp.len",
797                         FT_UINT16, BASE_DEC, NULL, 0,          
798                         "ParameterLength", HFILL}
799                 },
800                 {&hf_error_code, 
801                         {"ErrorCode", "btsdp.error_code", 
802                         FT_UINT16, BASE_HEX, NULL, 0, 
803                          "Error Code", HFILL}
804                 },
805                 {&hf_ssr_total_count,
806                         {"TotalServiceRecordCount", "btsdp.ssr.total_count",
807                         FT_UINT16, BASE_DEC, NULL, 0,
808                          "Total count of service records", HFILL}
809                 },
810                 {&hf_ssr_current_count,
811                         {"CurrentServiceRecordCount", "btsdp.ssr.current_count",
812                         FT_UINT16, BASE_DEC, NULL, 0,
813                          "count of service records in this message", HFILL}
814                 },
815                 {&hf_ssares_al_bytecount,
816                         {"AttributeListsByteCount", "btsdp.ssares.byte_count",
817                         FT_UINT16, BASE_DEC, NULL, 0,
818                          "count of bytes in attribute list response", HFILL}
819                 }
820         };
821
822         /* Setup protocol subtree array */
823
824         static gint *ett[] = {
825                 &ett_btsdp,
826                 &ett_btsdp_ssr,
827                 &ett_btsdp_des,
828                 &ett_btsdp_attribute,
829                 &ett_btsdp_service_search_pattern,
830                 &ett_btsdp_attribute_idlist
831         };
832
833         proto_btsdp = proto_register_protocol("Bluetooth SDP", "BTSDP", "btsdp");
834
835         register_dissector("btsdp", dissect_btsdp, proto_btsdp);
836         
837         /* Required function calls to register the header fields and subtrees used */
838         proto_register_field_array(proto_btsdp, hf, array_length(hf));
839         proto_register_subtree_array(ett, array_length(ett));
840 }
841
842
843 void
844 proto_reg_handoff_btsdp(void)
845 {
846         dissector_handle_t btsdp_handle;
847
848         btsdp_handle = find_dissector("btsdp");
849         dissector_add("btl2cap.psm", BTL2CAP_PSM_SDP, btsdp_handle);
850 }