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