1 /*-
2 * search.c
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
31 */
32
33 #include <sys/param.h>
34 #include <netinet/in.h>
35 #define L2CAP_SOCKET_CHECKED
36 #include <bluetooth.h>
37 #include <ctype.h>
38 #include <sdp.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include "sdpcontrol.h"
42
43 /* List of the attributes we are looking for */
44 static uint32_t attrs[] =
45 {
46 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE,
47 SDP_ATTR_SERVICE_RECORD_HANDLE),
48 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST,
49 SDP_ATTR_SERVICE_CLASS_ID_LIST),
50 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
51 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
52 SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
53 SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
54 };
55 #define attrs_len nitems(attrs)
56
57 /* Buffer for the attributes */
58 #define NRECS 25 /* request this much records from the SDP server */
59 #define BSIZE 256 /* one attribute buffer size */
60 static uint8_t buffer[NRECS * attrs_len][BSIZE];
61
62 /* SDP attributes */
63 static sdp_attr_t values[NRECS * attrs_len];
64 #define values_len nitems(values)
65
66 /*
67 * Print Service Class ID List
68 *
69 * The ServiceClassIDList attribute consists of a data element sequence in
70 * which each data element is a UUID representing the service classes that
71 * a given service record conforms to. The UUIDs are listed in order from
72 * the most specific class to the most general class. The ServiceClassIDList
73 * must contain at least one service class UUID.
74 */
75
76 static void
print_service_class_id_list(uint8_t const * start,uint8_t const * end)77 print_service_class_id_list(uint8_t const *start, uint8_t const *end)
78 {
79 uint32_t type, len, value;
80
81 if (end - start < 2) {
82 fprintf(stderr, "Invalid Service Class ID List. " \
83 "Too short, len=%zd\n", end - start);
84 return;
85 }
86
87 SDP_GET8(type, start);
88 switch (type) {
89 case SDP_DATA_SEQ8:
90 SDP_GET8(len, start);
91 break;
92
93 case SDP_DATA_SEQ16:
94 SDP_GET16(len, start);
95 break;
96
97 case SDP_DATA_SEQ32:
98 SDP_GET32(len, start);
99 break;
100
101 default:
102 fprintf(stderr, "Invalid Service Class ID List. " \
103 "Not a sequence, type=%#x\n", type);
104 return;
105 /* NOT REACHED */
106 }
107
108 if (len > (end - start)) {
109 fprintf(stderr, "Invalid Service Class ID List. " \
110 "Too long len=%d\n", len);
111 return;
112 }
113
114 while (start < end) {
115 SDP_GET8(type, start);
116 switch (type) {
117 case SDP_DATA_UUID16:
118 SDP_GET16(value, start);
119 fprintf(stdout, "\t%s (%#4.4x)\n",
120 sdp_uuid2desc(value), value);
121 break;
122
123 case SDP_DATA_UUID32:
124 SDP_GET32(value, start);
125 fprintf(stdout, "\t%#8.8x\n", value);
126 break;
127
128 case SDP_DATA_UUID128: {
129 int128_t uuid;
130
131 SDP_GET_UUID128(&uuid, start);
132 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
133 ntohl(*(uint32_t *)&uuid.b[0]),
134 ntohs(*(uint16_t *)&uuid.b[4]),
135 ntohs(*(uint16_t *)&uuid.b[6]),
136 ntohs(*(uint16_t *)&uuid.b[8]),
137 ntohs(*(uint16_t *)&uuid.b[10]),
138 ntohl(*(uint32_t *)&uuid.b[12]));
139 } break;
140
141 default:
142 fprintf(stderr, "Invalid Service Class ID List. " \
143 "Not a UUID, type=%#x\n", type);
144 return;
145 /* NOT REACHED */
146 }
147 }
148 } /* print_service_class_id_list */
149
150 /*
151 * Print Protocol Descriptor List
152 *
153 * If the ProtocolDescriptorList describes a single stack, it takes the form
154 * of a data element sequence in which each element of the sequence is a
155 * protocol descriptor. Each protocol descriptor is, in turn, a data element
156 * sequence whose first element is a UUID identifying the protocol and whose
157 * successive elements are protocol-specific parameters. The protocol
158 * descriptors are listed in order from the lowest layer protocol to the
159 * highest layer protocol used to gain access to the service. If it is possible
160 * for more than one kind of protocol stack to be used to gain access to the
161 * service, the ProtocolDescriptorList takes the form of a data element
162 * alternative where each member is a data element sequence as described above.
163 */
164
165 static void
print_protocol_descriptor(uint8_t const * start,uint8_t const * end)166 print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
167 {
168 union {
169 uint8_t uint8;
170 uint16_t uint16;
171 uint32_t uint32;
172 uint64_t uint64;
173 int128_t int128;
174 } value;
175 uint32_t type, len, param;
176
177 /* Get Protocol UUID */
178 SDP_GET8(type, start);
179 switch (type) {
180 case SDP_DATA_UUID16:
181 SDP_GET16(value.uint16, start);
182 fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
183 value.uint16);
184 break;
185
186 case SDP_DATA_UUID32:
187 SDP_GET32(value.uint32, start);
188 fprintf(stdout, "\t%#8.8x\n", value.uint32);
189 break;
190
191 case SDP_DATA_UUID128:
192 SDP_GET_UUID128(&value.int128, start);
193 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
194 ntohl(*(uint32_t *)&value.int128.b[0]),
195 ntohs(*(uint16_t *)&value.int128.b[4]),
196 ntohs(*(uint16_t *)&value.int128.b[6]),
197 ntohs(*(uint16_t *)&value.int128.b[8]),
198 ntohs(*(uint16_t *)&value.int128.b[10]),
199 ntohl(*(uint32_t *)&value.int128.b[12]));
200 break;
201
202 default:
203 fprintf(stderr, "Invalid Protocol Descriptor. " \
204 "Not a UUID, type=%#x\n", type);
205 return;
206 /* NOT REACHED */
207 }
208
209 /* Protocol specific parameters */
210 for (param = 1; start < end; param ++) {
211 fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
212
213 SDP_GET8(type, start);
214 switch (type) {
215 case SDP_DATA_NIL:
216 fprintf(stdout, "nil\n");
217 break;
218
219 case SDP_DATA_UINT8:
220 case SDP_DATA_INT8:
221 case SDP_DATA_BOOL:
222 SDP_GET8(value.uint8, start);
223 fprintf(stdout, "u/int8/bool %u\n", value.uint8);
224 break;
225
226 case SDP_DATA_UINT16:
227 case SDP_DATA_INT16:
228 case SDP_DATA_UUID16:
229 SDP_GET16(value.uint16, start);
230 fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
231 break;
232
233 case SDP_DATA_UINT32:
234 case SDP_DATA_INT32:
235 case SDP_DATA_UUID32:
236 SDP_GET32(value.uint32, start);
237 fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
238 break;
239
240 case SDP_DATA_UINT64:
241 case SDP_DATA_INT64:
242 SDP_GET64(value.uint64, start);
243 fprintf(stdout, "u/int64 %ju\n", value.uint64);
244 break;
245
246 case SDP_DATA_UINT128:
247 case SDP_DATA_INT128:
248 SDP_GET128(&value.int128, start);
249 fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
250 *(uint32_t *)&value.int128.b[0],
251 *(uint32_t *)&value.int128.b[4],
252 *(uint32_t *)&value.int128.b[8],
253 *(uint32_t *)&value.int128.b[12]);
254 break;
255
256 case SDP_DATA_UUID128:
257 SDP_GET_UUID128(&value.int128, start);
258 fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
259 ntohl(*(uint32_t *)&value.int128.b[0]),
260 ntohs(*(uint16_t *)&value.int128.b[4]),
261 ntohs(*(uint16_t *)&value.int128.b[6]),
262 ntohs(*(uint16_t *)&value.int128.b[8]),
263 ntohs(*(uint16_t *)&value.int128.b[10]),
264 ntohl(*(uint32_t *)&value.int128.b[12]));
265 break;
266
267 case SDP_DATA_STR8:
268 case SDP_DATA_URL8:
269 SDP_GET8(len, start);
270 for (; start < end && len > 0; start ++, len --)
271 fprintf(stdout, "%c", *start);
272 fprintf(stdout, "\n");
273 break;
274
275 case SDP_DATA_STR16:
276 case SDP_DATA_URL16:
277 SDP_GET16(len, start);
278 for (; start < end && len > 0; start ++, len --)
279 fprintf(stdout, "%c", *start);
280 fprintf(stdout, "\n");
281 break;
282
283 case SDP_DATA_STR32:
284 case SDP_DATA_URL32:
285 SDP_GET32(len, start);
286 for (; start < end && len > 0; start ++, len --)
287 fprintf(stdout, "%c", *start);
288 fprintf(stdout, "\n");
289 break;
290
291 case SDP_DATA_SEQ8:
292 case SDP_DATA_ALT8:
293 SDP_GET8(len, start);
294 for (; start < end && len > 0; start ++, len --)
295 fprintf(stdout, "%#2.2x ", *start);
296 fprintf(stdout, "\n");
297 break;
298
299 case SDP_DATA_SEQ16:
300 case SDP_DATA_ALT16:
301 SDP_GET16(len, start);
302 for (; start < end && len > 0; start ++, len --)
303 fprintf(stdout, "%#2.2x ", *start);
304 fprintf(stdout, "\n");
305 break;
306
307 case SDP_DATA_SEQ32:
308 case SDP_DATA_ALT32:
309 SDP_GET32(len, start);
310 for (; start < end && len > 0; start ++, len --)
311 fprintf(stdout, "%#2.2x ", *start);
312 fprintf(stdout, "\n");
313 break;
314
315 default:
316 fprintf(stderr, "Invalid Protocol Descriptor. " \
317 "Unknown data type: %#02x\n", type);
318 return;
319 /* NOT REACHED */
320 }
321 }
322 } /* print_protocol_descriptor */
323
324 static void
print_protocol_descriptor_list(uint8_t const * start,uint8_t const * end)325 print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
326 {
327 uint32_t type, len;
328
329 if (end - start < 2) {
330 fprintf(stderr, "Invalid Protocol Descriptor List. " \
331 "Too short, len=%zd\n", end - start);
332 return;
333 }
334
335 SDP_GET8(type, start);
336 switch (type) {
337 case SDP_DATA_SEQ8:
338 SDP_GET8(len, start);
339 break;
340
341 case SDP_DATA_SEQ16:
342 SDP_GET16(len, start);
343 break;
344
345 case SDP_DATA_SEQ32:
346 SDP_GET32(len, start);
347 break;
348
349 default:
350 fprintf(stderr, "Invalid Protocol Descriptor List. " \
351 "Not a sequence, type=%#x\n", type);
352 return;
353 /* NOT REACHED */
354 }
355
356 if (len > (end - start)) {
357 fprintf(stderr, "Invalid Protocol Descriptor List. " \
358 "Too long, len=%d\n", len);
359 return;
360 }
361
362 while (start < end) {
363 SDP_GET8(type, start);
364 switch (type) {
365 case SDP_DATA_SEQ8:
366 SDP_GET8(len, start);
367 break;
368
369 case SDP_DATA_SEQ16:
370 SDP_GET16(len, start);
371 break;
372
373 case SDP_DATA_SEQ32:
374 SDP_GET32(len, start);
375 break;
376
377 default:
378 fprintf(stderr, "Invalid Protocol Descriptor List. " \
379 "Not a sequence, type=%#x\n", type);
380 return;
381 /* NOT REACHED */
382 }
383
384 if (len > (end - start)) {
385 fprintf(stderr, "Invalid Protocol Descriptor List. " \
386 "Too long, len=%d\n", len);
387 return;
388 }
389
390 print_protocol_descriptor(start, start + len);
391 start += len;
392 }
393 } /* print_protocol_descriptor_list */
394
395 /*
396 * Print Bluetooth Profile Descriptor List
397 *
398 * The BluetoothProfileDescriptorList attribute consists of a data element
399 * sequence in which each element is a profile descriptor that contains
400 * information about a Bluetooth profile to which the service represented by
401 * this service record conforms. Each profile descriptor is a data element
402 * sequence whose first element is the UUID assigned to the profile and whose
403 * second element is a 16-bit profile version number. Each version of a profile
404 * is assigned a 16-bit unsigned integer profile version number, which consists
405 * of two 8-bit fields. The higher-order 8 bits contain the major version
406 * number field and the lower-order 8 bits contain the minor version number
407 * field.
408 */
409
410 static void
print_bluetooth_profile_descriptor_list(uint8_t const * start,uint8_t const * end)411 print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
412 {
413 uint32_t type, len, value;
414
415 if (end - start < 2) {
416 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
417 "Too short, len=%zd\n", end - start);
418 return;
419 }
420
421 SDP_GET8(type, start);
422 switch (type) {
423 case SDP_DATA_SEQ8:
424 SDP_GET8(len, start);
425 break;
426
427 case SDP_DATA_SEQ16:
428 SDP_GET16(len, start);
429 break;
430
431 case SDP_DATA_SEQ32:
432 SDP_GET32(len, start);
433 break;
434
435 default:
436 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
437 "Not a sequence, type=%#x\n", type);
438 return;
439 /* NOT REACHED */
440 }
441
442 if (len > (end - start)) {
443 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
444 "Too long, len=%d\n", len);
445 return;
446 }
447
448 while (start < end) {
449 SDP_GET8(type, start);
450 switch (type) {
451 case SDP_DATA_SEQ8:
452 SDP_GET8(len, start);
453 break;
454
455 case SDP_DATA_SEQ16:
456 SDP_GET16(len, start);
457 break;
458
459 case SDP_DATA_SEQ32:
460 SDP_GET32(len, start);
461 break;
462
463 default:
464 fprintf(stderr, "Invalid Bluetooth Profile " \
465 "Descriptor List. " \
466 "Not a sequence, type=%#x\n", type);
467 return;
468 /* NOT REACHED */
469 }
470
471 if (len > (end - start)) {
472 fprintf(stderr, "Invalid Bluetooth Profile " \
473 "Descriptor List. " \
474 "Too long, len=%d\n", len);
475 return;
476 }
477
478 /* Get UUID */
479 SDP_GET8(type, start);
480 switch (type) {
481 case SDP_DATA_UUID16:
482 SDP_GET16(value, start);
483 fprintf(stdout, "\t%s (%#4.4x) ",
484 sdp_uuid2desc(value), value);
485 break;
486
487 case SDP_DATA_UUID32:
488 SDP_GET32(value, start);
489 fprintf(stdout, "\t%#8.8x ", value);
490 break;
491
492 case SDP_DATA_UUID128: {
493 int128_t uuid;
494
495 SDP_GET_UUID128(&uuid, start);
496 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
497 ntohl(*(uint32_t *)&uuid.b[0]),
498 ntohs(*(uint16_t *)&uuid.b[4]),
499 ntohs(*(uint16_t *)&uuid.b[6]),
500 ntohs(*(uint16_t *)&uuid.b[8]),
501 ntohs(*(uint16_t *)&uuid.b[10]),
502 ntohl(*(uint32_t *)&uuid.b[12]));
503 } break;
504
505 default:
506 fprintf(stderr, "Invalid Bluetooth Profile " \
507 "Descriptor List. " \
508 "Not a UUID, type=%#x\n", type);
509 return;
510 /* NOT REACHED */
511 }
512
513 /* Get version */
514 SDP_GET8(type, start);
515 if (type != SDP_DATA_UINT16) {
516 fprintf(stderr, "Invalid Bluetooth Profile " \
517 "Descriptor List. " \
518 "Invalid version type=%#x\n", type);
519 return;
520 }
521
522 SDP_GET16(value, start);
523 fprintf(stdout, "ver. %d.%d\n",
524 (value >> 8) & 0xff, value & 0xff);
525 }
526 } /* print_bluetooth_profile_descriptor_list */
527
528 /* Perform SDP search command */
529 static int
do_sdp_search(void * xs,int argc,char ** argv)530 do_sdp_search(void *xs, int argc, char **argv)
531 {
532 char *ep = NULL;
533 int32_t n, type, value;
534 uint16_t service;
535
536 /* Parse command line arguments */
537 switch (argc) {
538 case 1:
539 n = strtoul(argv[0], &ep, 16);
540 if (*ep != 0) {
541 switch (tolower(argv[0][0])) {
542 case 'c': /* CIP/CTP */
543 switch (tolower(argv[0][1])) {
544 case 'i':
545 service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
546 break;
547
548 case 't':
549 service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
550 break;
551
552 default:
553 return (USAGE);
554 /* NOT REACHED */
555 }
556 break;
557
558 case 'd': /* DialUp Networking */
559 service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
560 break;
561
562 case 'f': /* Fax/OBEX File Transfer */
563 switch (tolower(argv[0][1])) {
564 case 'a':
565 service = SDP_SERVICE_CLASS_FAX;
566 break;
567
568 case 't':
569 service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
570 break;
571
572 default:
573 return (USAGE);
574 /* NOT REACHED */
575 }
576 break;
577
578 case 'g': /* GN */
579 service = SDP_SERVICE_CLASS_GN;
580 break;
581
582 case 'h': /* Headset/HID */
583 switch (tolower(argv[0][1])) {
584 case 'i':
585 service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
586 break;
587
588 case 's':
589 service = SDP_SERVICE_CLASS_HEADSET;
590 break;
591
592 default:
593 return (USAGE);
594 /* NOT REACHED */
595 }
596 break;
597
598 case 'l': /* LAN Access Using PPP */
599 service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
600 break;
601
602 case 'n': /* NAP */
603 service = SDP_SERVICE_CLASS_NAP;
604 break;
605
606 case 'o': /* OBEX Object Push */
607 service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
608 break;
609
610 case 's': /* Serial Port */
611 service = SDP_SERVICE_CLASS_SERIAL_PORT;
612 break;
613
614 default:
615 return (USAGE);
616 /* NOT REACHED */
617 }
618 } else
619 service = (uint16_t) n;
620 break;
621
622 default:
623 return (USAGE);
624 }
625
626 /* Initialize attribute values array */
627 for (n = 0; n < values_len; n ++) {
628 values[n].flags = SDP_ATTR_INVALID;
629 values[n].attr = 0;
630 values[n].vlen = BSIZE;
631 values[n].value = buffer[n];
632 }
633
634 /* Do SDP Service Search Attribute Request */
635 n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
636 if (n != 0)
637 return (ERROR);
638
639 /* Print attributes values */
640 for (n = 0; n < values_len; n ++) {
641 if (values[n].flags != SDP_ATTR_OK)
642 break;
643
644 switch (values[n].attr) {
645 case SDP_ATTR_SERVICE_RECORD_HANDLE:
646 fprintf(stdout, "\n");
647 if (values[n].vlen == 5) {
648 SDP_GET8(type, values[n].value);
649 if (type == SDP_DATA_UINT32) {
650 SDP_GET32(value, values[n].value);
651 fprintf(stdout, "Record Handle: " \
652 "%#8.8x\n", value);
653 } else
654 fprintf(stderr, "Invalid type=%#x " \
655 "Record Handle " \
656 "attribute!\n", type);
657 } else
658 fprintf(stderr, "Invalid size=%d for Record " \
659 "Handle attribute\n",
660 values[n].vlen);
661 break;
662
663 case SDP_ATTR_SERVICE_CLASS_ID_LIST:
664 fprintf(stdout, "Service Class ID List:\n");
665 print_service_class_id_list(values[n].value,
666 values[n].value + values[n].vlen);
667 break;
668
669 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
670 fprintf(stdout, "Protocol Descriptor List:\n");
671 print_protocol_descriptor_list(values[n].value,
672 values[n].value + values[n].vlen);
673 break;
674
675 case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
676 fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
677 print_bluetooth_profile_descriptor_list(values[n].value,
678 values[n].value + values[n].vlen);
679 break;
680
681 default:
682 fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
683 values[n].attr);
684 break;
685 }
686 }
687
688 return (OK);
689 } /* do_sdp_search */
690
691 /* Perform SDP browse command */
692 static int
do_sdp_browse(void * xs,int argc,char ** argv)693 do_sdp_browse(void *xs, int argc, char **argv)
694 {
695 #undef _STR
696 #undef STR
697 #define _STR(x) #x
698 #define STR(x) _STR(x)
699
700 static char const * const av[] = {
701 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
702 NULL
703 };
704
705 switch (argc) {
706 case 0:
707 argc = 1;
708 argv = (char **) av;
709 /* FALL THROUGH */
710 case 1:
711 return (do_sdp_search(xs, argc, argv));
712 }
713
714 return (USAGE);
715 } /* do_sdp_browse */
716
717 /* List of SDP commands */
718 struct sdp_command sdp_commands[] = {
719 {
720 "Browse [<Group>]",
721 "Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
722 "to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
723 "\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
724 do_sdp_browse
725 },
726 {
727 "Search <Service>",
728 "Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
729 "service to search for. For some services it is possible to use service name\n"\
730 "instead of service UUID\n\n" \
731 "\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
732 "\tKnown service names\n" \
733 "\t===================\n" \
734 "\tCIP - Common ISDN Access\n" \
735 "\tCTP - Cordless Telephony\n" \
736 "\tDUN - DialUp Networking\n" \
737 "\tFAX - Fax\n" \
738 "\tFTRN - OBEX File Transfer\n" \
739 "\tGN - GN\n" \
740 "\tHID - Human Interface Device\n" \
741 "\tHSET - Headset\n" \
742 "\tLAN - LAN Access Using PPP\n" \
743 "\tNAP - Network Access Point\n" \
744 "\tOPUSH - OBEX Object Push\n" \
745 "\tSP - Serial Port\n",
746 do_sdp_search
747 },
748 { NULL, NULL, NULL }
749 };
750
751