]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bluetooth/sdpcontrol/search.c
MFV r323530,r323533,r323534: 7431 ZFS Channel Programs, and followups
[FreeBSD/FreeBSD.git] / usr.sbin / bluetooth / sdpcontrol / search.c
1 /*
2  * search.c
3  *
4  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
29  * $FreeBSD$
30  */
31
32 #include <netinet/in.h>
33 #define L2CAP_SOCKET_CHECKED
34 #include <bluetooth.h>
35 #include <ctype.h>
36 #include <sdp.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include "sdpcontrol.h"
40
41 /* List of the attributes we are looking for */
42 static uint32_t attrs[] =
43 {
44         SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE,
45                         SDP_ATTR_SERVICE_RECORD_HANDLE),
46         SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST,
47                         SDP_ATTR_SERVICE_CLASS_ID_LIST),
48         SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
49                         SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
50         SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
51                         SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
52 };
53 #define attrs_len       (sizeof(attrs)/sizeof(attrs[0]))
54
55 /* Buffer for the attributes */
56 #define NRECS   25      /* request this much records from the SDP server */
57 #define BSIZE   256     /* one attribute buffer size */
58 static uint8_t          buffer[NRECS * attrs_len][BSIZE];
59
60 /* SDP attributes */
61 static sdp_attr_t       values[NRECS * attrs_len];
62 #define values_len      (sizeof(values)/sizeof(values[0]))
63
64 /*
65  * Print Service Class ID List
66  *
67  * The ServiceClassIDList attribute consists of a data element sequence in 
68  * which each data element is a UUID representing the service classes that
69  * a given service record conforms to. The UUIDs are listed in order from 
70  * the most specific class to the most general class. The ServiceClassIDList
71  * must contain at least one service class UUID.
72  */
73
74 static void
75 print_service_class_id_list(uint8_t const *start, uint8_t const *end)
76 {
77         uint32_t        type, len, value;
78
79         if (end - start < 2) {
80                 fprintf(stderr, "Invalid Service Class ID List. " \
81                                 "Too short, len=%zd\n", end - start);
82                 return;
83         }
84
85         SDP_GET8(type, start);
86         switch (type) {
87         case SDP_DATA_SEQ8:
88                 SDP_GET8(len, start);
89                 break;
90
91         case SDP_DATA_SEQ16:
92                 SDP_GET16(len, start);
93                 break;
94
95         case SDP_DATA_SEQ32:
96                 SDP_GET32(len, start);
97                 break;
98
99         default:
100                 fprintf(stderr, "Invalid Service Class ID List. " \
101                                 "Not a sequence, type=%#x\n", type);
102                 return;
103                 /* NOT REACHED */
104         }
105
106         if (len > (end - start)) {
107                 fprintf(stderr, "Invalid Service Class ID List. " \
108                                 "Too long len=%d\n", len);
109                 return;
110         }
111
112         while (start < end) {
113                 SDP_GET8(type, start);
114                 switch (type) {
115                 case SDP_DATA_UUID16:
116                         SDP_GET16(value, start);
117                         fprintf(stdout, "\t%s (%#4.4x)\n",
118                                         sdp_uuid2desc(value), value);
119                         break;
120
121                 case SDP_DATA_UUID32:
122                         SDP_GET32(value, start);
123                         fprintf(stdout, "\t%#8.8x\n", value);
124                         break;
125
126                 case SDP_DATA_UUID128: {
127                         int128_t        uuid;
128
129                         SDP_GET_UUID128(&uuid, start);
130                         fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
131                                         ntohl(*(uint32_t *)&uuid.b[0]),
132                                         ntohs(*(uint16_t *)&uuid.b[4]),
133                                         ntohs(*(uint16_t *)&uuid.b[6]),
134                                         ntohs(*(uint16_t *)&uuid.b[8]),
135                                         ntohs(*(uint16_t *)&uuid.b[10]),
136                                         ntohl(*(uint32_t *)&uuid.b[12]));
137                         } break;
138
139                 default:
140                         fprintf(stderr, "Invalid Service Class ID List. " \
141                                         "Not a UUID, type=%#x\n", type);
142                         return;
143                         /* NOT REACHED */
144                 }
145         }
146 } /* print_service_class_id_list */
147
148 /*
149  * Print Protocol Descriptor List
150  *
151  * If the ProtocolDescriptorList describes a single stack, it takes the form 
152  * of a data element sequence in which each element of the sequence is a 
153  * protocol descriptor. Each protocol descriptor is, in turn, a data element 
154  * sequence whose first element is a UUID identifying the protocol and whose 
155  * successive elements are protocol-specific parameters. The protocol 
156  * descriptors are listed in order from the lowest layer protocol to the 
157  * highest layer protocol used to gain access to the service. If it is possible
158  * for more than one kind of protocol stack to be used to gain access to the 
159  * service, the ProtocolDescriptorList takes the form of a data element 
160  * alternative where each member is a data element sequence as described above.
161  */
162
163 static void
164 print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
165 {
166         union {
167                 uint8_t         uint8;
168                 uint16_t        uint16;
169                 uint32_t        uint32;
170                 uint64_t        uint64;
171                 int128_t        int128;
172         }                       value;
173         uint32_t                type, len, param;
174
175         /* Get Protocol UUID */
176         SDP_GET8(type, start);
177         switch (type) {
178         case SDP_DATA_UUID16:
179                 SDP_GET16(value.uint16, start);
180                 fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
181                                 value.uint16);
182                 break;
183
184         case SDP_DATA_UUID32:
185                 SDP_GET32(value.uint32, start);
186                 fprintf(stdout, "\t%#8.8x\n", value.uint32);
187                 break;
188
189         case SDP_DATA_UUID128:
190                 SDP_GET_UUID128(&value.int128, start);
191                 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
192                                 ntohl(*(uint32_t *)&value.int128.b[0]),
193                                 ntohs(*(uint16_t *)&value.int128.b[4]),
194                                 ntohs(*(uint16_t *)&value.int128.b[6]),
195                                 ntohs(*(uint16_t *)&value.int128.b[8]),
196                                 ntohs(*(uint16_t *)&value.int128.b[10]),
197                                 ntohl(*(uint32_t *)&value.int128.b[12]));
198                 break;
199
200         default:
201                 fprintf(stderr, "Invalid Protocol Descriptor. " \
202                                 "Not a UUID, type=%#x\n", type);
203                 return;
204                 /* NOT REACHED */
205         }
206
207         /* Protocol specific parameters */
208         for (param = 1; start < end; param ++) {
209                 fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
210
211                 SDP_GET8(type, start);
212                 switch (type) {
213                 case SDP_DATA_NIL:
214                         fprintf(stdout, "nil\n");
215                         break;
216
217                 case SDP_DATA_UINT8:
218                 case SDP_DATA_INT8:
219                 case SDP_DATA_BOOL:
220                         SDP_GET8(value.uint8, start);
221                         fprintf(stdout, "u/int8/bool %u\n", value.uint8);
222                         break;
223
224                 case SDP_DATA_UINT16:
225                 case SDP_DATA_INT16:
226                 case SDP_DATA_UUID16:
227                         SDP_GET16(value.uint16, start);
228                         fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
229                         break;
230
231                 case SDP_DATA_UINT32:
232                 case SDP_DATA_INT32:
233                 case SDP_DATA_UUID32:
234                         SDP_GET32(value.uint32, start);
235                         fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
236                         break;
237
238                 case SDP_DATA_UINT64:
239                 case SDP_DATA_INT64:
240                         SDP_GET64(value.uint64, start);
241                         fprintf(stdout, "u/int64 %ju\n", value.uint64);
242                         break;
243
244                 case SDP_DATA_UINT128:
245                 case SDP_DATA_INT128:
246                         SDP_GET128(&value.int128, start);
247                         fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
248                                 *(uint32_t *)&value.int128.b[0],
249                                 *(uint32_t *)&value.int128.b[4],
250                                 *(uint32_t *)&value.int128.b[8],
251                                 *(uint32_t *)&value.int128.b[12]);
252                         break;
253
254                 case SDP_DATA_UUID128:
255                         SDP_GET_UUID128(&value.int128, start);
256                         fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
257                                 ntohl(*(uint32_t *)&value.int128.b[0]),
258                                 ntohs(*(uint16_t *)&value.int128.b[4]),
259                                 ntohs(*(uint16_t *)&value.int128.b[6]),
260                                 ntohs(*(uint16_t *)&value.int128.b[8]),
261                                 ntohs(*(uint16_t *)&value.int128.b[10]),
262                                 ntohl(*(uint32_t *)&value.int128.b[12]));
263                         break;
264
265                 case SDP_DATA_STR8:
266                 case SDP_DATA_URL8:
267                         SDP_GET8(len, start);
268                         for (; start < end && len > 0; start ++, len --)
269                                 fprintf(stdout, "%c", *start);
270                         fprintf(stdout, "\n");
271                         break;
272
273                 case SDP_DATA_STR16:
274                 case SDP_DATA_URL16:
275                         SDP_GET16(len, start);
276                         for (; start < end && len > 0; start ++, len --)
277                                 fprintf(stdout, "%c", *start);
278                         fprintf(stdout, "\n");
279                         break;
280
281                 case SDP_DATA_STR32:
282                 case SDP_DATA_URL32:
283                         SDP_GET32(len, start);
284                         for (; start < end && len > 0; start ++, len --)
285                                 fprintf(stdout, "%c", *start);
286                         fprintf(stdout, "\n");
287                         break;
288
289                 case SDP_DATA_SEQ8:
290                 case SDP_DATA_ALT8:
291                         SDP_GET8(len, start);
292                         for (; start < end && len > 0; start ++, len --)
293                                 fprintf(stdout, "%#2.2x ", *start);
294                         fprintf(stdout, "\n");
295                         break;
296
297                 case SDP_DATA_SEQ16:
298                 case SDP_DATA_ALT16:
299                         SDP_GET16(len, start);
300                         for (; start < end && len > 0; start ++, len --)
301                                 fprintf(stdout, "%#2.2x ", *start);
302                         fprintf(stdout, "\n");
303                         break;
304
305                 case SDP_DATA_SEQ32:
306                 case SDP_DATA_ALT32:
307                         SDP_GET32(len, start);
308                         for (; start < end && len > 0; start ++, len --)
309                                 fprintf(stdout, "%#2.2x ", *start);
310                         fprintf(stdout, "\n");
311                         break;
312
313                 default:
314                         fprintf(stderr, "Invalid Protocol Descriptor. " \
315                                         "Unknown data type: %#02x\n", type);
316                         return;
317                         /* NOT REACHED */
318                 }
319         }
320 } /* print_protocol_descriptor */
321
322 static void
323 print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
324 {
325         uint32_t        type, len;
326
327         if (end - start < 2) {
328                 fprintf(stderr, "Invalid Protocol Descriptor List. " \
329                                 "Too short, len=%zd\n", end - start);
330                 return;
331         }
332
333         SDP_GET8(type, start);
334         switch (type) {
335         case SDP_DATA_SEQ8:
336                 SDP_GET8(len, start);
337                 break;
338
339         case SDP_DATA_SEQ16:
340                 SDP_GET16(len, start);
341                 break;
342
343         case SDP_DATA_SEQ32:
344                 SDP_GET32(len, start);
345                 break;
346
347         default:
348                 fprintf(stderr, "Invalid Protocol Descriptor List. " \
349                                 "Not a sequence, type=%#x\n", type);
350                 return;
351                 /* NOT REACHED */
352         }
353
354         if (len > (end - start)) {
355                 fprintf(stderr, "Invalid Protocol Descriptor List. " \
356                                 "Too long, len=%d\n", len);
357                 return;
358         }
359
360         while (start < end) {
361                 SDP_GET8(type, start);
362                 switch (type) {
363                 case SDP_DATA_SEQ8:
364                         SDP_GET8(len, start);
365                         break;
366
367                 case SDP_DATA_SEQ16:
368                         SDP_GET16(len, start);
369                         break;
370
371                 case SDP_DATA_SEQ32:
372                         SDP_GET32(len, start);
373                         break;
374
375                 default:
376                         fprintf(stderr, "Invalid Protocol Descriptor List. " \
377                                         "Not a sequence, type=%#x\n", type);
378                         return;
379                         /* NOT REACHED */
380                 }
381
382                 if (len > (end - start)) {
383                         fprintf(stderr, "Invalid Protocol Descriptor List. " \
384                                         "Too long, len=%d\n", len);
385                         return;
386                 }
387
388                 print_protocol_descriptor(start, start + len);
389                 start += len;
390         }
391 } /* print_protocol_descriptor_list */
392
393 /*
394  * Print Bluetooth Profile Descriptor List
395  *
396  * The BluetoothProfileDescriptorList attribute consists of a data element 
397  * sequence in which each element is a profile descriptor that contains 
398  * information about a Bluetooth profile to which the service represented by 
399  * this service record conforms. Each profile descriptor is a data element 
400  * sequence whose first element is the UUID assigned to the profile and whose 
401  * second element is a 16-bit profile version number. Each version of a profile
402  * is assigned a 16-bit unsigned integer profile version number, which consists
403  * of two 8-bit fields. The higher-order 8 bits contain the major version 
404  * number field and the lower-order 8 bits contain the minor version number 
405  * field.
406  */
407
408 static void
409 print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
410 {
411         uint32_t        type, len, value;
412
413         if (end - start < 2) {
414                 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
415                                 "Too short, len=%zd\n", end - start);
416                 return;
417         }
418
419         SDP_GET8(type, start);
420         switch (type) {
421         case SDP_DATA_SEQ8:
422                 SDP_GET8(len, start);
423                 break;
424
425         case SDP_DATA_SEQ16:
426                 SDP_GET16(len, start);
427                 break;
428
429         case SDP_DATA_SEQ32:
430                 SDP_GET32(len, start);
431                 break;
432
433         default:
434                 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
435                                 "Not a sequence, type=%#x\n", type);
436                 return;
437                 /* NOT REACHED */
438         }
439
440         if (len > (end - start)) {
441                 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
442                                 "Too long, len=%d\n", len);
443                 return;
444         }
445
446         while (start < end) {
447                 SDP_GET8(type, start);
448                 switch (type) {
449                 case SDP_DATA_SEQ8:
450                         SDP_GET8(len, start);
451                         break;
452
453                 case SDP_DATA_SEQ16:
454                         SDP_GET16(len, start);
455                         break;
456
457                 case SDP_DATA_SEQ32:
458                         SDP_GET32(len, start);
459                         break;
460
461                 default:
462                         fprintf(stderr, "Invalid Bluetooth Profile " \
463                                         "Descriptor List. " \
464                                         "Not a sequence, type=%#x\n", type);
465                         return;
466                         /* NOT REACHED */
467                 }
468
469                 if (len > (end - start)) {
470                         fprintf(stderr, "Invalid Bluetooth Profile " \
471                                         "Descriptor List. " \
472                                         "Too long, len=%d\n", len);
473                         return;
474                 }
475
476                 /* Get UUID */
477                 SDP_GET8(type, start);
478                 switch (type) {
479                 case SDP_DATA_UUID16:
480                         SDP_GET16(value, start);
481                         fprintf(stdout, "\t%s (%#4.4x) ",
482                                         sdp_uuid2desc(value), value);
483                         break;
484
485                 case SDP_DATA_UUID32:
486                         SDP_GET32(value, start);
487                         fprintf(stdout, "\t%#8.8x ", value);
488                         break;
489
490                 case SDP_DATA_UUID128: {
491                         int128_t        uuid;
492
493                         SDP_GET_UUID128(&uuid, start);
494                         fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
495                                         ntohl(*(uint32_t *)&uuid.b[0]),
496                                         ntohs(*(uint16_t *)&uuid.b[4]),
497                                         ntohs(*(uint16_t *)&uuid.b[6]),
498                                         ntohs(*(uint16_t *)&uuid.b[8]),
499                                         ntohs(*(uint16_t *)&uuid.b[10]),
500                                         ntohl(*(uint32_t *)&uuid.b[12]));
501                         } break;
502
503                 default:
504                         fprintf(stderr, "Invalid Bluetooth Profile " \
505                                         "Descriptor List. " \
506                                         "Not a UUID, type=%#x\n", type);
507                         return;
508                         /* NOT REACHED */
509                 }
510
511                 /* Get version */
512                 SDP_GET8(type, start);
513                 if (type != SDP_DATA_UINT16) {
514                         fprintf(stderr, "Invalid Bluetooth Profile " \
515                                         "Descriptor List. " \
516                                         "Invalid version type=%#x\n", type);
517                         return;
518                 }
519
520                 SDP_GET16(value, start);
521                 fprintf(stdout, "ver. %d.%d\n",
522                                 (value >> 8) & 0xff, value & 0xff);
523         }
524 } /* print_bluetooth_profile_descriptor_list */
525
526 /* Perform SDP search command */
527 static int
528 do_sdp_search(void *xs, int argc, char **argv)
529 {
530         char            *ep = NULL;
531         int32_t          n, type, value;
532         uint16_t         service;
533
534         /* Parse command line arguments */
535         switch (argc) {
536         case 1:
537                 n = strtoul(argv[0], &ep, 16);
538                 if (*ep != 0) {
539                         switch (tolower(argv[0][0])) {
540                         case 'c': /* CIP/CTP */
541                                 switch (tolower(argv[0][1])) {
542                                 case 'i':
543                                         service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
544                                         break;
545
546                                 case 't':
547                                         service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
548                                         break;
549
550                                 default:
551                                         return (USAGE);
552                                         /* NOT REACHED */
553                                 }
554                                 break;
555
556                         case 'd': /* DialUp Networking */
557                                 service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
558                                 break;
559
560                         case 'f': /* Fax/OBEX File Transfer */
561                                 switch (tolower(argv[0][1])) {
562                                 case 'a':
563                                         service = SDP_SERVICE_CLASS_FAX;
564                                         break;
565
566                                 case 't':
567                                         service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
568                                         break;
569
570                                 default:
571                                         return (USAGE);
572                                         /* NOT REACHED */
573                                 }
574                                 break;
575
576                         case 'g': /* GN */
577                                 service = SDP_SERVICE_CLASS_GN;
578                                 break;
579
580                         case 'h': /* Headset/HID */
581                                 switch (tolower(argv[0][1])) {
582                                 case 'i':
583                                         service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
584                                         break;
585
586                                 case 's':
587                                         service = SDP_SERVICE_CLASS_HEADSET;
588                                         break;
589
590                                 default:
591                                         return (USAGE);
592                                         /* NOT REACHED */
593                                 }
594                                 break;
595
596                         case 'l': /* LAN Access Using PPP */
597                                 service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
598                                 break;
599
600                         case 'n': /* NAP */
601                                 service = SDP_SERVICE_CLASS_NAP;
602                                 break;
603
604                         case 'o': /* OBEX Object Push */
605                                 service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
606                                 break;
607
608                         case 's': /* Serial Port */
609                                 service = SDP_SERVICE_CLASS_SERIAL_PORT;
610                                 break;
611
612                         default:
613                                 return (USAGE);
614                                 /* NOT REACHED */
615                         }
616                 } else
617                         service = (uint16_t) n;
618                 break;
619
620         default:
621                 return (USAGE);
622         }
623
624         /* Initialize attribute values array */
625         for (n = 0; n < values_len; n ++) {
626                 values[n].flags = SDP_ATTR_INVALID;
627                 values[n].attr = 0;
628                 values[n].vlen = BSIZE;
629                 values[n].value = buffer[n];
630         }
631
632         /* Do SDP Service Search Attribute Request */
633         n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
634         if (n != 0)
635                 return (ERROR);
636
637         /* Print attributes values */
638         for (n = 0; n < values_len; n ++) {
639                 if (values[n].flags != SDP_ATTR_OK)
640                         break;
641
642                 switch (values[n].attr) {
643                 case SDP_ATTR_SERVICE_RECORD_HANDLE:
644                         fprintf(stdout, "\n");
645                         if (values[n].vlen == 5) {
646                                 SDP_GET8(type, values[n].value);
647                                 if (type == SDP_DATA_UINT32) {
648                                         SDP_GET32(value, values[n].value);
649                                         fprintf(stdout, "Record Handle: " \
650                                                         "%#8.8x\n", value);
651                                 } else
652                                         fprintf(stderr, "Invalid type=%#x " \
653                                                         "Record Handle " \
654                                                         "attribute!\n", type);
655                         } else
656                                 fprintf(stderr, "Invalid size=%d for Record " \
657                                                 "Handle attribute\n",
658                                                 values[n].vlen);
659                         break;
660
661                 case SDP_ATTR_SERVICE_CLASS_ID_LIST:
662                         fprintf(stdout, "Service Class ID List:\n");
663                         print_service_class_id_list(values[n].value,
664                                         values[n].value + values[n].vlen);
665                         break;
666
667                 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
668                         fprintf(stdout, "Protocol Descriptor List:\n");
669                         print_protocol_descriptor_list(values[n].value,
670                                         values[n].value + values[n].vlen);
671                         break;
672
673                 case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
674                         fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
675                         print_bluetooth_profile_descriptor_list(values[n].value,
676                                         values[n].value + values[n].vlen);
677                         break;
678
679                 default:
680                         fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
681                                         values[n].attr);
682                         break;
683                 }
684         }
685
686         return (OK);
687 } /* do_sdp_search */
688
689 /* Perform SDP browse command */
690 static int
691 do_sdp_browse(void *xs, int argc, char **argv)
692 {
693 #undef  _STR
694 #undef  STR
695 #define _STR(x) #x
696 #define STR(x)  _STR(x)
697
698         static char const * const       av[] = {
699                 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
700                 NULL
701         }; 
702
703         switch (argc) {
704         case 0:
705                 argc = 1;
706                 argv = (char **) av;
707                 /* FALL THROUGH */
708         case 1:
709                 return (do_sdp_search(xs, argc, argv));
710         }
711
712         return (USAGE);
713 } /* do_sdp_browse */
714
715 /* List of SDP commands */
716 struct sdp_command      sdp_commands[] = {
717 {
718 "Browse [<Group>]",
719 "Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
720 "to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
721 "\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
722 do_sdp_browse
723 },
724 {
725 "Search <Service>",
726 "Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
727 "service to search for. For some services it is possible to use service name\n"\
728 "instead of service UUID\n\n" \
729 "\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
730 "\tKnown service names\n" \
731 "\t===================\n" \
732 "\tCIP   - Common ISDN Access\n" \
733 "\tCTP   - Cordless Telephony\n" \
734 "\tDUN   - DialUp Networking\n" \
735 "\tFAX   - Fax\n" \
736 "\tFTRN  - OBEX File Transfer\n" \
737 "\tGN    - GN\n" \
738 "\tHID   - Human Interface Device\n" \
739 "\tHSET  - Headset\n" \
740 "\tLAN   - LAN Access Using PPP\n" \
741 "\tNAP   - Network Access Point\n" \
742 "\tOPUSH - OBEX Object Push\n" \
743 "\tSP    - Serial Port\n",
744 do_sdp_search
745 },
746 { NULL, NULL, NULL }
747 };
748