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 #define L2CAP_SOCKET_CHECKED
34 #include <bluetooth.h>
39 #include "sdpcontrol.h"
41 /* List of the attributes we are looking for */
42 static uint32_t attrs[] =
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)
53 #define attrs_len (sizeof(attrs)/sizeof(attrs[0]))
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];
61 static sdp_attr_t values[NRECS * attrs_len];
62 #define values_len (sizeof(values)/sizeof(values[0]))
65 * Print Service Class ID List
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.
75 print_service_class_id_list(uint8_t const *start, uint8_t const *end)
77 uint32_t type, len, value;
79 if (end - start < 2) {
80 fprintf(stderr, "Invalid Service Class ID List. " \
81 "Too short, len=%zd\n", end - start);
85 SDP_GET8(type, start);
92 SDP_GET16(len, start);
96 SDP_GET32(len, start);
100 fprintf(stderr, "Invalid Service Class ID List. " \
101 "Not a sequence, type=%#x\n", type);
106 if (len > (end - start)) {
107 fprintf(stderr, "Invalid Service Class ID List. " \
108 "Too long len=%d\n", len);
112 while (start < end) {
113 SDP_GET8(type, start);
115 case SDP_DATA_UUID16:
116 SDP_GET16(value, start);
117 fprintf(stdout, "\t%s (%#4.4x)\n",
118 sdp_uuid2desc(value), value);
121 case SDP_DATA_UUID32:
122 SDP_GET32(value, start);
123 fprintf(stdout, "\t%#8.8x\n", value);
126 case SDP_DATA_UUID128: {
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]));
140 fprintf(stderr, "Invalid Service Class ID List. " \
141 "Not a UUID, type=%#x\n", type);
146 } /* print_service_class_id_list */
149 * Print Protocol Descriptor List
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.
164 print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
173 uint32_t type, len, param;
175 /* Get Protocol UUID */
176 SDP_GET8(type, start);
178 case SDP_DATA_UUID16:
179 SDP_GET16(value.uint16, start);
180 fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
184 case SDP_DATA_UUID32:
185 SDP_GET32(value.uint32, start);
186 fprintf(stdout, "\t%#8.8x\n", value.uint32);
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]));
201 fprintf(stderr, "Invalid Protocol Descriptor. " \
202 "Not a UUID, type=%#x\n", type);
207 /* Protocol specific parameters */
208 for (param = 1; start < end; param ++) {
209 fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
211 SDP_GET8(type, start);
214 fprintf(stdout, "nil\n");
220 SDP_GET8(value.uint8, start);
221 fprintf(stdout, "u/int8/bool %u\n", value.uint8);
224 case SDP_DATA_UINT16:
226 case SDP_DATA_UUID16:
227 SDP_GET16(value.uint16, start);
228 fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
231 case SDP_DATA_UINT32:
233 case SDP_DATA_UUID32:
234 SDP_GET32(value.uint32, start);
235 fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
238 case SDP_DATA_UINT64:
240 SDP_GET64(value.uint64, start);
241 fprintf(stdout, "u/int64 %ju\n", value.uint64);
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]);
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]));
267 SDP_GET8(len, start);
268 for (; start < end && len > 0; start ++, len --)
269 fprintf(stdout, "%c", *start);
270 fprintf(stdout, "\n");
275 SDP_GET16(len, start);
276 for (; start < end && len > 0; start ++, len --)
277 fprintf(stdout, "%c", *start);
278 fprintf(stdout, "\n");
283 SDP_GET32(len, start);
284 for (; start < end && len > 0; start ++, len --)
285 fprintf(stdout, "%c", *start);
286 fprintf(stdout, "\n");
291 SDP_GET8(len, start);
292 for (; start < end && len > 0; start ++, len --)
293 fprintf(stdout, "%#2.2x ", *start);
294 fprintf(stdout, "\n");
299 SDP_GET16(len, start);
300 for (; start < end && len > 0; start ++, len --)
301 fprintf(stdout, "%#2.2x ", *start);
302 fprintf(stdout, "\n");
307 SDP_GET32(len, start);
308 for (; start < end && len > 0; start ++, len --)
309 fprintf(stdout, "%#2.2x ", *start);
310 fprintf(stdout, "\n");
314 fprintf(stderr, "Invalid Protocol Descriptor. " \
315 "Unknown data type: %#02x\n", type);
320 } /* print_protocol_descriptor */
323 print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
327 if (end - start < 2) {
328 fprintf(stderr, "Invalid Protocol Descriptor List. " \
329 "Too short, len=%zd\n", end - start);
333 SDP_GET8(type, start);
336 SDP_GET8(len, start);
340 SDP_GET16(len, start);
344 SDP_GET32(len, start);
348 fprintf(stderr, "Invalid Protocol Descriptor List. " \
349 "Not a sequence, type=%#x\n", type);
354 if (len > (end - start)) {
355 fprintf(stderr, "Invalid Protocol Descriptor List. " \
356 "Too long, len=%d\n", len);
360 while (start < end) {
361 SDP_GET8(type, start);
364 SDP_GET8(len, start);
368 SDP_GET16(len, start);
372 SDP_GET32(len, start);
376 fprintf(stderr, "Invalid Protocol Descriptor List. " \
377 "Not a sequence, type=%#x\n", type);
382 if (len > (end - start)) {
383 fprintf(stderr, "Invalid Protocol Descriptor List. " \
384 "Too long, len=%d\n", len);
388 print_protocol_descriptor(start, start + len);
391 } /* print_protocol_descriptor_list */
394 * Print Bluetooth Profile Descriptor List
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
409 print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
411 uint32_t type, len, value;
413 if (end - start < 2) {
414 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
415 "Too short, len=%zd\n", end - start);
419 SDP_GET8(type, start);
422 SDP_GET8(len, start);
426 SDP_GET16(len, start);
430 SDP_GET32(len, start);
434 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
435 "Not a sequence, type=%#x\n", type);
440 if (len > (end - start)) {
441 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
442 "Too long, len=%d\n", len);
446 while (start < end) {
447 SDP_GET8(type, start);
450 SDP_GET8(len, start);
454 SDP_GET16(len, start);
458 SDP_GET32(len, start);
462 fprintf(stderr, "Invalid Bluetooth Profile " \
463 "Descriptor List. " \
464 "Not a sequence, type=%#x\n", type);
469 if (len > (end - start)) {
470 fprintf(stderr, "Invalid Bluetooth Profile " \
471 "Descriptor List. " \
472 "Too long, len=%d\n", len);
477 SDP_GET8(type, start);
479 case SDP_DATA_UUID16:
480 SDP_GET16(value, start);
481 fprintf(stdout, "\t%s (%#4.4x) ",
482 sdp_uuid2desc(value), value);
485 case SDP_DATA_UUID32:
486 SDP_GET32(value, start);
487 fprintf(stdout, "\t%#8.8x ", value);
490 case SDP_DATA_UUID128: {
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]));
504 fprintf(stderr, "Invalid Bluetooth Profile " \
505 "Descriptor List. " \
506 "Not a UUID, type=%#x\n", type);
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);
520 SDP_GET16(value, start);
521 fprintf(stdout, "ver. %d.%d\n",
522 (value >> 8) & 0xff, value & 0xff);
524 } /* print_bluetooth_profile_descriptor_list */
526 /* Perform SDP search command */
528 do_sdp_search(void *xs, int argc, char **argv)
531 int32_t n, type, value;
534 /* Parse command line arguments */
537 n = strtoul(argv[0], &ep, 16);
539 switch (tolower(argv[0][0])) {
540 case 'c': /* CIP/CTP */
541 switch (tolower(argv[0][1])) {
543 service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
547 service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
556 case 'd': /* DialUp Networking */
557 service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
560 case 'f': /* Fax/OBEX File Transfer */
561 switch (tolower(argv[0][1])) {
563 service = SDP_SERVICE_CLASS_FAX;
567 service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
577 service = SDP_SERVICE_CLASS_GN;
580 case 'h': /* Headset/HID */
581 switch (tolower(argv[0][1])) {
583 service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
587 service = SDP_SERVICE_CLASS_HEADSET;
596 case 'l': /* LAN Access Using PPP */
597 service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
601 service = SDP_SERVICE_CLASS_NAP;
604 case 'o': /* OBEX Object Push */
605 service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
608 case 's': /* Serial Port */
609 service = SDP_SERVICE_CLASS_SERIAL_PORT;
617 service = (uint16_t) n;
624 /* Initialize attribute values array */
625 for (n = 0; n < values_len; n ++) {
626 values[n].flags = SDP_ATTR_INVALID;
628 values[n].vlen = BSIZE;
629 values[n].value = buffer[n];
632 /* Do SDP Service Search Attribute Request */
633 n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
637 /* Print attributes values */
638 for (n = 0; n < values_len; n ++) {
639 if (values[n].flags != SDP_ATTR_OK)
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: " \
652 fprintf(stderr, "Invalid type=%#x " \
654 "attribute!\n", type);
656 fprintf(stderr, "Invalid size=%d for Record " \
657 "Handle attribute\n",
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);
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);
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);
680 fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
687 } /* do_sdp_search */
689 /* Perform SDP browse command */
691 do_sdp_browse(void *xs, int argc, char **argv)
696 #define STR(x) _STR(x)
698 static char const * const av[] = {
699 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
709 return (do_sdp_search(xs, argc, argv));
713 } /* do_sdp_browse */
715 /* List of SDP commands */
716 struct sdp_command sdp_commands[] = {
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",
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" \
736 "\tFTRN - OBEX File Transfer\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",