1 /* $NetBSD: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $ */
4 * Copyright (c) 2006 Itronix Inc.
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.
15 * 3. The name of Itronix Inc. may not be used to endorse
16 * or promote products derived from this software without specific
17 * prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
35 * All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * $Id: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $
59 * $FreeBSD: src/usr.sbin/bluetooth/sdpcontrol/search.c,v 1.4 2005/05/27 19:11:33 emax Exp $
62 #include <netinet/in.h>
63 #include <bluetooth.h>
73 /* List of the attributes we are looking for */
74 static uint32_t attrs
[] =
76 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE
,
77 SDP_ATTR_SERVICE_RECORD_HANDLE
),
78 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST
,
79 SDP_ATTR_SERVICE_CLASS_ID_LIST
),
80 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST
,
81 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST
),
82 SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST
,
83 SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST
)
85 #define attrs_len (sizeof(attrs)/sizeof(attrs[0]))
87 /* Buffer for the attributes */
88 #define NRECS 25 /* request this much records from the SDP server */
89 #define BSIZE 256 /* one attribute buffer size */
90 static uint8_t buffer
[NRECS
* attrs_len
][BSIZE
];
93 static sdp_attr_t values
[NRECS
* attrs_len
];
94 #define values_len (sizeof(values)/sizeof(values[0]))
97 * Print Service Class ID List
99 * The ServiceClassIDList attribute consists of a data element sequence in
100 * which each data element is a UUID representing the service classes that
101 * a given service record conforms to. The UUIDs are listed in order from
102 * the most specific class to the most general class. The ServiceClassIDList
103 * must contain at least one service class UUID.
107 print_service_class_id_list(uint8_t const *start
, uint8_t const *end
)
109 uint32_t type
, len
, value
;
111 if (end
- start
< 2) {
112 fprintf(stderr
, "Invalid Service Class ID List. " \
113 "Too short, len=%td\n", end
- start
);
117 SDP_GET8(type
, start
);
120 SDP_GET8(len
, start
);
124 SDP_GET16(len
, start
);
128 SDP_GET32(len
, start
);
132 fprintf(stderr
, "Invalid Service Class ID List. " \
133 "Not a sequence, type=%#x\n", type
);
138 while (start
< end
) {
139 SDP_GET8(type
, start
);
141 case SDP_DATA_UUID16
:
142 SDP_GET16(value
, start
);
143 fprintf(stdout
, "\t%s (%#4.4x)\n",
144 sdp_uuid2desc(value
), value
);
147 case SDP_DATA_UUID32
:
148 SDP_GET32(value
, start
);
149 fprintf(stdout
, "\t%#8.8x\n", value
);
152 case SDP_DATA_UUID128
: {
155 SDP_GET_UUID128(&uuid
, start
);
156 fprintf(stdout
, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
157 ntohl(*(uint32_t *)&uuid
.b
[0]),
158 ntohs(*(uint16_t *)&uuid
.b
[4]),
159 ntohs(*(uint16_t *)&uuid
.b
[6]),
160 ntohs(*(uint16_t *)&uuid
.b
[8]),
161 ntohs(*(uint16_t *)&uuid
.b
[10]),
162 ntohl(*(uint32_t *)&uuid
.b
[12]));
166 fprintf(stderr
, "Invalid Service Class ID List. " \
167 "Not a UUID, type=%#x\n", type
);
172 } /* print_service_class_id_list */
175 * Print Protocol Descriptor List
177 * If the ProtocolDescriptorList describes a single stack, it takes the form
178 * of a data element sequence in which each element of the sequence is a
179 * protocol descriptor. Each protocol descriptor is, in turn, a data element
180 * sequence whose first element is a UUID identifying the protocol and whose
181 * successive elements are protocol-specific parameters. The protocol
182 * descriptors are listed in order from the lowest layer protocol to the
183 * highest layer protocol used to gain access to the service. If it is possible
184 * for more than one kind of protocol stack to be used to gain access to the
185 * service, the ProtocolDescriptorList takes the form of a data element
186 * alternative where each member is a data element sequence as described above.
190 print_protocol_descriptor(uint8_t const *start
, uint8_t const *end
)
199 uint32_t type
, len
, param
;
201 /* Get Protocol UUID */
202 SDP_GET8(type
, start
);
204 case SDP_DATA_UUID16
:
205 SDP_GET16(value
.uint16
, start
);
206 fprintf(stdout
, "\t%s (%#4.4x)\n", sdp_uuid2desc(value
.uint16
),
210 case SDP_DATA_UUID32
:
211 SDP_GET32(value
.uint32
, start
);
212 fprintf(stdout
, "\t%#8.8x\n", value
.uint32
);
215 case SDP_DATA_UUID128
:
216 SDP_GET_UUID128(&value
.int128
, start
);
217 fprintf(stdout
, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
218 ntohl(*(uint32_t *)&value
.int128
.b
[0]),
219 ntohs(*(uint16_t *)&value
.int128
.b
[4]),
220 ntohs(*(uint16_t *)&value
.int128
.b
[6]),
221 ntohs(*(uint16_t *)&value
.int128
.b
[8]),
222 ntohs(*(uint16_t *)&value
.int128
.b
[10]),
223 ntohl(*(uint32_t *)&value
.int128
.b
[12]));
227 fprintf(stderr
, "Invalid Protocol Descriptor. " \
228 "Not a UUID, type=%#x\n", type
);
233 /* Protocol specific parameters */
234 for (param
= 1; start
< end
; param
++) {
235 fprintf(stdout
, "\t\tProtocol specific parameter #%d: ", param
);
237 SDP_GET8(type
, start
);
240 fprintf(stdout
, "nil\n");
246 SDP_GET8(value
.uint8
, start
);
247 fprintf(stdout
, "u/int8/bool %u\n", value
.uint8
);
250 case SDP_DATA_UINT16
:
252 case SDP_DATA_UUID16
:
253 SDP_GET16(value
.uint16
, start
);
254 fprintf(stdout
, "u/int/uuid16 %u\n", value
.uint16
);
257 case SDP_DATA_UINT32
:
259 case SDP_DATA_UUID32
:
260 SDP_GET32(value
.uint32
, start
);
261 fprintf(stdout
, "u/int/uuid32 %u\n", value
.uint32
);
264 case SDP_DATA_UINT64
:
266 SDP_GET64(value
.uint64
, start
);
267 fprintf(stdout
, "u/int64 %ju\n", value
.uint64
);
270 case SDP_DATA_UINT128
:
271 case SDP_DATA_INT128
:
272 SDP_GET128(&value
.int128
, start
);
273 fprintf(stdout
, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
274 *(uint32_t *)&value
.int128
.b
[0],
275 *(uint32_t *)&value
.int128
.b
[4],
276 *(uint32_t *)&value
.int128
.b
[8],
277 *(uint32_t *)&value
.int128
.b
[12]);
280 case SDP_DATA_UUID128
:
281 SDP_GET_UUID128(&value
.int128
, start
);
282 fprintf(stdout
, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
283 ntohl(*(uint32_t *)&value
.int128
.b
[0]),
284 ntohs(*(uint16_t *)&value
.int128
.b
[4]),
285 ntohs(*(uint16_t *)&value
.int128
.b
[6]),
286 ntohs(*(uint16_t *)&value
.int128
.b
[8]),
287 ntohs(*(uint16_t *)&value
.int128
.b
[10]),
288 ntohl(*(uint32_t *)&value
.int128
.b
[12]));
293 SDP_GET8(len
, start
);
294 fprintf(stdout
, "%*.*s\n", len
, len
, start
);
300 SDP_GET16(len
, start
);
301 fprintf(stdout
, "%*.*s\n", len
, len
, start
);
307 SDP_GET32(len
, start
);
308 fprintf(stdout
, "%*.*s\n", len
, len
, start
);
314 SDP_GET8(len
, start
);
315 for (; len
> 0; start
++, len
--)
316 fprintf(stdout
, "%#2.2x ", *start
);
317 fprintf(stdout
, "\n");
322 SDP_GET16(len
, start
);
323 for (; len
> 0; start
++, len
--)
324 fprintf(stdout
, "%#2.2x ", *start
);
325 fprintf(stdout
, "\n");
330 SDP_GET32(len
, start
);
331 for (; len
> 0; start
++, len
--)
332 fprintf(stdout
, "%#2.2x ", *start
);
333 fprintf(stdout
, "\n");
337 fprintf(stderr
, "Invalid Protocol Descriptor. " \
338 "Unknown data type: %#02x\n", type
);
343 } /* print_protocol_descriptor */
346 print_protocol_descriptor_list(uint8_t const *start
, uint8_t const *end
)
350 if (end
- start
< 2) {
351 fprintf(stderr
, "Invalid Protocol Descriptor List. " \
352 "Too short, len=%td\n", end
- start
);
356 SDP_GET8(type
, start
);
359 SDP_GET8(len
, start
);
363 SDP_GET16(len
, start
);
367 SDP_GET32(len
, start
);
371 fprintf(stderr
, "Invalid Protocol Descriptor List. " \
372 "Not a sequence, type=%#x\n", type
);
377 while (start
< end
) {
378 SDP_GET8(type
, start
);
381 SDP_GET8(len
, start
);
385 SDP_GET16(len
, start
);
389 SDP_GET32(len
, start
);
393 fprintf(stderr
, "Invalid Protocol Descriptor List. " \
394 "Not a sequence, type=%#x\n", type
);
399 print_protocol_descriptor(start
, start
+ len
);
402 } /* print_protocol_descriptor_list */
405 * Print Bluetooth Profile Descriptor List
407 * The BluetoothProfileDescriptorList attribute consists of a data element
408 * sequence in which each element is a profile descriptor that contains
409 * information about a Bluetooth profile to which the service represented by
410 * this service record conforms. Each profile descriptor is a data element
411 * sequence whose first element is the UUID assigned to the profile and whose
412 * second element is a 16-bit profile version number. Each version of a profile
413 * is assigned a 16-bit unsigned integer profile version number, which consists
414 * of two 8-bit fields. The higher-order 8 bits contain the major version
415 * number field and the lower-order 8 bits contain the minor version number
420 print_bluetooth_profile_descriptor_list(uint8_t const *start
, uint8_t const *end
)
422 uint32_t type
, len
, value
;
424 if (end
- start
< 2) {
425 fprintf(stderr
, "Invalid Bluetooth Profile Descriptor List. " \
426 "Too short, len=%td\n", end
- start
);
430 SDP_GET8(type
, start
);
433 SDP_GET8(len
, start
);
437 SDP_GET16(len
, start
);
441 SDP_GET32(len
, start
);
445 fprintf(stderr
, "Invalid Bluetooth Profile Descriptor List. " \
446 "Not a sequence, type=%#x\n", type
);
451 while (start
< end
) {
452 SDP_GET8(type
, start
);
455 SDP_GET8(len
, start
);
459 SDP_GET16(len
, start
);
463 SDP_GET32(len
, start
);
467 fprintf(stderr
, "Invalid Bluetooth Profile " \
468 "Descriptor List. " \
469 "Not a sequence, type=%#x\n", type
);
475 SDP_GET8(type
, start
);
477 case SDP_DATA_UUID16
:
478 SDP_GET16(value
, start
);
479 fprintf(stdout
, "\t%s (%#4.4x) ",
480 sdp_uuid2desc(value
), value
);
483 case SDP_DATA_UUID32
:
484 SDP_GET32(value
, start
);
485 fprintf(stdout
, "\t%#8.8x ", value
);
488 case SDP_DATA_UUID128
: {
491 SDP_GET_UUID128(&uuid
, start
);
492 fprintf(stdout
, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
493 ntohl(*(uint32_t *)&uuid
.b
[0]),
494 ntohs(*(uint16_t *)&uuid
.b
[4]),
495 ntohs(*(uint16_t *)&uuid
.b
[6]),
496 ntohs(*(uint16_t *)&uuid
.b
[8]),
497 ntohs(*(uint16_t *)&uuid
.b
[10]),
498 ntohl(*(uint32_t *)&uuid
.b
[12]));
502 fprintf(stderr
, "Invalid Bluetooth Profile " \
503 "Descriptor List. " \
504 "Not a UUID, type=%#x\n", type
);
510 SDP_GET8(type
, start
);
511 if (type
!= SDP_DATA_UINT16
) {
512 fprintf(stderr
, "Invalid Bluetooth Profile " \
513 "Descriptor List. " \
514 "Invalid version type=%#x\n", type
);
518 SDP_GET16(value
, start
);
519 fprintf(stdout
, "ver. %d.%d\n",
520 (value
>> 8) & 0xff, value
& 0xff);
522 } /* print_bluetooth_profile_descriptor_list */
527 const char *description
;
529 { "CIP", SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS
,
530 "Common ISDN Access" },
531 { "CTP", SDP_SERVICE_CLASS_CORDLESS_TELEPHONY
,
532 "Cordless Telephony" },
533 { "DUN", SDP_SERVICE_CLASS_DIALUP_NETWORKING
,
534 "Dial Up Networking" },
535 { "FAX", SDP_SERVICE_CLASS_FAX
,
537 { "FTRN", SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER
,
538 "Obex File Transfer" },
539 { "GN", SDP_SERVICE_CLASS_GN
,
540 "Group ad-hoc Network" },
541 { "HID", SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE
,
542 "Human Interface Device" },
543 { "HF", SDP_SERVICE_CLASS_HANDSFREE
,
545 { "HSET", SDP_SERVICE_CLASS_HEADSET
,
547 { "LAN", SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP
,
548 "Lan access using PPP" },
549 { "NAP", SDP_SERVICE_CLASS_NAP
,
550 "Network Access Point" },
551 { "OPUSH", SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH
,
552 "OBEX Object Push" },
553 { "PANU", SDP_SERVICE_CLASS_PANU
,
554 "Personal Area Networking User" },
555 { "SP", SDP_SERVICE_CLASS_SERIAL_PORT
,
561 /* Perform SDP search command */
563 do_sdp_search(bdaddr_t
*laddr
, bdaddr_t
*raddr
, int argc
, char const **argv
)
575 service
= strtoul(*argv
, &ep
, 16);
577 for (s
= services
; ; s
++) {
581 if (strcasecmp(s
->name
, *argv
) == 0)
587 /* Initialize attribute values array */
588 for (n
= 0; n
< values_len
; n
++) {
589 values
[n
].flags
= SDP_ATTR_INVALID
;
591 values
[n
].vlen
= BSIZE
;
592 values
[n
].value
= buffer
[n
];
595 if (bdaddr_any(raddr
))
596 xs
= sdp_open_local(control_socket
);
598 xs
= sdp_open(laddr
, raddr
);
600 if (xs
== NULL
|| (errno
= sdp_error(xs
)) != 0)
601 err(EXIT_FAILURE
, "sdp_open");
603 /* Do SDP Service Search Attribute Request */
604 n
= sdp_search(xs
, 1, &service
, attrs_len
, attrs
, values_len
, values
);
606 err(EXIT_FAILURE
, "sdp_search");
610 /* Print attributes values */
611 for (n
= 0; n
< values_len
; n
++) {
612 if (values
[n
].flags
!= SDP_ATTR_OK
)
615 switch (values
[n
].attr
) {
616 case SDP_ATTR_SERVICE_RECORD_HANDLE
:
617 fprintf(stdout
, "\n");
618 if (values
[n
].vlen
== 5) {
619 SDP_GET8(type
, values
[n
].value
);
620 if (type
== SDP_DATA_UINT32
) {
621 SDP_GET32(value
, values
[n
].value
);
622 fprintf(stdout
, "Record Handle: " \
625 fprintf(stderr
, "Invalid type=%#x " \
627 "attribute!\n", type
);
629 fprintf(stderr
, "Invalid size=%d for Record " \
630 "Handle attribute\n",
634 case SDP_ATTR_SERVICE_CLASS_ID_LIST
:
635 fprintf(stdout
, "Service Class ID List:\n");
636 print_service_class_id_list(values
[n
].value
,
637 values
[n
].value
+ values
[n
].vlen
);
640 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST
:
641 fprintf(stdout
, "Protocol Descriptor List:\n");
642 print_protocol_descriptor_list(values
[n
].value
,
643 values
[n
].value
+ values
[n
].vlen
);
646 case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST
:
647 fprintf(stdout
, "Bluetooth Profile Descriptor List:\n");
648 print_bluetooth_profile_descriptor_list(values
[n
].value
,
649 values
[n
].value
+ values
[n
].vlen
);
653 fprintf(stderr
, "Unexpected attribute ID=%#4.4x\n",
662 fprintf(stderr
, "Known services:\n");
663 for (s
= services
; s
->name
!= NULL
; s
++)
664 fprintf(stderr
, "\t%s\t%s\n", s
->name
, s
->description
);
667 } /* do_sdp_search */
669 /* Perform SDP browse command */
671 do_sdp_browse(bdaddr_t
*laddr
, bdaddr_t
*raddr
, int argc
, char const **argv
)
676 #define STR(x) _STR(x)
678 static char const * av
[] = {
679 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP
),
686 argv
= (char const **) av
;
689 return (do_sdp_search(laddr
, raddr
, argc
, argv
));
693 } /* do_sdp_browse */