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