openpam: Sync OpenPAM modules a bit with FreeBSD.
[dragonfly.git] / usr.bin / sdpquery / search.c
blob7b75ade2da9bb079040841e639ea9abecacd5be2
1 /* $NetBSD: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $ */
2 /* $DragonFly: src/usr.bin/sdpquery/search.c,v 1.2 2008/02/11 20:09:42 swildner Exp $ */
4 /*-
5 * Copyright (c) 2006 Itronix Inc.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of Itronix Inc. may not be used to endorse
17 * or promote products derived from this software without specific
18 * prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 * search.c
35 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
59 * $Id: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $
60 * $FreeBSD: src/usr.sbin/bluetooth/sdpcontrol/search.c,v 1.4 2005/05/27 19:11:33 emax Exp $
63 #include <netinet/in.h>
64 #include <bluetooth.h>
65 #include <err.h>
66 #include <errno.h>
67 #include <ctype.h>
68 #include <sdp.h>
69 #include <stdio.h>
70 #include <stdlib.h>
72 #include "sdpquery.h"
74 /* List of the attributes we are looking for */
75 static uint32_t attrs[] =
77 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE,
78 SDP_ATTR_SERVICE_RECORD_HANDLE),
79 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST,
80 SDP_ATTR_SERVICE_CLASS_ID_LIST),
81 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
82 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
83 SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
84 SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
86 #define attrs_len (sizeof(attrs)/sizeof(attrs[0]))
88 /* Buffer for the attributes */
89 #define NRECS 25 /* request this much records from the SDP server */
90 #define BSIZE 256 /* one attribute buffer size */
91 static uint8_t buffer[NRECS * attrs_len][BSIZE];
93 /* SDP attributes */
94 static sdp_attr_t values[NRECS * attrs_len];
95 #define values_len (sizeof(values)/sizeof(values[0]))
98 * Print Service Class ID List
100 * The ServiceClassIDList attribute consists of a data element sequence in
101 * which each data element is a UUID representing the service classes that
102 * a given service record conforms to. The UUIDs are listed in order from
103 * the most specific class to the most general class. The ServiceClassIDList
104 * must contain at least one service class UUID.
107 static void
108 print_service_class_id_list(uint8_t const *start, uint8_t const *end)
110 uint32_t type, len, value;
112 if (end - start < 2) {
113 fprintf(stderr, "Invalid Service Class ID List. " \
114 "Too short, len=%zd\n", end - start);
115 return;
118 SDP_GET8(type, start);
119 switch (type) {
120 case SDP_DATA_SEQ8:
121 SDP_GET8(len, start);
122 break;
124 case SDP_DATA_SEQ16:
125 SDP_GET16(len, start);
126 break;
128 case SDP_DATA_SEQ32:
129 SDP_GET32(len, start);
130 break;
132 default:
133 fprintf(stderr, "Invalid Service Class ID List. " \
134 "Not a sequence, type=%#x\n", type);
135 return;
136 /* NOT REACHED */
139 while (start < end) {
140 SDP_GET8(type, start);
141 switch (type) {
142 case SDP_DATA_UUID16:
143 SDP_GET16(value, start);
144 fprintf(stdout, "\t%s (%#4.4x)\n",
145 sdp_uuid2desc(value), value);
146 break;
148 case SDP_DATA_UUID32:
149 SDP_GET32(value, start);
150 fprintf(stdout, "\t%#8.8x\n", value);
151 break;
153 case SDP_DATA_UUID128: {
154 int128_t uuid;
156 SDP_GET_UUID128(&uuid, start);
157 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
158 ntohl(*(uint32_t *)&uuid.b[0]),
159 ntohs(*(uint16_t *)&uuid.b[4]),
160 ntohs(*(uint16_t *)&uuid.b[6]),
161 ntohs(*(uint16_t *)&uuid.b[8]),
162 ntohs(*(uint16_t *)&uuid.b[10]),
163 ntohl(*(uint32_t *)&uuid.b[12]));
164 } break;
166 default:
167 fprintf(stderr, "Invalid Service Class ID List. " \
168 "Not a UUID, type=%#x\n", type);
169 return;
170 /* NOT REACHED */
173 } /* print_service_class_id_list */
176 * Print Protocol Descriptor List
178 * If the ProtocolDescriptorList describes a single stack, it takes the form
179 * of a data element sequence in which each element of the sequence is a
180 * protocol descriptor. Each protocol descriptor is, in turn, a data element
181 * sequence whose first element is a UUID identifying the protocol and whose
182 * successive elements are protocol-specific parameters. The protocol
183 * descriptors are listed in order from the lowest layer protocol to the
184 * highest layer protocol used to gain access to the service. If it is possible
185 * for more than one kind of protocol stack to be used to gain access to the
186 * service, the ProtocolDescriptorList takes the form of a data element
187 * alternative where each member is a data element sequence as described above.
190 static void
191 print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
193 union {
194 uint8_t uint8;
195 uint16_t uint16;
196 uint32_t uint32;
197 uint64_t uint64;
198 int128_t int128;
199 } value;
200 uint32_t type, len, param;
202 /* Get Protocol UUID */
203 SDP_GET8(type, start);
204 switch (type) {
205 case SDP_DATA_UUID16:
206 SDP_GET16(value.uint16, start);
207 fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
208 value.uint16);
209 break;
211 case SDP_DATA_UUID32:
212 SDP_GET32(value.uint32, start);
213 fprintf(stdout, "\t%#8.8x\n", value.uint32);
214 break;
216 case SDP_DATA_UUID128:
217 SDP_GET_UUID128(&value.int128, start);
218 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
219 ntohl(*(uint32_t *)&value.int128.b[0]),
220 ntohs(*(uint16_t *)&value.int128.b[4]),
221 ntohs(*(uint16_t *)&value.int128.b[6]),
222 ntohs(*(uint16_t *)&value.int128.b[8]),
223 ntohs(*(uint16_t *)&value.int128.b[10]),
224 ntohl(*(uint32_t *)&value.int128.b[12]));
225 break;
227 default:
228 fprintf(stderr, "Invalid Protocol Descriptor. " \
229 "Not a UUID, type=%#x\n", type);
230 return;
231 /* NOT REACHED */
234 /* Protocol specific parameters */
235 for (param = 1; start < end; param ++) {
236 fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
238 SDP_GET8(type, start);
239 switch (type) {
240 case SDP_DATA_NIL:
241 fprintf(stdout, "nil\n");
242 break;
244 case SDP_DATA_UINT8:
245 case SDP_DATA_INT8:
246 case SDP_DATA_BOOL:
247 SDP_GET8(value.uint8, start);
248 fprintf(stdout, "u/int8/bool %u\n", value.uint8);
249 break;
251 case SDP_DATA_UINT16:
252 case SDP_DATA_INT16:
253 case SDP_DATA_UUID16:
254 SDP_GET16(value.uint16, start);
255 fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
256 break;
258 case SDP_DATA_UINT32:
259 case SDP_DATA_INT32:
260 case SDP_DATA_UUID32:
261 SDP_GET32(value.uint32, start);
262 fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
263 break;
265 case SDP_DATA_UINT64:
266 case SDP_DATA_INT64:
267 SDP_GET64(value.uint64, start);
268 fprintf(stdout, "u/int64 %ju\n", value.uint64);
269 break;
271 case SDP_DATA_UINT128:
272 case SDP_DATA_INT128:
273 SDP_GET128(&value.int128, start);
274 fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
275 *(uint32_t *)&value.int128.b[0],
276 *(uint32_t *)&value.int128.b[4],
277 *(uint32_t *)&value.int128.b[8],
278 *(uint32_t *)&value.int128.b[12]);
279 break;
281 case SDP_DATA_UUID128:
282 SDP_GET_UUID128(&value.int128, start);
283 fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
284 ntohl(*(uint32_t *)&value.int128.b[0]),
285 ntohs(*(uint16_t *)&value.int128.b[4]),
286 ntohs(*(uint16_t *)&value.int128.b[6]),
287 ntohs(*(uint16_t *)&value.int128.b[8]),
288 ntohs(*(uint16_t *)&value.int128.b[10]),
289 ntohl(*(uint32_t *)&value.int128.b[12]));
290 break;
292 case SDP_DATA_STR8:
293 case SDP_DATA_URL8:
294 SDP_GET8(len, start);
295 fprintf(stdout, "%*.*s\n", len, len, start);
296 start += len;
297 break;
299 case SDP_DATA_STR16:
300 case SDP_DATA_URL16:
301 SDP_GET16(len, start);
302 fprintf(stdout, "%*.*s\n", len, len, start);
303 start += len;
304 break;
306 case SDP_DATA_STR32:
307 case SDP_DATA_URL32:
308 SDP_GET32(len, start);
309 fprintf(stdout, "%*.*s\n", len, len, start);
310 start += len;
311 break;
313 case SDP_DATA_SEQ8:
314 case SDP_DATA_ALT8:
315 SDP_GET8(len, start);
316 for (; len > 0; start ++, len --)
317 fprintf(stdout, "%#2.2x ", *start);
318 fprintf(stdout, "\n");
319 break;
321 case SDP_DATA_SEQ16:
322 case SDP_DATA_ALT16:
323 SDP_GET16(len, start);
324 for (; len > 0; start ++, len --)
325 fprintf(stdout, "%#2.2x ", *start);
326 fprintf(stdout, "\n");
327 break;
329 case SDP_DATA_SEQ32:
330 case SDP_DATA_ALT32:
331 SDP_GET32(len, start);
332 for (; len > 0; start ++, len --)
333 fprintf(stdout, "%#2.2x ", *start);
334 fprintf(stdout, "\n");
335 break;
337 default:
338 fprintf(stderr, "Invalid Protocol Descriptor. " \
339 "Unknown data type: %#02x\n", type);
340 return;
341 /* NOT REACHED */
344 } /* print_protocol_descriptor */
346 static void
347 print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
349 uint32_t type, len;
351 if (end - start < 2) {
352 fprintf(stderr, "Invalid Protocol Descriptor List. " \
353 "Too short, len=%zd\n", end - start);
354 return;
357 SDP_GET8(type, start);
358 switch (type) {
359 case SDP_DATA_SEQ8:
360 SDP_GET8(len, start);
361 break;
363 case SDP_DATA_SEQ16:
364 SDP_GET16(len, start);
365 break;
367 case SDP_DATA_SEQ32:
368 SDP_GET32(len, start);
369 break;
371 default:
372 fprintf(stderr, "Invalid Protocol Descriptor List. " \
373 "Not a sequence, type=%#x\n", type);
374 return;
375 /* NOT REACHED */
378 while (start < end) {
379 SDP_GET8(type, start);
380 switch (type) {
381 case SDP_DATA_SEQ8:
382 SDP_GET8(len, start);
383 break;
385 case SDP_DATA_SEQ16:
386 SDP_GET16(len, start);
387 break;
389 case SDP_DATA_SEQ32:
390 SDP_GET32(len, start);
391 break;
393 default:
394 fprintf(stderr, "Invalid Protocol Descriptor List. " \
395 "Not a sequence, type=%#x\n", type);
396 return;
397 /* NOT REACHED */
400 print_protocol_descriptor(start, start + len);
401 start += len;
403 } /* print_protocol_descriptor_list */
406 * Print Bluetooth Profile Descriptor List
408 * The BluetoothProfileDescriptorList attribute consists of a data element
409 * sequence in which each element is a profile descriptor that contains
410 * information about a Bluetooth profile to which the service represented by
411 * this service record conforms. Each profile descriptor is a data element
412 * sequence whose first element is the UUID assigned to the profile and whose
413 * second element is a 16-bit profile version number. Each version of a profile
414 * is assigned a 16-bit unsigned integer profile version number, which consists
415 * of two 8-bit fields. The higher-order 8 bits contain the major version
416 * number field and the lower-order 8 bits contain the minor version number
417 * field.
420 static void
421 print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
423 uint32_t type, len, value;
425 if (end - start < 2) {
426 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
427 "Too short, len=%zd\n", end - start);
428 return;
431 SDP_GET8(type, start);
432 switch (type) {
433 case SDP_DATA_SEQ8:
434 SDP_GET8(len, start);
435 break;
437 case SDP_DATA_SEQ16:
438 SDP_GET16(len, start);
439 break;
441 case SDP_DATA_SEQ32:
442 SDP_GET32(len, start);
443 break;
445 default:
446 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
447 "Not a sequence, type=%#x\n", type);
448 return;
449 /* NOT REACHED */
452 while (start < end) {
453 SDP_GET8(type, start);
454 switch (type) {
455 case SDP_DATA_SEQ8:
456 SDP_GET8(len, start);
457 break;
459 case SDP_DATA_SEQ16:
460 SDP_GET16(len, start);
461 break;
463 case SDP_DATA_SEQ32:
464 SDP_GET32(len, start);
465 break;
467 default:
468 fprintf(stderr, "Invalid Bluetooth Profile " \
469 "Descriptor List. " \
470 "Not a sequence, type=%#x\n", type);
471 return;
472 /* NOT REACHED */
475 /* Get UUID */
476 SDP_GET8(type, start);
477 switch (type) {
478 case SDP_DATA_UUID16:
479 SDP_GET16(value, start);
480 fprintf(stdout, "\t%s (%#4.4x) ",
481 sdp_uuid2desc(value), value);
482 break;
484 case SDP_DATA_UUID32:
485 SDP_GET32(value, start);
486 fprintf(stdout, "\t%#8.8x ", value);
487 break;
489 case SDP_DATA_UUID128: {
490 int128_t uuid;
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]));
500 } break;
502 default:
503 fprintf(stderr, "Invalid Bluetooth Profile " \
504 "Descriptor List. " \
505 "Not a UUID, type=%#x\n", type);
506 return;
507 /* NOT REACHED */
510 /* Get version */
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);
516 return;
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 struct service {
526 const char *name;
527 uint16_t class;
528 const char *description;
529 } services[] = {
530 { "CIP", SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS,
531 "Common ISDN Access" },
532 { "CTP", SDP_SERVICE_CLASS_CORDLESS_TELEPHONY,
533 "Cordless Telephony" },
534 { "DUN", SDP_SERVICE_CLASS_DIALUP_NETWORKING,
535 "Dial Up Networking" },
536 { "FAX", SDP_SERVICE_CLASS_FAX,
537 "Fax" },
538 { "FTRN", SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
539 "Obex File Transfer" },
540 { "GN", SDP_SERVICE_CLASS_GN,
541 "Group ad-hoc Network" },
542 { "HID", SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
543 "Human Interface Device" },
544 { "HF", SDP_SERVICE_CLASS_HANDSFREE,
545 "Handsfree" },
546 { "HSET", SDP_SERVICE_CLASS_HEADSET,
547 "Headset" },
548 { "LAN", SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
549 "Lan access using PPP" },
550 { "NAP", SDP_SERVICE_CLASS_NAP,
551 "Network Access Point" },
552 { "OPUSH", SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
553 "OBEX Object Push" },
554 { "PANU", SDP_SERVICE_CLASS_PANU,
555 "Personal Area Networking User" },
556 { "SP", SDP_SERVICE_CLASS_SERIAL_PORT,
557 "Serial Port" },
558 { NULL, 0,
559 NULL }
562 /* Perform SDP search command */
564 do_sdp_search(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
566 struct service *s;
567 void *xs;
568 char *ep;
569 uint32_t n;
570 int32_t type, value;
571 uint16_t service;
573 if (argc != 1)
574 goto usage;
576 service = strtoul(*argv, &ep, 16);
577 if (*ep != 0) {
578 for (s = services ; ; s++) {
579 if (s->name == NULL)
580 goto usage;
582 if (strcasecmp(s->name, *argv) == 0)
583 break;
585 service = s->class;
588 /* Initialize attribute values array */
589 for (n = 0; n < values_len; n ++) {
590 values[n].flags = SDP_ATTR_INVALID;
591 values[n].attr = 0;
592 values[n].vlen = BSIZE;
593 values[n].value = buffer[n];
596 if (bdaddr_any(raddr))
597 xs = sdp_open_local(control_socket);
598 else
599 xs = sdp_open(laddr, raddr);
601 if (xs == NULL || (errno = sdp_error(xs)) != 0)
602 err(EXIT_FAILURE, "sdp_open");
604 /* Do SDP Service Search Attribute Request */
605 n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
606 if (n != 0)
607 err(EXIT_FAILURE, "sdp_search");
609 sdp_close(xs);
611 /* Print attributes values */
612 for (n = 0; n < values_len; n ++) {
613 if (values[n].flags != SDP_ATTR_OK)
614 break;
616 switch (values[n].attr) {
617 case SDP_ATTR_SERVICE_RECORD_HANDLE:
618 fprintf(stdout, "\n");
619 if (values[n].vlen == 5) {
620 SDP_GET8(type, values[n].value);
621 if (type == SDP_DATA_UINT32) {
622 SDP_GET32(value, values[n].value);
623 fprintf(stdout, "Record Handle: " \
624 "%#8.8x\n", value);
625 } else
626 fprintf(stderr, "Invalid type=%#x " \
627 "Record Handle " \
628 "attribute!\n", type);
629 } else
630 fprintf(stderr, "Invalid size=%d for Record " \
631 "Handle attribute\n",
632 values[n].vlen);
633 break;
635 case SDP_ATTR_SERVICE_CLASS_ID_LIST:
636 fprintf(stdout, "Service Class ID List:\n");
637 print_service_class_id_list(values[n].value,
638 values[n].value + values[n].vlen);
639 break;
641 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
642 fprintf(stdout, "Protocol Descriptor List:\n");
643 print_protocol_descriptor_list(values[n].value,
644 values[n].value + values[n].vlen);
645 break;
647 case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
648 fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
649 print_bluetooth_profile_descriptor_list(values[n].value,
650 values[n].value + values[n].vlen);
651 break;
653 default:
654 fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
655 values[n].attr);
656 break;
660 return EXIT_SUCCESS;
662 usage:
663 fprintf(stderr, "Known services:\n");
664 for (s = services ; s->name != NULL ; s++)
665 fprintf(stderr, "\t%s\t%s\n", s->name, s->description);
667 return EXIT_FAILURE;
668 } /* do_sdp_search */
670 /* Perform SDP browse command */
672 do_sdp_browse(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
674 #undef _STR
675 #undef STR
676 #define _STR(x) #x
677 #define STR(x) _STR(x)
679 static char const * av[] = {
680 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
681 NULL
684 switch (argc) {
685 case 0:
686 argc = 1;
687 argv = (char const **) av;
688 /* FALL THROUGH */
689 case 1:
690 return (do_sdp_search(laddr, raddr, argc, argv));
693 return EXIT_FAILURE;
694 } /* do_sdp_browse */