4 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
28 * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
32 #include <netinet/in.h>
33 #include <bluetooth.h>
38 #include "sdpcontrol.h"
40 /* List of the attributes we are looking for */
41 static uint32_t attrs[] =
43 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE,
44 SDP_ATTR_SERVICE_RECORD_HANDLE),
45 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST,
46 SDP_ATTR_SERVICE_CLASS_ID_LIST),
47 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
48 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
49 SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
50 SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
52 #define attrs_len (sizeof(attrs)/sizeof(attrs[0]))
54 /* Buffer for the attributes */
55 #define NRECS 25 /* request this much records from the SDP server */
56 #define BSIZE 256 /* one attribute buffer size */
57 static uint8_t buffer[NRECS * attrs_len][BSIZE];
60 static sdp_attr_t values[NRECS * attrs_len];
61 #define values_len (sizeof(values)/sizeof(values[0]))
64 * Print Service Class ID List
66 * The ServiceClassIDList attribute consists of a data element sequence in
67 * which each data element is a UUID representing the service classes that
68 * a given service record conforms to. The UUIDs are listed in order from
69 * the most specific class to the most general class. The ServiceClassIDList
70 * must contain at least one service class UUID.
74 print_service_class_id_list(uint8_t const *start, uint8_t const *end)
76 uint32_t type, len, value;
78 if (end - start < 2) {
79 fprintf(stderr, "Invalid Service Class ID List. " \
80 "Too short, len=%zd\n", end - start);
84 SDP_GET8(type, start);
91 SDP_GET16(len, start);
95 SDP_GET32(len, start);
99 fprintf(stderr, "Invalid Service Class ID List. " \
100 "Not a sequence, type=%#x\n", type);
105 if (len > (end - start)) {
106 fprintf(stderr, "Invalid Service Class ID List. " \
107 "Too long len=%d\n", len);
111 while (start < end) {
112 SDP_GET8(type, start);
114 case SDP_DATA_UUID16:
115 SDP_GET16(value, start);
116 fprintf(stdout, "\t%s (%#4.4x)\n",
117 sdp_uuid2desc(value), value);
120 case SDP_DATA_UUID32:
121 SDP_GET32(value, start);
122 fprintf(stdout, "\t%#8.8x\n", value);
125 case SDP_DATA_UUID128: {
128 SDP_GET_UUID128(&uuid, start);
129 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
130 ntohl(*(uint32_t *)&uuid.b[0]),
131 ntohs(*(uint16_t *)&uuid.b[4]),
132 ntohs(*(uint16_t *)&uuid.b[6]),
133 ntohs(*(uint16_t *)&uuid.b[8]),
134 ntohs(*(uint16_t *)&uuid.b[10]),
135 ntohl(*(uint32_t *)&uuid.b[12]));
139 fprintf(stderr, "Invalid Service Class ID List. " \
140 "Not a UUID, type=%#x\n", type);
145 } /* print_service_class_id_list */
148 * Print Protocol Descriptor List
150 * If the ProtocolDescriptorList describes a single stack, it takes the form
151 * of a data element sequence in which each element of the sequence is a
152 * protocol descriptor. Each protocol descriptor is, in turn, a data element
153 * sequence whose first element is a UUID identifying the protocol and whose
154 * successive elements are protocol-specific parameters. The protocol
155 * descriptors are listed in order from the lowest layer protocol to the
156 * highest layer protocol used to gain access to the service. If it is possible
157 * for more than one kind of protocol stack to be used to gain access to the
158 * service, the ProtocolDescriptorList takes the form of a data element
159 * alternative where each member is a data element sequence as described above.
163 print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
172 uint32_t type, len, param;
174 /* Get Protocol UUID */
175 SDP_GET8(type, start);
177 case SDP_DATA_UUID16:
178 SDP_GET16(value.uint16, start);
179 fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
183 case SDP_DATA_UUID32:
184 SDP_GET32(value.uint32, start);
185 fprintf(stdout, "\t%#8.8x\n", value.uint32);
188 case SDP_DATA_UUID128:
189 SDP_GET_UUID128(&value.int128, start);
190 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
191 ntohl(*(uint32_t *)&value.int128.b[0]),
192 ntohs(*(uint16_t *)&value.int128.b[4]),
193 ntohs(*(uint16_t *)&value.int128.b[6]),
194 ntohs(*(uint16_t *)&value.int128.b[8]),
195 ntohs(*(uint16_t *)&value.int128.b[10]),
196 ntohl(*(uint32_t *)&value.int128.b[12]));
200 fprintf(stderr, "Invalid Protocol Descriptor. " \
201 "Not a UUID, type=%#x\n", type);
206 /* Protocol specific parameters */
207 for (param = 1; start < end; param ++) {
208 fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
210 SDP_GET8(type, start);
213 fprintf(stdout, "nil\n");
219 SDP_GET8(value.uint8, start);
220 fprintf(stdout, "u/int8/bool %u\n", value.uint8);
223 case SDP_DATA_UINT16:
225 case SDP_DATA_UUID16:
226 SDP_GET16(value.uint16, start);
227 fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
230 case SDP_DATA_UINT32:
232 case SDP_DATA_UUID32:
233 SDP_GET32(value.uint32, start);
234 fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
237 case SDP_DATA_UINT64:
239 SDP_GET64(value.uint64, start);
240 fprintf(stdout, "u/int64 %ju\n", value.uint64);
243 case SDP_DATA_UINT128:
244 case SDP_DATA_INT128:
245 SDP_GET128(&value.int128, start);
246 fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
247 *(uint32_t *)&value.int128.b[0],
248 *(uint32_t *)&value.int128.b[4],
249 *(uint32_t *)&value.int128.b[8],
250 *(uint32_t *)&value.int128.b[12]);
253 case SDP_DATA_UUID128:
254 SDP_GET_UUID128(&value.int128, start);
255 fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
256 ntohl(*(uint32_t *)&value.int128.b[0]),
257 ntohs(*(uint16_t *)&value.int128.b[4]),
258 ntohs(*(uint16_t *)&value.int128.b[6]),
259 ntohs(*(uint16_t *)&value.int128.b[8]),
260 ntohs(*(uint16_t *)&value.int128.b[10]),
261 ntohl(*(uint32_t *)&value.int128.b[12]));
266 SDP_GET8(len, start);
267 for (; start < end && len > 0; start ++, len --)
268 fprintf(stdout, "%c", *start);
269 fprintf(stdout, "\n");
274 SDP_GET16(len, start);
275 for (; start < end && len > 0; start ++, len --)
276 fprintf(stdout, "%c", *start);
277 fprintf(stdout, "\n");
282 SDP_GET32(len, start);
283 for (; start < end && len > 0; start ++, len --)
284 fprintf(stdout, "%c", *start);
285 fprintf(stdout, "\n");
290 SDP_GET8(len, start);
291 for (; start < end && len > 0; start ++, len --)
292 fprintf(stdout, "%#2.2x ", *start);
293 fprintf(stdout, "\n");
298 SDP_GET16(len, start);
299 for (; start < end && len > 0; start ++, len --)
300 fprintf(stdout, "%#2.2x ", *start);
301 fprintf(stdout, "\n");
306 SDP_GET32(len, start);
307 for (; start < end && len > 0; start ++, len --)
308 fprintf(stdout, "%#2.2x ", *start);
309 fprintf(stdout, "\n");
313 fprintf(stderr, "Invalid Protocol Descriptor. " \
314 "Unknown data type: %#02x\n", type);
319 } /* print_protocol_descriptor */
322 print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
326 if (end - start < 2) {
327 fprintf(stderr, "Invalid Protocol Descriptor List. " \
328 "Too short, len=%zd\n", end - start);
332 SDP_GET8(type, start);
335 SDP_GET8(len, start);
339 SDP_GET16(len, start);
343 SDP_GET32(len, start);
347 fprintf(stderr, "Invalid Protocol Descriptor List. " \
348 "Not a sequence, type=%#x\n", type);
353 if (len > (end - start)) {
354 fprintf(stderr, "Invalid Protocol Descriptor List. " \
355 "Too long, len=%d\n", len);
359 while (start < end) {
360 SDP_GET8(type, start);
363 SDP_GET8(len, start);
367 SDP_GET16(len, start);
371 SDP_GET32(len, start);
375 fprintf(stderr, "Invalid Protocol Descriptor List. " \
376 "Not a sequence, type=%#x\n", type);
381 if (len > (end - start)) {
382 fprintf(stderr, "Invalid Protocol Descriptor List. " \
383 "Too long, len=%d\n", len);
387 print_protocol_descriptor(start, start + len);
390 } /* print_protocol_descriptor_list */
393 * Print Bluetooth Profile Descriptor List
395 * The BluetoothProfileDescriptorList attribute consists of a data element
396 * sequence in which each element is a profile descriptor that contains
397 * information about a Bluetooth profile to which the service represented by
398 * this service record conforms. Each profile descriptor is a data element
399 * sequence whose first element is the UUID assigned to the profile and whose
400 * second element is a 16-bit profile version number. Each version of a profile
401 * is assigned a 16-bit unsigned integer profile version number, which consists
402 * of two 8-bit fields. The higher-order 8 bits contain the major version
403 * number field and the lower-order 8 bits contain the minor version number
408 print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
410 uint32_t type, len, value;
412 if (end - start < 2) {
413 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
414 "Too short, len=%zd\n", end - start);
418 SDP_GET8(type, start);
421 SDP_GET8(len, start);
425 SDP_GET16(len, start);
429 SDP_GET32(len, start);
433 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
434 "Not a sequence, type=%#x\n", type);
439 if (len > (end - start)) {
440 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
441 "Too long, len=%d\n", len);
445 while (start < end) {
446 SDP_GET8(type, start);
449 SDP_GET8(len, start);
453 SDP_GET16(len, start);
457 SDP_GET32(len, start);
461 fprintf(stderr, "Invalid Bluetooth Profile " \
462 "Descriptor List. " \
463 "Not a sequence, type=%#x\n", type);
468 if (len > (end - start)) {
469 fprintf(stderr, "Invalid Bluetooth Profile " \
470 "Descriptor List. " \
471 "Too long, len=%d\n", len);
476 SDP_GET8(type, start);
478 case SDP_DATA_UUID16:
479 SDP_GET16(value, start);
480 fprintf(stdout, "\t%s (%#4.4x) ",
481 sdp_uuid2desc(value), value);
484 case SDP_DATA_UUID32:
485 SDP_GET32(value, start);
486 fprintf(stdout, "\t%#8.8x ", value);
489 case SDP_DATA_UUID128: {
492 SDP_GET_UUID128(&uuid, start);
493 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
494 ntohl(*(uint32_t *)&uuid.b[0]),
495 ntohs(*(uint16_t *)&uuid.b[4]),
496 ntohs(*(uint16_t *)&uuid.b[6]),
497 ntohs(*(uint16_t *)&uuid.b[8]),
498 ntohs(*(uint16_t *)&uuid.b[10]),
499 ntohl(*(uint32_t *)&uuid.b[12]));
503 fprintf(stderr, "Invalid Bluetooth Profile " \
504 "Descriptor List. " \
505 "Not a UUID, type=%#x\n", type);
511 SDP_GET8(type, start);
512 if (type != SDP_DATA_UINT16) {
513 fprintf(stderr, "Invalid Bluetooth Profile " \
514 "Descriptor List. " \
515 "Invalid version type=%#x\n", type);
519 SDP_GET16(value, start);
520 fprintf(stdout, "ver. %d.%d\n",
521 (value >> 8) & 0xff, value & 0xff);
523 } /* print_bluetooth_profile_descriptor_list */
525 /* Perform SDP search command */
527 do_sdp_search(void *xs, int argc, char **argv)
530 int32_t n, type, value;
533 /* Parse command line arguments */
536 n = strtoul(argv[0], &ep, 16);
538 switch (tolower(argv[0][0])) {
539 case 'c': /* CIP/CTP */
540 switch (tolower(argv[0][1])) {
542 service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
546 service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
555 case 'd': /* DialUp Networking */
556 service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
559 case 'f': /* Fax/OBEX File Transfer */
560 switch (tolower(argv[0][1])) {
562 service = SDP_SERVICE_CLASS_FAX;
566 service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
576 service = SDP_SERVICE_CLASS_GN;
579 case 'h': /* Headset/HID */
580 switch (tolower(argv[0][1])) {
582 service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
586 service = SDP_SERVICE_CLASS_HEADSET;
595 case 'l': /* LAN Access Using PPP */
596 service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
600 service = SDP_SERVICE_CLASS_NAP;
603 case 'o': /* OBEX Object Push */
604 service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
607 case 's': /* Serial Port */
608 service = SDP_SERVICE_CLASS_SERIAL_PORT;
616 service = (uint16_t) n;
623 /* Initialize attribute values array */
624 for (n = 0; n < values_len; n ++) {
625 values[n].flags = SDP_ATTR_INVALID;
627 values[n].vlen = BSIZE;
628 values[n].value = buffer[n];
631 /* Do SDP Service Search Attribute Request */
632 n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
636 /* Print attributes values */
637 for (n = 0; n < values_len; n ++) {
638 if (values[n].flags != SDP_ATTR_OK)
641 switch (values[n].attr) {
642 case SDP_ATTR_SERVICE_RECORD_HANDLE:
643 fprintf(stdout, "\n");
644 if (values[n].vlen == 5) {
645 SDP_GET8(type, values[n].value);
646 if (type == SDP_DATA_UINT32) {
647 SDP_GET32(value, values[n].value);
648 fprintf(stdout, "Record Handle: " \
651 fprintf(stderr, "Invalid type=%#x " \
653 "attribute!\n", type);
655 fprintf(stderr, "Invalid size=%d for Record " \
656 "Handle attribute\n",
660 case SDP_ATTR_SERVICE_CLASS_ID_LIST:
661 fprintf(stdout, "Service Class ID List:\n");
662 print_service_class_id_list(values[n].value,
663 values[n].value + values[n].vlen);
666 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
667 fprintf(stdout, "Protocol Descriptor List:\n");
668 print_protocol_descriptor_list(values[n].value,
669 values[n].value + values[n].vlen);
672 case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
673 fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
674 print_bluetooth_profile_descriptor_list(values[n].value,
675 values[n].value + values[n].vlen);
679 fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
686 } /* do_sdp_search */
688 /* Perform SDP browse command */
690 do_sdp_browse(void *xs, int argc, char **argv)
695 #define STR(x) _STR(x)
697 static char const * const av[] = {
698 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
708 return (do_sdp_search(xs, argc, argv));
712 } /* do_sdp_browse */
714 /* List of SDP commands */
715 struct sdp_command sdp_commands[] = {
718 "Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
719 "to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
720 "\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
725 "Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
726 "service to search for. For some services it is possible to use service name\n"\
727 "instead of service UUID\n\n" \
728 "\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
729 "\tKnown service names\n" \
730 "\t===================\n" \
731 "\tCIP - Common ISDN Access\n" \
732 "\tCTP - Cordless Telephony\n" \
733 "\tDUN - DialUp Networking\n" \
735 "\tFTRN - OBEX File Transfer\n" \
737 "\tHID - Human Interface Device\n" \
738 "\tHSET - Headset\n" \
739 "\tLAN - LAN Access Using PPP\n" \
740 "\tNAP - Network Access Point\n" \
741 "\tOPUSH - OBEX Object Push\n" \
742 "\tSP - Serial Port\n",