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