xref: /freebsd/usr.sbin/bluetooth/sdpcontrol/search.c (revision fdbf7cab91ae9ae7ca87bd47acb7400813bd7160)
11de7b4b8SPedro F. Giffuni /*-
20986ab12SMaksim Yevmenkin  * search.c
30986ab12SMaksim Yevmenkin  *
44d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni  *
60986ab12SMaksim Yevmenkin  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
70986ab12SMaksim Yevmenkin  * All rights reserved.
80986ab12SMaksim Yevmenkin  *
90986ab12SMaksim Yevmenkin  * Redistribution and use in source and binary forms, with or without
100986ab12SMaksim Yevmenkin  * modification, are permitted provided that the following conditions
110986ab12SMaksim Yevmenkin  * are met:
120986ab12SMaksim Yevmenkin  * 1. Redistributions of source code must retain the above copyright
130986ab12SMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer.
140986ab12SMaksim Yevmenkin  * 2. Redistributions in binary form must reproduce the above copyright
150986ab12SMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer in the
160986ab12SMaksim Yevmenkin  *    documentation and/or other materials provided with the distribution.
170986ab12SMaksim Yevmenkin  *
180986ab12SMaksim Yevmenkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
190986ab12SMaksim Yevmenkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
200986ab12SMaksim Yevmenkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
210986ab12SMaksim Yevmenkin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
220986ab12SMaksim Yevmenkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
230986ab12SMaksim Yevmenkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
240986ab12SMaksim Yevmenkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
250986ab12SMaksim Yevmenkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
260986ab12SMaksim Yevmenkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
270986ab12SMaksim Yevmenkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
280986ab12SMaksim Yevmenkin  * SUCH DAMAGE.
290986ab12SMaksim Yevmenkin  *
300986ab12SMaksim Yevmenkin  * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
310986ab12SMaksim Yevmenkin  */
320986ab12SMaksim Yevmenkin 
33*fdbf7cabSElyes Haouas #include <sys/param.h>
3443d33de9SMaksim Yevmenkin #include <netinet/in.h>
358d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
360986ab12SMaksim Yevmenkin #include <bluetooth.h>
370986ab12SMaksim Yevmenkin #include <ctype.h>
380986ab12SMaksim Yevmenkin #include <sdp.h>
390986ab12SMaksim Yevmenkin #include <stdio.h>
400986ab12SMaksim Yevmenkin #include <stdlib.h>
410986ab12SMaksim Yevmenkin #include "sdpcontrol.h"
420986ab12SMaksim Yevmenkin 
430986ab12SMaksim Yevmenkin /* List of the attributes we are looking for */
44a4b187faSMaksim Yevmenkin static uint32_t	attrs[] =
450986ab12SMaksim Yevmenkin {
460986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_RECORD_HANDLE,
470986ab12SMaksim Yevmenkin 			SDP_ATTR_SERVICE_RECORD_HANDLE),
480986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_CLASS_ID_LIST,
490986ab12SMaksim Yevmenkin 			SDP_ATTR_SERVICE_CLASS_ID_LIST),
500986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
510986ab12SMaksim Yevmenkin 			SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
520986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
530986ab12SMaksim Yevmenkin 			SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
540986ab12SMaksim Yevmenkin };
55*fdbf7cabSElyes Haouas #define attrs_len	nitems(attrs)
560986ab12SMaksim Yevmenkin 
570986ab12SMaksim Yevmenkin /* Buffer for the attributes */
580986ab12SMaksim Yevmenkin #define NRECS	25	/* request this much records from the SDP server */
590986ab12SMaksim Yevmenkin #define	BSIZE	256	/* one attribute buffer size */
60a4b187faSMaksim Yevmenkin static uint8_t		buffer[NRECS * attrs_len][BSIZE];
610986ab12SMaksim Yevmenkin 
620986ab12SMaksim Yevmenkin /* SDP attributes */
630986ab12SMaksim Yevmenkin static sdp_attr_t	values[NRECS * attrs_len];
64*fdbf7cabSElyes Haouas #define values_len	nitems(values)
650986ab12SMaksim Yevmenkin 
660986ab12SMaksim Yevmenkin /*
670986ab12SMaksim Yevmenkin  * Print Service Class ID List
680986ab12SMaksim Yevmenkin  *
690986ab12SMaksim Yevmenkin  * The ServiceClassIDList attribute consists of a data element sequence in
700986ab12SMaksim Yevmenkin  * which each data element is a UUID representing the service classes that
710986ab12SMaksim Yevmenkin  * a given service record conforms to. The UUIDs are listed in order from
720986ab12SMaksim Yevmenkin  * the most specific class to the most general class. The ServiceClassIDList
730986ab12SMaksim Yevmenkin  * must contain at least one service class UUID.
740986ab12SMaksim Yevmenkin  */
750986ab12SMaksim Yevmenkin 
760986ab12SMaksim Yevmenkin static void
77a4b187faSMaksim Yevmenkin print_service_class_id_list(uint8_t const *start, uint8_t const *end)
780986ab12SMaksim Yevmenkin {
79a4b187faSMaksim Yevmenkin 	uint32_t	type, len, value;
800986ab12SMaksim Yevmenkin 
810986ab12SMaksim Yevmenkin 	if (end - start < 2) {
820986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Service Class ID List. " \
834ae439a3SMaksim Yevmenkin 				"Too short, len=%zd\n", end - start);
840986ab12SMaksim Yevmenkin 		return;
850986ab12SMaksim Yevmenkin 	}
860986ab12SMaksim Yevmenkin 
870986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
880986ab12SMaksim Yevmenkin 	switch (type) {
890986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ8:
900986ab12SMaksim Yevmenkin 		SDP_GET8(len, start);
910986ab12SMaksim Yevmenkin 		break;
920986ab12SMaksim Yevmenkin 
930986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ16:
940986ab12SMaksim Yevmenkin 		SDP_GET16(len, start);
950986ab12SMaksim Yevmenkin 		break;
960986ab12SMaksim Yevmenkin 
970986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ32:
980986ab12SMaksim Yevmenkin 		SDP_GET32(len, start);
990986ab12SMaksim Yevmenkin 		break;
1000986ab12SMaksim Yevmenkin 
1010986ab12SMaksim Yevmenkin 	default:
1020986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Service Class ID List. " \
1030986ab12SMaksim Yevmenkin 				"Not a sequence, type=%#x\n", type);
1040986ab12SMaksim Yevmenkin 		return;
1050986ab12SMaksim Yevmenkin 		/* NOT REACHED */
1060986ab12SMaksim Yevmenkin 	}
1070986ab12SMaksim Yevmenkin 
108f32d9c4bSMaksim Yevmenkin 	if (len > (end - start)) {
109f32d9c4bSMaksim Yevmenkin 		fprintf(stderr, "Invalid Service Class ID List. " \
110f32d9c4bSMaksim Yevmenkin 				"Too long len=%d\n", len);
111f32d9c4bSMaksim Yevmenkin 		return;
112f32d9c4bSMaksim Yevmenkin 	}
113f32d9c4bSMaksim Yevmenkin 
1140986ab12SMaksim Yevmenkin 	while (start < end) {
1150986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
1160986ab12SMaksim Yevmenkin 		switch (type) {
1170986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID16:
1180986ab12SMaksim Yevmenkin 			SDP_GET16(value, start);
1190986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%s (%#4.4x)\n",
1200986ab12SMaksim Yevmenkin 					sdp_uuid2desc(value), value);
1210986ab12SMaksim Yevmenkin 			break;
1220986ab12SMaksim Yevmenkin 
1230986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID32:
1240986ab12SMaksim Yevmenkin 			SDP_GET32(value, start);
1250986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x\n", value);
1260986ab12SMaksim Yevmenkin 			break;
1270986ab12SMaksim Yevmenkin 
1280986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID128: {
1290986ab12SMaksim Yevmenkin 			int128_t	uuid;
1300986ab12SMaksim Yevmenkin 
13143d33de9SMaksim Yevmenkin 			SDP_GET_UUID128(&uuid, start);
1320986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
13343d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[0]),
13443d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[4]),
13543d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[6]),
13643d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[8]),
13743d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[10]),
13843d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[12]));
1390986ab12SMaksim Yevmenkin 			} break;
1400986ab12SMaksim Yevmenkin 
1410986ab12SMaksim Yevmenkin 		default:
1420986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Service Class ID List. " \
1430986ab12SMaksim Yevmenkin 					"Not a UUID, type=%#x\n", type);
1440986ab12SMaksim Yevmenkin 			return;
1450986ab12SMaksim Yevmenkin 			/* NOT REACHED */
1460986ab12SMaksim Yevmenkin 		}
1470986ab12SMaksim Yevmenkin 	}
1480986ab12SMaksim Yevmenkin } /* print_service_class_id_list */
1490986ab12SMaksim Yevmenkin 
1500986ab12SMaksim Yevmenkin /*
1510986ab12SMaksim Yevmenkin  * Print Protocol Descriptor List
1520986ab12SMaksim Yevmenkin  *
1530986ab12SMaksim Yevmenkin  * If the ProtocolDescriptorList describes a single stack, it takes the form
1540986ab12SMaksim Yevmenkin  * of a data element sequence in which each element of the sequence is a
1550986ab12SMaksim Yevmenkin  * protocol descriptor. Each protocol descriptor is, in turn, a data element
1560986ab12SMaksim Yevmenkin  * sequence whose first element is a UUID identifying the protocol and whose
1570986ab12SMaksim Yevmenkin  * successive elements are protocol-specific parameters. The protocol
1580986ab12SMaksim Yevmenkin  * descriptors are listed in order from the lowest layer protocol to the
1590986ab12SMaksim Yevmenkin  * highest layer protocol used to gain access to the service. If it is possible
1600986ab12SMaksim Yevmenkin  * for more than one kind of protocol stack to be used to gain access to the
1610986ab12SMaksim Yevmenkin  * service, the ProtocolDescriptorList takes the form of a data element
1620986ab12SMaksim Yevmenkin  * alternative where each member is a data element sequence as described above.
1630986ab12SMaksim Yevmenkin  */
1640986ab12SMaksim Yevmenkin 
1650986ab12SMaksim Yevmenkin static void
166a4b187faSMaksim Yevmenkin print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
1670986ab12SMaksim Yevmenkin {
1680986ab12SMaksim Yevmenkin 	union {
1690986ab12SMaksim Yevmenkin 		uint8_t		uint8;
1700986ab12SMaksim Yevmenkin 		uint16_t	uint16;
1710986ab12SMaksim Yevmenkin 		uint32_t	uint32;
1720986ab12SMaksim Yevmenkin 		uint64_t	uint64;
1730986ab12SMaksim Yevmenkin 		int128_t	int128;
1740986ab12SMaksim Yevmenkin 	}			value;
175a4b187faSMaksim Yevmenkin 	uint32_t		type, len, param;
1760986ab12SMaksim Yevmenkin 
1770986ab12SMaksim Yevmenkin 	/* Get Protocol UUID */
1780986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
1790986ab12SMaksim Yevmenkin 	switch (type) {
1800986ab12SMaksim Yevmenkin 	case SDP_DATA_UUID16:
1810986ab12SMaksim Yevmenkin 		SDP_GET16(value.uint16, start);
1820986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
1830986ab12SMaksim Yevmenkin 				value.uint16);
1840986ab12SMaksim Yevmenkin 		break;
1850986ab12SMaksim Yevmenkin 
1860986ab12SMaksim Yevmenkin 	case SDP_DATA_UUID32:
1870986ab12SMaksim Yevmenkin 		SDP_GET32(value.uint32, start);
1880986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t%#8.8x\n", value.uint32);
1890986ab12SMaksim Yevmenkin 		break;
1900986ab12SMaksim Yevmenkin 
1910986ab12SMaksim Yevmenkin 	case SDP_DATA_UUID128:
19243d33de9SMaksim Yevmenkin 		SDP_GET_UUID128(&value.int128, start);
1930986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
19443d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[0]),
19543d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[4]),
19643d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[6]),
19743d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[8]),
19843d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[10]),
19943d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[12]));
2000986ab12SMaksim Yevmenkin 		break;
2010986ab12SMaksim Yevmenkin 
2020986ab12SMaksim Yevmenkin 	default:
2030986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor. " \
2040986ab12SMaksim Yevmenkin 				"Not a UUID, type=%#x\n", type);
2050986ab12SMaksim Yevmenkin 		return;
2060986ab12SMaksim Yevmenkin 		/* NOT REACHED */
2070986ab12SMaksim Yevmenkin 	}
2080986ab12SMaksim Yevmenkin 
2090986ab12SMaksim Yevmenkin 	/* Protocol specific parameters */
2100986ab12SMaksim Yevmenkin 	for (param = 1; start < end; param ++) {
2110986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
2120986ab12SMaksim Yevmenkin 
2130986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
2140986ab12SMaksim Yevmenkin 		switch (type) {
2150986ab12SMaksim Yevmenkin 		case SDP_DATA_NIL:
2160986ab12SMaksim Yevmenkin 			fprintf(stdout, "nil\n");
2170986ab12SMaksim Yevmenkin 			break;
2180986ab12SMaksim Yevmenkin 
2190986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT8:
2200986ab12SMaksim Yevmenkin 		case SDP_DATA_INT8:
2210986ab12SMaksim Yevmenkin 		case SDP_DATA_BOOL:
2220986ab12SMaksim Yevmenkin 			SDP_GET8(value.uint8, start);
2230986ab12SMaksim Yevmenkin 			fprintf(stdout, "u/int8/bool %u\n", value.uint8);
2240986ab12SMaksim Yevmenkin 			break;
2250986ab12SMaksim Yevmenkin 
2260986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT16:
2270986ab12SMaksim Yevmenkin 		case SDP_DATA_INT16:
2280986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID16:
2290986ab12SMaksim Yevmenkin 			SDP_GET16(value.uint16, start);
2300986ab12SMaksim Yevmenkin 			fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
2310986ab12SMaksim Yevmenkin 			break;
2320986ab12SMaksim Yevmenkin 
2330986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT32:
2340986ab12SMaksim Yevmenkin 		case SDP_DATA_INT32:
2350986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID32:
2360986ab12SMaksim Yevmenkin 			SDP_GET32(value.uint32, start);
2370986ab12SMaksim Yevmenkin 			fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
2380986ab12SMaksim Yevmenkin 			break;
2390986ab12SMaksim Yevmenkin 
2400986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT64:
2410986ab12SMaksim Yevmenkin 		case SDP_DATA_INT64:
2420986ab12SMaksim Yevmenkin 			SDP_GET64(value.uint64, start);
2434ae439a3SMaksim Yevmenkin 			fprintf(stdout, "u/int64 %ju\n", value.uint64);
2440986ab12SMaksim Yevmenkin 			break;
2450986ab12SMaksim Yevmenkin 
2460986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT128:
2470986ab12SMaksim Yevmenkin 		case SDP_DATA_INT128:
2480986ab12SMaksim Yevmenkin 			SDP_GET128(&value.int128, start);
24943d33de9SMaksim Yevmenkin 			fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
250a4b187faSMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[0],
25143d33de9SMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[4],
25243d33de9SMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[8],
253a4b187faSMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[12]);
2540986ab12SMaksim Yevmenkin 			break;
2550986ab12SMaksim Yevmenkin 
25643d33de9SMaksim Yevmenkin 		case SDP_DATA_UUID128:
25743d33de9SMaksim Yevmenkin 			SDP_GET_UUID128(&value.int128, start);
25843d33de9SMaksim Yevmenkin 			fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
25943d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[0]),
26043d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[4]),
26143d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[6]),
26243d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[8]),
26343d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[10]),
26443d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[12]));
26543d33de9SMaksim Yevmenkin 			break;
26643d33de9SMaksim Yevmenkin 
2670986ab12SMaksim Yevmenkin 		case SDP_DATA_STR8:
2680986ab12SMaksim Yevmenkin 		case SDP_DATA_URL8:
2690986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
270f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
271f32d9c4bSMaksim Yevmenkin 				fprintf(stdout, "%c", *start);
272f32d9c4bSMaksim Yevmenkin 			fprintf(stdout, "\n");
2730986ab12SMaksim Yevmenkin 			break;
2740986ab12SMaksim Yevmenkin 
2750986ab12SMaksim Yevmenkin 		case SDP_DATA_STR16:
2760986ab12SMaksim Yevmenkin 		case SDP_DATA_URL16:
2770986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
278f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
279f32d9c4bSMaksim Yevmenkin 				fprintf(stdout, "%c", *start);
280f32d9c4bSMaksim Yevmenkin 			fprintf(stdout, "\n");
2810986ab12SMaksim Yevmenkin 			break;
2820986ab12SMaksim Yevmenkin 
2830986ab12SMaksim Yevmenkin 		case SDP_DATA_STR32:
2840986ab12SMaksim Yevmenkin 		case SDP_DATA_URL32:
2850986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
286f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
287f32d9c4bSMaksim Yevmenkin 				fprintf(stdout, "%c", *start);
288f32d9c4bSMaksim Yevmenkin 			fprintf(stdout, "\n");
2890986ab12SMaksim Yevmenkin 			break;
2900986ab12SMaksim Yevmenkin 
2910986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ8:
2920986ab12SMaksim Yevmenkin 		case SDP_DATA_ALT8:
2930986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
294f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
2950986ab12SMaksim Yevmenkin 				fprintf(stdout, "%#2.2x ", *start);
2960986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
2970986ab12SMaksim Yevmenkin 			break;
2980986ab12SMaksim Yevmenkin 
2990986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ16:
3000986ab12SMaksim Yevmenkin 		case SDP_DATA_ALT16:
3010986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
302f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
3030986ab12SMaksim Yevmenkin 				fprintf(stdout, "%#2.2x ", *start);
3040986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
3050986ab12SMaksim Yevmenkin 			break;
3060986ab12SMaksim Yevmenkin 
3070986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ32:
3080986ab12SMaksim Yevmenkin 		case SDP_DATA_ALT32:
3090986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
310f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
3110986ab12SMaksim Yevmenkin 				fprintf(stdout, "%#2.2x ", *start);
3120986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
3130986ab12SMaksim Yevmenkin 			break;
3140986ab12SMaksim Yevmenkin 
3150986ab12SMaksim Yevmenkin 		default:
3160986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Protocol Descriptor. " \
3170986ab12SMaksim Yevmenkin 					"Unknown data type: %#02x\n", type);
3180986ab12SMaksim Yevmenkin 			return;
3190986ab12SMaksim Yevmenkin 			/* NOT REACHED */
3200986ab12SMaksim Yevmenkin 		}
3210986ab12SMaksim Yevmenkin 	}
3220986ab12SMaksim Yevmenkin } /* print_protocol_descriptor */
3230986ab12SMaksim Yevmenkin 
3240986ab12SMaksim Yevmenkin static void
325a4b187faSMaksim Yevmenkin print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
3260986ab12SMaksim Yevmenkin {
327a4b187faSMaksim Yevmenkin 	uint32_t	type, len;
3280986ab12SMaksim Yevmenkin 
3290986ab12SMaksim Yevmenkin 	if (end - start < 2) {
3300986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor List. " \
3314ae439a3SMaksim Yevmenkin 				"Too short, len=%zd\n", end - start);
3320986ab12SMaksim Yevmenkin 		return;
3330986ab12SMaksim Yevmenkin 	}
3340986ab12SMaksim Yevmenkin 
3350986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
3360986ab12SMaksim Yevmenkin 	switch (type) {
3370986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ8:
3380986ab12SMaksim Yevmenkin 		SDP_GET8(len, start);
3390986ab12SMaksim Yevmenkin 		break;
3400986ab12SMaksim Yevmenkin 
3410986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ16:
3420986ab12SMaksim Yevmenkin 		SDP_GET16(len, start);
3430986ab12SMaksim Yevmenkin 		break;
3440986ab12SMaksim Yevmenkin 
3450986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ32:
3460986ab12SMaksim Yevmenkin 		SDP_GET32(len, start);
3470986ab12SMaksim Yevmenkin 		break;
3480986ab12SMaksim Yevmenkin 
3490986ab12SMaksim Yevmenkin 	default:
3500986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor List. " \
3510986ab12SMaksim Yevmenkin 				"Not a sequence, type=%#x\n", type);
3520986ab12SMaksim Yevmenkin 		return;
3530986ab12SMaksim Yevmenkin 		/* NOT REACHED */
3540986ab12SMaksim Yevmenkin 	}
3550986ab12SMaksim Yevmenkin 
356f32d9c4bSMaksim Yevmenkin 	if (len > (end - start)) {
357f32d9c4bSMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor List. " \
358f32d9c4bSMaksim Yevmenkin 				"Too long, len=%d\n", len);
359f32d9c4bSMaksim Yevmenkin 		return;
360f32d9c4bSMaksim Yevmenkin 	}
361f32d9c4bSMaksim Yevmenkin 
3620986ab12SMaksim Yevmenkin 	while (start < end) {
3630986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
3640986ab12SMaksim Yevmenkin 		switch (type) {
3650986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ8:
3660986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
3670986ab12SMaksim Yevmenkin 			break;
3680986ab12SMaksim Yevmenkin 
3690986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ16:
3700986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
3710986ab12SMaksim Yevmenkin 			break;
3720986ab12SMaksim Yevmenkin 
3730986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ32:
3740986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
3750986ab12SMaksim Yevmenkin 			break;
3760986ab12SMaksim Yevmenkin 
3770986ab12SMaksim Yevmenkin 		default:
3780986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Protocol Descriptor List. " \
3790986ab12SMaksim Yevmenkin 					"Not a sequence, type=%#x\n", type);
3800986ab12SMaksim Yevmenkin 			return;
3810986ab12SMaksim Yevmenkin 			/* NOT REACHED */
3820986ab12SMaksim Yevmenkin 		}
3830986ab12SMaksim Yevmenkin 
384f32d9c4bSMaksim Yevmenkin 		if (len > (end - start)) {
385f32d9c4bSMaksim Yevmenkin 			fprintf(stderr, "Invalid Protocol Descriptor List. " \
386f32d9c4bSMaksim Yevmenkin 					"Too long, len=%d\n", len);
387f32d9c4bSMaksim Yevmenkin 			return;
388f32d9c4bSMaksim Yevmenkin 		}
389f32d9c4bSMaksim Yevmenkin 
3900986ab12SMaksim Yevmenkin 		print_protocol_descriptor(start, start + len);
3910986ab12SMaksim Yevmenkin 		start += len;
3920986ab12SMaksim Yevmenkin 	}
3930986ab12SMaksim Yevmenkin } /* print_protocol_descriptor_list */
3940986ab12SMaksim Yevmenkin 
3950986ab12SMaksim Yevmenkin /*
3960986ab12SMaksim Yevmenkin  * Print Bluetooth Profile Descriptor List
3970986ab12SMaksim Yevmenkin  *
3980986ab12SMaksim Yevmenkin  * The BluetoothProfileDescriptorList attribute consists of a data element
3990986ab12SMaksim Yevmenkin  * sequence in which each element is a profile descriptor that contains
4000986ab12SMaksim Yevmenkin  * information about a Bluetooth profile to which the service represented by
4010986ab12SMaksim Yevmenkin  * this service record conforms. Each profile descriptor is a data element
4020986ab12SMaksim Yevmenkin  * sequence whose first element is the UUID assigned to the profile and whose
4030986ab12SMaksim Yevmenkin  * second element is a 16-bit profile version number. Each version of a profile
4040986ab12SMaksim Yevmenkin  * is assigned a 16-bit unsigned integer profile version number, which consists
4050986ab12SMaksim Yevmenkin  * of two 8-bit fields. The higher-order 8 bits contain the major version
4060986ab12SMaksim Yevmenkin  * number field and the lower-order 8 bits contain the minor version number
4070986ab12SMaksim Yevmenkin  * field.
4080986ab12SMaksim Yevmenkin  */
4090986ab12SMaksim Yevmenkin 
4100986ab12SMaksim Yevmenkin static void
411a4b187faSMaksim Yevmenkin print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
4120986ab12SMaksim Yevmenkin {
413a4b187faSMaksim Yevmenkin 	uint32_t	type, len, value;
4140986ab12SMaksim Yevmenkin 
4150986ab12SMaksim Yevmenkin 	if (end - start < 2) {
4160986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
4174ae439a3SMaksim Yevmenkin 				"Too short, len=%zd\n", end - start);
4180986ab12SMaksim Yevmenkin 		return;
4190986ab12SMaksim Yevmenkin 	}
4200986ab12SMaksim Yevmenkin 
4210986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
4220986ab12SMaksim Yevmenkin 	switch (type) {
4230986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ8:
4240986ab12SMaksim Yevmenkin 		SDP_GET8(len, start);
4250986ab12SMaksim Yevmenkin 		break;
4260986ab12SMaksim Yevmenkin 
4270986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ16:
4280986ab12SMaksim Yevmenkin 		SDP_GET16(len, start);
4290986ab12SMaksim Yevmenkin 		break;
4300986ab12SMaksim Yevmenkin 
4310986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ32:
4320986ab12SMaksim Yevmenkin 		SDP_GET32(len, start);
4330986ab12SMaksim Yevmenkin 		break;
4340986ab12SMaksim Yevmenkin 
4350986ab12SMaksim Yevmenkin 	default:
4360986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
4370986ab12SMaksim Yevmenkin 				"Not a sequence, type=%#x\n", type);
4380986ab12SMaksim Yevmenkin 		return;
4390986ab12SMaksim Yevmenkin 		/* NOT REACHED */
4400986ab12SMaksim Yevmenkin 	}
4410986ab12SMaksim Yevmenkin 
442f32d9c4bSMaksim Yevmenkin 	if (len > (end - start)) {
443f32d9c4bSMaksim Yevmenkin 		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
444f32d9c4bSMaksim Yevmenkin 				"Too long, len=%d\n", len);
445f32d9c4bSMaksim Yevmenkin 		return;
446f32d9c4bSMaksim Yevmenkin 	}
447f32d9c4bSMaksim Yevmenkin 
4480986ab12SMaksim Yevmenkin 	while (start < end) {
4490986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
4500986ab12SMaksim Yevmenkin 		switch (type) {
4510986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ8:
4520986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
4530986ab12SMaksim Yevmenkin 			break;
4540986ab12SMaksim Yevmenkin 
4550986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ16:
4560986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
4570986ab12SMaksim Yevmenkin 			break;
4580986ab12SMaksim Yevmenkin 
4590986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ32:
4600986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
4610986ab12SMaksim Yevmenkin 			break;
4620986ab12SMaksim Yevmenkin 
4630986ab12SMaksim Yevmenkin 		default:
4640986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
4650986ab12SMaksim Yevmenkin 					"Descriptor List. " \
4660986ab12SMaksim Yevmenkin 					"Not a sequence, type=%#x\n", type);
4670986ab12SMaksim Yevmenkin 			return;
4680986ab12SMaksim Yevmenkin 			/* NOT REACHED */
4690986ab12SMaksim Yevmenkin 		}
4700986ab12SMaksim Yevmenkin 
471f32d9c4bSMaksim Yevmenkin 		if (len > (end - start)) {
472f32d9c4bSMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
473f32d9c4bSMaksim Yevmenkin 					"Descriptor List. " \
474f32d9c4bSMaksim Yevmenkin 					"Too long, len=%d\n", len);
475f32d9c4bSMaksim Yevmenkin 			return;
476f32d9c4bSMaksim Yevmenkin 		}
477f32d9c4bSMaksim Yevmenkin 
4780986ab12SMaksim Yevmenkin 		/* Get UUID */
4790986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
4800986ab12SMaksim Yevmenkin 		switch (type) {
4810986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID16:
4820986ab12SMaksim Yevmenkin 			SDP_GET16(value, start);
4830986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%s (%#4.4x) ",
4840986ab12SMaksim Yevmenkin 					sdp_uuid2desc(value), value);
4850986ab12SMaksim Yevmenkin 			break;
4860986ab12SMaksim Yevmenkin 
4870986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID32:
4880986ab12SMaksim Yevmenkin 			SDP_GET32(value, start);
4890986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x ", value);
4900986ab12SMaksim Yevmenkin 			break;
4910986ab12SMaksim Yevmenkin 
4920986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID128: {
4930986ab12SMaksim Yevmenkin 			int128_t	uuid;
4940986ab12SMaksim Yevmenkin 
49543d33de9SMaksim Yevmenkin 			SDP_GET_UUID128(&uuid, start);
4960986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
49743d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[0]),
49843d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[4]),
49943d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[6]),
50043d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[8]),
50143d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[10]),
50243d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[12]));
5030986ab12SMaksim Yevmenkin 			} break;
5040986ab12SMaksim Yevmenkin 
5050986ab12SMaksim Yevmenkin 		default:
5060986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
5070986ab12SMaksim Yevmenkin 					"Descriptor List. " \
5080986ab12SMaksim Yevmenkin 					"Not a UUID, type=%#x\n", type);
5090986ab12SMaksim Yevmenkin 			return;
5100986ab12SMaksim Yevmenkin 			/* NOT REACHED */
5110986ab12SMaksim Yevmenkin 		}
5120986ab12SMaksim Yevmenkin 
5130986ab12SMaksim Yevmenkin 		/* Get version */
5140986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
5150986ab12SMaksim Yevmenkin 		if (type != SDP_DATA_UINT16) {
5160986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
5170986ab12SMaksim Yevmenkin 					"Descriptor List. " \
5180986ab12SMaksim Yevmenkin 					"Invalid version type=%#x\n", type);
5190986ab12SMaksim Yevmenkin 			return;
5200986ab12SMaksim Yevmenkin 		}
5210986ab12SMaksim Yevmenkin 
5220986ab12SMaksim Yevmenkin 		SDP_GET16(value, start);
5230986ab12SMaksim Yevmenkin 		fprintf(stdout, "ver. %d.%d\n",
5240986ab12SMaksim Yevmenkin 				(value >> 8) & 0xff, value & 0xff);
5250986ab12SMaksim Yevmenkin 	}
5260986ab12SMaksim Yevmenkin } /* print_bluetooth_profile_descriptor_list */
5270986ab12SMaksim Yevmenkin 
5280986ab12SMaksim Yevmenkin /* Perform SDP search command */
5290986ab12SMaksim Yevmenkin static int
5300986ab12SMaksim Yevmenkin do_sdp_search(void *xs, int argc, char **argv)
5310986ab12SMaksim Yevmenkin {
5320986ab12SMaksim Yevmenkin 	char		*ep = NULL;
5330986ab12SMaksim Yevmenkin 	int32_t		 n, type, value;
534a4b187faSMaksim Yevmenkin 	uint16_t	 service;
5350986ab12SMaksim Yevmenkin 
5360986ab12SMaksim Yevmenkin 	/* Parse command line arguments */
5370986ab12SMaksim Yevmenkin 	switch (argc) {
5380986ab12SMaksim Yevmenkin 	case 1:
5390986ab12SMaksim Yevmenkin 		n = strtoul(argv[0], &ep, 16);
5400986ab12SMaksim Yevmenkin 		if (*ep != 0) {
5410986ab12SMaksim Yevmenkin 			switch (tolower(argv[0][0])) {
5420986ab12SMaksim Yevmenkin 			case 'c': /* CIP/CTP */
5430986ab12SMaksim Yevmenkin 				switch (tolower(argv[0][1])) {
5440986ab12SMaksim Yevmenkin 				case 'i':
5450986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
5460986ab12SMaksim Yevmenkin 					break;
5470986ab12SMaksim Yevmenkin 
5480986ab12SMaksim Yevmenkin 				case 't':
5490986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
5500986ab12SMaksim Yevmenkin 					break;
5510986ab12SMaksim Yevmenkin 
5520986ab12SMaksim Yevmenkin 				default:
5530986ab12SMaksim Yevmenkin 					return (USAGE);
5540986ab12SMaksim Yevmenkin 					/* NOT REACHED */
5550986ab12SMaksim Yevmenkin 				}
5560986ab12SMaksim Yevmenkin 				break;
5570986ab12SMaksim Yevmenkin 
5580986ab12SMaksim Yevmenkin 			case 'd': /* DialUp Networking */
5590986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
5600986ab12SMaksim Yevmenkin 				break;
5610986ab12SMaksim Yevmenkin 
5620986ab12SMaksim Yevmenkin 			case 'f': /* Fax/OBEX File Transfer */
5630986ab12SMaksim Yevmenkin 				switch (tolower(argv[0][1])) {
5640986ab12SMaksim Yevmenkin 				case 'a':
5650986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_FAX;
5660986ab12SMaksim Yevmenkin 					break;
5670986ab12SMaksim Yevmenkin 
5680986ab12SMaksim Yevmenkin 				case 't':
5690986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
5700986ab12SMaksim Yevmenkin 					break;
5710986ab12SMaksim Yevmenkin 
5720986ab12SMaksim Yevmenkin 				default:
5730986ab12SMaksim Yevmenkin 					return (USAGE);
5740986ab12SMaksim Yevmenkin 					/* NOT REACHED */
5750986ab12SMaksim Yevmenkin 				}
5760986ab12SMaksim Yevmenkin 				break;
5770986ab12SMaksim Yevmenkin 
5780986ab12SMaksim Yevmenkin 			case 'g': /* GN */
5790986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_GN;
5800986ab12SMaksim Yevmenkin 				break;
5810986ab12SMaksim Yevmenkin 
5820986ab12SMaksim Yevmenkin 			case 'h': /* Headset/HID */
5830986ab12SMaksim Yevmenkin 				switch (tolower(argv[0][1])) {
5840986ab12SMaksim Yevmenkin 				case 'i':
5850986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
5860986ab12SMaksim Yevmenkin 					break;
5870986ab12SMaksim Yevmenkin 
5880986ab12SMaksim Yevmenkin 				case 's':
5890986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_HEADSET;
5900986ab12SMaksim Yevmenkin 					break;
5910986ab12SMaksim Yevmenkin 
5920986ab12SMaksim Yevmenkin 				default:
5930986ab12SMaksim Yevmenkin 					return (USAGE);
5940986ab12SMaksim Yevmenkin 					/* NOT REACHED */
5950986ab12SMaksim Yevmenkin 				}
5960986ab12SMaksim Yevmenkin 				break;
5970986ab12SMaksim Yevmenkin 
5980986ab12SMaksim Yevmenkin 			case 'l': /* LAN Access Using PPP */
5990986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
6000986ab12SMaksim Yevmenkin 				break;
6010986ab12SMaksim Yevmenkin 
6020986ab12SMaksim Yevmenkin 			case 'n': /* NAP */
6030986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_NAP;
6040986ab12SMaksim Yevmenkin 				break;
6050986ab12SMaksim Yevmenkin 
6060986ab12SMaksim Yevmenkin 			case 'o': /* OBEX Object Push */
6070986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
6080986ab12SMaksim Yevmenkin 				break;
6090986ab12SMaksim Yevmenkin 
6100986ab12SMaksim Yevmenkin 			case 's': /* Serial Port */
6110986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_SERIAL_PORT;
6120986ab12SMaksim Yevmenkin 				break;
6130986ab12SMaksim Yevmenkin 
6140986ab12SMaksim Yevmenkin 			default:
6150986ab12SMaksim Yevmenkin 				return (USAGE);
6160986ab12SMaksim Yevmenkin 				/* NOT REACHED */
6170986ab12SMaksim Yevmenkin 			}
6180986ab12SMaksim Yevmenkin 		} else
619a4b187faSMaksim Yevmenkin 			service = (uint16_t) n;
6200986ab12SMaksim Yevmenkin 		break;
6210986ab12SMaksim Yevmenkin 
6220986ab12SMaksim Yevmenkin 	default:
6230986ab12SMaksim Yevmenkin 		return (USAGE);
6240986ab12SMaksim Yevmenkin 	}
6250986ab12SMaksim Yevmenkin 
6260986ab12SMaksim Yevmenkin 	/* Initialize attribute values array */
6270986ab12SMaksim Yevmenkin 	for (n = 0; n < values_len; n ++) {
6280986ab12SMaksim Yevmenkin 		values[n].flags = SDP_ATTR_INVALID;
6290986ab12SMaksim Yevmenkin 		values[n].attr = 0;
6300986ab12SMaksim Yevmenkin 		values[n].vlen = BSIZE;
6310986ab12SMaksim Yevmenkin 		values[n].value = buffer[n];
6320986ab12SMaksim Yevmenkin 	}
6330986ab12SMaksim Yevmenkin 
6340986ab12SMaksim Yevmenkin 	/* Do SDP Service Search Attribute Request */
6350986ab12SMaksim Yevmenkin 	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
6360986ab12SMaksim Yevmenkin 	if (n != 0)
6370986ab12SMaksim Yevmenkin 		return (ERROR);
6380986ab12SMaksim Yevmenkin 
6390986ab12SMaksim Yevmenkin 	/* Print attributes values */
6400986ab12SMaksim Yevmenkin 	for (n = 0; n < values_len; n ++) {
6410986ab12SMaksim Yevmenkin 		if (values[n].flags != SDP_ATTR_OK)
6420986ab12SMaksim Yevmenkin 			break;
6430986ab12SMaksim Yevmenkin 
6440986ab12SMaksim Yevmenkin 		switch (values[n].attr) {
6450986ab12SMaksim Yevmenkin 		case SDP_ATTR_SERVICE_RECORD_HANDLE:
6460986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
6470986ab12SMaksim Yevmenkin 			if (values[n].vlen == 5) {
6480986ab12SMaksim Yevmenkin 				SDP_GET8(type, values[n].value);
6490986ab12SMaksim Yevmenkin 				if (type == SDP_DATA_UINT32) {
6500986ab12SMaksim Yevmenkin 					SDP_GET32(value, values[n].value);
6510986ab12SMaksim Yevmenkin 					fprintf(stdout, "Record Handle: " \
6520986ab12SMaksim Yevmenkin 							"%#8.8x\n", value);
6530986ab12SMaksim Yevmenkin 				} else
6540986ab12SMaksim Yevmenkin 					fprintf(stderr, "Invalid type=%#x " \
6550986ab12SMaksim Yevmenkin 							"Record Handle " \
6560986ab12SMaksim Yevmenkin 							"attribute!\n", type);
6570986ab12SMaksim Yevmenkin 			} else
6580986ab12SMaksim Yevmenkin 				fprintf(stderr, "Invalid size=%d for Record " \
6590986ab12SMaksim Yevmenkin 						"Handle attribute\n",
6600986ab12SMaksim Yevmenkin 						values[n].vlen);
6610986ab12SMaksim Yevmenkin 			break;
6620986ab12SMaksim Yevmenkin 
6630986ab12SMaksim Yevmenkin 		case SDP_ATTR_SERVICE_CLASS_ID_LIST:
6640986ab12SMaksim Yevmenkin 			fprintf(stdout, "Service Class ID List:\n");
6650986ab12SMaksim Yevmenkin 			print_service_class_id_list(values[n].value,
6660986ab12SMaksim Yevmenkin 					values[n].value + values[n].vlen);
6670986ab12SMaksim Yevmenkin 			break;
6680986ab12SMaksim Yevmenkin 
6690986ab12SMaksim Yevmenkin 		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
6700986ab12SMaksim Yevmenkin 			fprintf(stdout, "Protocol Descriptor List:\n");
6710986ab12SMaksim Yevmenkin 			print_protocol_descriptor_list(values[n].value,
6720986ab12SMaksim Yevmenkin 					values[n].value + values[n].vlen);
6730986ab12SMaksim Yevmenkin 			break;
6740986ab12SMaksim Yevmenkin 
6750986ab12SMaksim Yevmenkin 		case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
6760986ab12SMaksim Yevmenkin 			fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
6770986ab12SMaksim Yevmenkin 			print_bluetooth_profile_descriptor_list(values[n].value,
6780986ab12SMaksim Yevmenkin 					values[n].value + values[n].vlen);
6790986ab12SMaksim Yevmenkin 			break;
6800986ab12SMaksim Yevmenkin 
6810986ab12SMaksim Yevmenkin 		default:
6820986ab12SMaksim Yevmenkin 			fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
6830986ab12SMaksim Yevmenkin 					values[n].attr);
6840986ab12SMaksim Yevmenkin 			break;
6850986ab12SMaksim Yevmenkin 		}
6860986ab12SMaksim Yevmenkin 	}
6870986ab12SMaksim Yevmenkin 
6880986ab12SMaksim Yevmenkin 	return (OK);
6890986ab12SMaksim Yevmenkin } /* do_sdp_search */
6900986ab12SMaksim Yevmenkin 
6910986ab12SMaksim Yevmenkin /* Perform SDP browse command */
6920986ab12SMaksim Yevmenkin static int
6930986ab12SMaksim Yevmenkin do_sdp_browse(void *xs, int argc, char **argv)
6940986ab12SMaksim Yevmenkin {
6950986ab12SMaksim Yevmenkin #undef	_STR
6960986ab12SMaksim Yevmenkin #undef	STR
6970986ab12SMaksim Yevmenkin #define	_STR(x)	#x
6980986ab12SMaksim Yevmenkin #define	STR(x)	_STR(x)
6990986ab12SMaksim Yevmenkin 
7000986ab12SMaksim Yevmenkin 	static char const * const	av[] = {
7010986ab12SMaksim Yevmenkin 		STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
7020986ab12SMaksim Yevmenkin 		NULL
7030986ab12SMaksim Yevmenkin 	};
7040986ab12SMaksim Yevmenkin 
7050986ab12SMaksim Yevmenkin 	switch (argc) {
7060986ab12SMaksim Yevmenkin 	case 0:
7070986ab12SMaksim Yevmenkin 		argc = 1;
7080986ab12SMaksim Yevmenkin 		argv = (char **) av;
7090986ab12SMaksim Yevmenkin 		/* FALL THROUGH */
7100986ab12SMaksim Yevmenkin 	case 1:
7110986ab12SMaksim Yevmenkin 		return (do_sdp_search(xs, argc, argv));
7120986ab12SMaksim Yevmenkin 	}
7130986ab12SMaksim Yevmenkin 
7140986ab12SMaksim Yevmenkin 	return (USAGE);
7150986ab12SMaksim Yevmenkin } /* do_sdp_browse */
7160986ab12SMaksim Yevmenkin 
7170986ab12SMaksim Yevmenkin /* List of SDP commands */
7180986ab12SMaksim Yevmenkin struct sdp_command	sdp_commands[] = {
7190986ab12SMaksim Yevmenkin {
7200986ab12SMaksim Yevmenkin "Browse [<Group>]",
7210986ab12SMaksim Yevmenkin "Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
7220986ab12SMaksim Yevmenkin "to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
7230986ab12SMaksim Yevmenkin "\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
7240986ab12SMaksim Yevmenkin do_sdp_browse
7250986ab12SMaksim Yevmenkin },
7260986ab12SMaksim Yevmenkin {
7270986ab12SMaksim Yevmenkin "Search <Service>",
7280986ab12SMaksim Yevmenkin "Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
7290986ab12SMaksim Yevmenkin "service to search for. For some services it is possible to use service name\n"\
7300986ab12SMaksim Yevmenkin "instead of service UUID\n\n" \
7310986ab12SMaksim Yevmenkin "\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
7320986ab12SMaksim Yevmenkin "\tKnown service names\n" \
7330986ab12SMaksim Yevmenkin "\t===================\n" \
7340986ab12SMaksim Yevmenkin "\tCIP   - Common ISDN Access\n" \
7350986ab12SMaksim Yevmenkin "\tCTP   - Cordless Telephony\n" \
7360986ab12SMaksim Yevmenkin "\tDUN   - DialUp Networking\n" \
7370986ab12SMaksim Yevmenkin "\tFAX   - Fax\n" \
7380986ab12SMaksim Yevmenkin "\tFTRN  - OBEX File Transfer\n" \
7390986ab12SMaksim Yevmenkin "\tGN    - GN\n" \
7400986ab12SMaksim Yevmenkin "\tHID   - Human Interface Device\n" \
7410986ab12SMaksim Yevmenkin "\tHSET  - Headset\n" \
7420986ab12SMaksim Yevmenkin "\tLAN   - LAN Access Using PPP\n" \
7430986ab12SMaksim Yevmenkin "\tNAP   - Network Access Point\n" \
7440986ab12SMaksim Yevmenkin "\tOPUSH - OBEX Object Push\n" \
7450986ab12SMaksim Yevmenkin "\tSP    - Serial Port\n",
7460986ab12SMaksim Yevmenkin do_sdp_search
7470986ab12SMaksim Yevmenkin },
7480986ab12SMaksim Yevmenkin { NULL, NULL, NULL }
7490986ab12SMaksim Yevmenkin };
7500986ab12SMaksim Yevmenkin 
751