inet6: require RTF_ANNOUNCE to proxy NS
[dragonfly.git] / usr.bin / sdpquery / search.c
blobae86d57d2f73471818f70faae219b7ce43cd7acb
1 /* $NetBSD: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $ */
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
32 * search.c
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
39 * are met:
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
56 * SUCH DAMAGE.
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>
64 #include <err.h>
65 #include <errno.h>
66 #include <ctype.h>
67 #include <sdp.h>
68 #include <stdio.h>
69 #include <stdlib.h>
71 #include "sdpquery.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];
92 /* SDP attributes */
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.
106 static void
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);
114 return;
117 SDP_GET8(type, start);
118 switch (type) {
119 case SDP_DATA_SEQ8:
120 SDP_GET8(len, start);
121 break;
123 case SDP_DATA_SEQ16:
124 SDP_GET16(len, start);
125 break;
127 case SDP_DATA_SEQ32:
128 SDP_GET32(len, start);
129 break;
131 default:
132 fprintf(stderr, "Invalid Service Class ID List. " \
133 "Not a sequence, type=%#x\n", type);
134 return;
135 /* NOT REACHED */
138 while (start < end) {
139 SDP_GET8(type, start);
140 switch (type) {
141 case SDP_DATA_UUID16:
142 SDP_GET16(value, start);
143 fprintf(stdout, "\t%s (%#4.4x)\n",
144 sdp_uuid2desc(value), value);
145 break;
147 case SDP_DATA_UUID32:
148 SDP_GET32(value, start);
149 fprintf(stdout, "\t%#8.8x\n", value);
150 break;
152 case SDP_DATA_UUID128: {
153 int128_t uuid;
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]));
163 } break;
165 default:
166 fprintf(stderr, "Invalid Service Class ID List. " \
167 "Not a UUID, type=%#x\n", type);
168 return;
169 /* NOT REACHED */
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.
189 static void
190 print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
192 union {
193 uint8_t uint8;
194 uint16_t uint16;
195 uint32_t uint32;
196 uint64_t uint64;
197 int128_t int128;
198 } value;
199 uint32_t type, len, param;
201 /* Get Protocol UUID */
202 SDP_GET8(type, start);
203 switch (type) {
204 case SDP_DATA_UUID16:
205 SDP_GET16(value.uint16, start);
206 fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
207 value.uint16);
208 break;
210 case SDP_DATA_UUID32:
211 SDP_GET32(value.uint32, start);
212 fprintf(stdout, "\t%#8.8x\n", value.uint32);
213 break;
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]));
224 break;
226 default:
227 fprintf(stderr, "Invalid Protocol Descriptor. " \
228 "Not a UUID, type=%#x\n", type);
229 return;
230 /* NOT REACHED */
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);
238 switch (type) {
239 case SDP_DATA_NIL:
240 fprintf(stdout, "nil\n");
241 break;
243 case SDP_DATA_UINT8:
244 case SDP_DATA_INT8:
245 case SDP_DATA_BOOL:
246 SDP_GET8(value.uint8, start);
247 fprintf(stdout, "u/int8/bool %u\n", value.uint8);
248 break;
250 case SDP_DATA_UINT16:
251 case SDP_DATA_INT16:
252 case SDP_DATA_UUID16:
253 SDP_GET16(value.uint16, start);
254 fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
255 break;
257 case SDP_DATA_UINT32:
258 case SDP_DATA_INT32:
259 case SDP_DATA_UUID32:
260 SDP_GET32(value.uint32, start);
261 fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
262 break;
264 case SDP_DATA_UINT64:
265 case SDP_DATA_INT64:
266 SDP_GET64(value.uint64, start);
267 fprintf(stdout, "u/int64 %ju\n", value.uint64);
268 break;
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]);
278 break;
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]));
289 break;
291 case SDP_DATA_STR8:
292 case SDP_DATA_URL8:
293 SDP_GET8(len, start);
294 fprintf(stdout, "%*.*s\n", len, len, start);
295 start += len;
296 break;
298 case SDP_DATA_STR16:
299 case SDP_DATA_URL16:
300 SDP_GET16(len, start);
301 fprintf(stdout, "%*.*s\n", len, len, start);
302 start += len;
303 break;
305 case SDP_DATA_STR32:
306 case SDP_DATA_URL32:
307 SDP_GET32(len, start);
308 fprintf(stdout, "%*.*s\n", len, len, start);
309 start += len;
310 break;
312 case SDP_DATA_SEQ8:
313 case SDP_DATA_ALT8:
314 SDP_GET8(len, start);
315 for (; len > 0; start ++, len --)
316 fprintf(stdout, "%#2.2x ", *start);
317 fprintf(stdout, "\n");
318 break;
320 case SDP_DATA_SEQ16:
321 case SDP_DATA_ALT16:
322 SDP_GET16(len, start);
323 for (; len > 0; start ++, len --)
324 fprintf(stdout, "%#2.2x ", *start);
325 fprintf(stdout, "\n");
326 break;
328 case SDP_DATA_SEQ32:
329 case SDP_DATA_ALT32:
330 SDP_GET32(len, start);
331 for (; len > 0; start ++, len --)
332 fprintf(stdout, "%#2.2x ", *start);
333 fprintf(stdout, "\n");
334 break;
336 default:
337 fprintf(stderr, "Invalid Protocol Descriptor. " \
338 "Unknown data type: %#02x\n", type);
339 return;
340 /* NOT REACHED */
343 } /* print_protocol_descriptor */
345 static void
346 print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
348 uint32_t type, len;
350 if (end - start < 2) {
351 fprintf(stderr, "Invalid Protocol Descriptor List. " \
352 "Too short, len=%td\n", end - start);
353 return;
356 SDP_GET8(type, start);
357 switch (type) {
358 case SDP_DATA_SEQ8:
359 SDP_GET8(len, start);
360 break;
362 case SDP_DATA_SEQ16:
363 SDP_GET16(len, start);
364 break;
366 case SDP_DATA_SEQ32:
367 SDP_GET32(len, start);
368 break;
370 default:
371 fprintf(stderr, "Invalid Protocol Descriptor List. " \
372 "Not a sequence, type=%#x\n", type);
373 return;
374 /* NOT REACHED */
377 while (start < end) {
378 SDP_GET8(type, start);
379 switch (type) {
380 case SDP_DATA_SEQ8:
381 SDP_GET8(len, start);
382 break;
384 case SDP_DATA_SEQ16:
385 SDP_GET16(len, start);
386 break;
388 case SDP_DATA_SEQ32:
389 SDP_GET32(len, start);
390 break;
392 default:
393 fprintf(stderr, "Invalid Protocol Descriptor List. " \
394 "Not a sequence, type=%#x\n", type);
395 return;
396 /* NOT REACHED */
399 print_protocol_descriptor(start, start + len);
400 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
416 * field.
419 static void
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);
427 return;
430 SDP_GET8(type, start);
431 switch (type) {
432 case SDP_DATA_SEQ8:
433 SDP_GET8(len, start);
434 break;
436 case SDP_DATA_SEQ16:
437 SDP_GET16(len, start);
438 break;
440 case SDP_DATA_SEQ32:
441 SDP_GET32(len, start);
442 break;
444 default:
445 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
446 "Not a sequence, type=%#x\n", type);
447 return;
448 /* NOT REACHED */
451 while (start < end) {
452 SDP_GET8(type, start);
453 switch (type) {
454 case SDP_DATA_SEQ8:
455 SDP_GET8(len, start);
456 break;
458 case SDP_DATA_SEQ16:
459 SDP_GET16(len, start);
460 break;
462 case SDP_DATA_SEQ32:
463 SDP_GET32(len, start);
464 break;
466 default:
467 fprintf(stderr, "Invalid Bluetooth Profile " \
468 "Descriptor List. " \
469 "Not a sequence, type=%#x\n", type);
470 return;
471 /* NOT REACHED */
474 /* Get UUID */
475 SDP_GET8(type, start);
476 switch (type) {
477 case SDP_DATA_UUID16:
478 SDP_GET16(value, start);
479 fprintf(stdout, "\t%s (%#4.4x) ",
480 sdp_uuid2desc(value), value);
481 break;
483 case SDP_DATA_UUID32:
484 SDP_GET32(value, start);
485 fprintf(stdout, "\t%#8.8x ", value);
486 break;
488 case SDP_DATA_UUID128: {
489 int128_t uuid;
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]));
499 } break;
501 default:
502 fprintf(stderr, "Invalid Bluetooth Profile " \
503 "Descriptor List. " \
504 "Not a UUID, type=%#x\n", type);
505 return;
506 /* NOT REACHED */
509 /* Get version */
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);
515 return;
518 SDP_GET16(value, start);
519 fprintf(stdout, "ver. %d.%d\n",
520 (value >> 8) & 0xff, value & 0xff);
522 } /* print_bluetooth_profile_descriptor_list */
524 struct service {
525 const char *name;
526 uint16_t class;
527 const char *description;
528 } services[] = {
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,
536 "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,
544 "Handsfree" },
545 { "HSET", SDP_SERVICE_CLASS_HEADSET,
546 "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,
556 "Serial Port" },
557 { NULL, 0,
558 NULL }
561 /* Perform SDP search command */
563 do_sdp_search(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
565 struct service *s;
566 void *xs;
567 char *ep;
568 uint32_t n;
569 int32_t type, value;
570 uint16_t service;
572 if (argc != 1)
573 goto usage;
575 service = strtoul(*argv, &ep, 16);
576 if (*ep != 0) {
577 for (s = services ; ; s++) {
578 if (s->name == NULL)
579 goto usage;
581 if (strcasecmp(s->name, *argv) == 0)
582 break;
584 service = s->class;
587 /* Initialize attribute values array */
588 for (n = 0; n < values_len; n ++) {
589 values[n].flags = SDP_ATTR_INVALID;
590 values[n].attr = 0;
591 values[n].vlen = BSIZE;
592 values[n].value = buffer[n];
595 if (bdaddr_any(raddr))
596 xs = sdp_open_local(control_socket);
597 else
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);
605 if (n != 0)
606 err(EXIT_FAILURE, "sdp_search");
608 sdp_close(xs);
610 /* Print attributes values */
611 for (n = 0; n < values_len; n ++) {
612 if (values[n].flags != SDP_ATTR_OK)
613 break;
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: " \
623 "%#8.8x\n", value);
624 } else
625 fprintf(stderr, "Invalid type=%#x " \
626 "Record Handle " \
627 "attribute!\n", type);
628 } else
629 fprintf(stderr, "Invalid size=%d for Record " \
630 "Handle attribute\n",
631 values[n].vlen);
632 break;
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);
638 break;
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);
644 break;
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);
650 break;
652 default:
653 fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
654 values[n].attr);
655 break;
659 return EXIT_SUCCESS;
661 usage:
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);
666 return EXIT_FAILURE;
667 } /* do_sdp_search */
669 /* Perform SDP browse command */
671 do_sdp_browse(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
673 #undef _STR
674 #undef STR
675 #define _STR(x) #x
676 #define STR(x) _STR(x)
678 static char const * av[] = {
679 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
680 NULL
683 switch (argc) {
684 case 0:
685 argc = 1;
686 argv = (char const **) av;
687 /* FALL THROUGH */
688 case 1:
689 return (do_sdp_search(laddr, raddr, argc, argv));
692 return EXIT_FAILURE;
693 } /* do_sdp_browse */