xref: /netbsd-src/usr.bin/sdpquery/command.c (revision 57a185009a99c0e9773538928d7a228ffa2cb424)
1*57a18500Sandvar /*	$NetBSD: command.c,v 1.6 2023/12/17 14:38:49 andvar Exp $	*/
2384153c1Splunky 
3384153c1Splunky /*-
4384153c1Splunky  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5384153c1Splunky  * All rights reserved.
6384153c1Splunky  *
7384153c1Splunky  * This code is derived from software contributed to The NetBSD Foundation
8384153c1Splunky  * by Iain Hibbert.
9384153c1Splunky  *
10384153c1Splunky  * Redistribution and use in source and binary forms, with or without
11384153c1Splunky  * modification, are permitted provided that the following conditions
12384153c1Splunky  * are met:
13384153c1Splunky  * 1. Redistributions of source code must retain the above copyright
14384153c1Splunky  *    notice, this list of conditions and the following disclaimer.
15384153c1Splunky  * 2. Redistributions in binary form must reproduce the above copyright
16384153c1Splunky  *    notice, this list of conditions and the following disclaimer in the
17384153c1Splunky  *    documentation and/or other materials provided with the distribution.
18384153c1Splunky  *
19384153c1Splunky  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20384153c1Splunky  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21384153c1Splunky  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22384153c1Splunky  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23384153c1Splunky  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24384153c1Splunky  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25384153c1Splunky  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26384153c1Splunky  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27384153c1Splunky  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28384153c1Splunky  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29384153c1Splunky  * POSSIBILITY OF SUCH DAMAGE.
30384153c1Splunky  */
31384153c1Splunky 
32384153c1Splunky #include <sys/cdefs.h>
33*57a18500Sandvar __RCSID("$NetBSD: command.c,v 1.6 2023/12/17 14:38:49 andvar Exp $");
34384153c1Splunky 
35384153c1Splunky #include <bluetooth.h>
36384153c1Splunky #include <err.h>
37384153c1Splunky #include <sdp.h>
38384153c1Splunky #include <stdlib.h>
39384153c1Splunky #include <string.h>
40384153c1Splunky 
41384153c1Splunky #include "sdpquery.h"
42384153c1Splunky 
43384153c1Splunky static sdp_session_t open_session(void);
44384153c1Splunky static void build_ssp(sdp_data_t *, int, const char **);
45384153c1Splunky 
46384153c1Splunky static struct alias {
47384153c1Splunky 	uint16_t	uuid;
48384153c1Splunky 	const char *	name;
49384153c1Splunky 	const char *	desc;
50384153c1Splunky } aliases[] = {
51384153c1Splunky 	{ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION,
52384153c1Splunky 	  "A2DP",	"Advanced Audio Distribution Profile"		},
53384153c1Splunky 	{ SDP_UUID_PROTOCOL_BNEP,
54384153c1Splunky 	  "BNEP",	"Bluetooth Network Encapsulation Protocol"	},
55384153c1Splunky 	{ SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS,
56384153c1Splunky 	  "CIP",	"Common ISDN Access Service"			},
57384153c1Splunky 	{ SDP_SERVICE_CLASS_CORDLESS_TELEPHONY,
58384153c1Splunky 	  "CTP",	"Cordless Telephony Service"			},
59384153c1Splunky 	{ SDP_SERVICE_CLASS_DIALUP_NETWORKING,
60384153c1Splunky 	  "DUN",	"Dial Up Networking Service"			},
61384153c1Splunky 	{ SDP_SERVICE_CLASS_FAX,
62384153c1Splunky 	  "FAX",	"Fax Service"					},
63384153c1Splunky 	{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
64384153c1Splunky 	  "FTRN",	"File Transfer Service"				},
65384153c1Splunky 	{ SDP_SERVICE_CLASS_GN,
66384153c1Splunky 	  "GN",		"Group ad-hoc Network Service"			},
67384153c1Splunky 	{ SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
68384153c1Splunky 	  "HID",	"Human Interface Device Service"		},
69384153c1Splunky 	{ SDP_SERVICE_CLASS_HANDSFREE,
70384153c1Splunky 	  "HF",		"Handsfree Service"				},
71384153c1Splunky 	{ SDP_SERVICE_CLASS_HEADSET,
72384153c1Splunky 	  "HSET",	"Headset Service"				},
73384153c1Splunky 	{ SDP_UUID_PROTOCOL_L2CAP,
74*57a18500Sandvar 	  "L2CAP",	"Logical Link Control and Adaptation Protocol"	},
75384153c1Splunky 	{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
76384153c1Splunky 	  "LAN",	"Lan access using PPP Service"			},
77384153c1Splunky 	{ SDP_SERVICE_CLASS_NAP,
78384153c1Splunky 	  "NAP",	"Network Access Point Service"			},
79384153c1Splunky 	{ SDP_UUID_PROTOCOL_OBEX,
80384153c1Splunky 	  "OBEX",	"Object Exchange Protocol"			},
81384153c1Splunky 	{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
82384153c1Splunky 	  "OPUSH",	"Object Push Service"				},
83384153c1Splunky 	{ SDP_SERVICE_CLASS_PANU,
84384153c1Splunky 	  "PANU",	"Personal Area Networking User Service"		},
85e16149e2Splunky 	{ SDP_SERVICE_CLASS_PNP_INFORMATION,
86e16149e2Splunky 	  "PNP",	"PNP Information Service"			},
87384153c1Splunky 	{ SDP_UUID_PROTOCOL_RFCOMM,
88384153c1Splunky 	  "RFCOMM",	"RFCOMM Protocol"				},
89384153c1Splunky 	{ SDP_UUID_PROTOCOL_SDP,
90384153c1Splunky 	  "SDP",	"Service Discovery Protocol"			},
91384153c1Splunky 	{ SDP_SERVICE_CLASS_SERIAL_PORT,
92384153c1Splunky 	  "SP",		"Serial Port Service"				},
93384153c1Splunky 	{ SDP_SERVICE_CLASS_IR_MC_SYNC,
94384153c1Splunky 	  "SYNC",	"IrMC Sync Client Service"			},
95384153c1Splunky };
96384153c1Splunky 
97384153c1Splunky int
do_sdp_browse(int argc,const char ** argv)98384153c1Splunky do_sdp_browse(int argc, const char **argv)
99384153c1Splunky {
1007349c9ffSplunky 	const char *av = ___STRING(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
101384153c1Splunky 
102384153c1Splunky 	if (argc > 1)
103384153c1Splunky 		errx(EXIT_FAILURE, "Too many arguments");
104384153c1Splunky 
105384153c1Splunky 	if (argc == 0) {
106384153c1Splunky 		argc = 1;
107384153c1Splunky 		argv = &av;
108384153c1Splunky 	}
109384153c1Splunky 
110384153c1Splunky 	return do_sdp_search(argc, argv);
111384153c1Splunky }
112384153c1Splunky 
113384153c1Splunky int
do_sdp_record(int argc,const char ** argv)114384153c1Splunky do_sdp_record(int argc, const char **argv)
115384153c1Splunky {
116384153c1Splunky 	sdp_session_t	ss;
117384153c1Splunky 	sdp_data_t	rsp;
118384153c1Splunky 	char *		ep;
119384153c1Splunky 	unsigned long	handle;
120384153c1Splunky 	bool		rv;
121384153c1Splunky 
122384153c1Splunky 	if (argc == 0)
123384153c1Splunky 		errx(EXIT_FAILURE, "Record handle required");
124384153c1Splunky 
125384153c1Splunky 	ss = open_session();
126384153c1Splunky 
127384153c1Splunky 	for (; argc-- > 0; argv++) {
128384153c1Splunky 		handle = strtoul(*argv, &ep, 0);
129384153c1Splunky 		if (*argv[0] == '\0' || *ep != '\0' || handle > UINT32_MAX)
130ff532697Schristos 			errx(EXIT_FAILURE, "Invalid handle: %s", *argv);
131384153c1Splunky 
1320fbc382dSplunky 		rv = sdp_service_attribute(ss, (uint32_t)handle, NULL, &rsp);
133384153c1Splunky 		if (!rv)
134384153c1Splunky 			warn("%s", *argv);
135384153c1Splunky 		else
136384153c1Splunky 			print_record(&rsp);
137384153c1Splunky 
138384153c1Splunky 		if (argc > 0)
139384153c1Splunky 			printf("\n\n");
140384153c1Splunky 	}
141384153c1Splunky 
142384153c1Splunky 	sdp_close(ss);
143384153c1Splunky 	return EXIT_SUCCESS;
144384153c1Splunky }
145384153c1Splunky 
146384153c1Splunky int
do_sdp_search(int argc,const char ** argv)147384153c1Splunky do_sdp_search(int argc, const char **argv)
148384153c1Splunky {
149384153c1Splunky 	sdp_session_t	ss;
150384153c1Splunky 	sdp_data_t	ssp, rec, rsp;
151384153c1Splunky 	bool		rv;
152384153c1Splunky 
153384153c1Splunky 	if (argc < 1)
154384153c1Splunky 		errx(EXIT_FAILURE, "UUID required");
155384153c1Splunky 
156384153c1Splunky 	if (argc > 12)
157384153c1Splunky 		errx(EXIT_FAILURE, "Too many UUIDs");
158384153c1Splunky 
159384153c1Splunky 	build_ssp(&ssp, argc, argv);
160384153c1Splunky 
161384153c1Splunky 	ss = open_session();
162384153c1Splunky 
163384153c1Splunky 	rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp);
164384153c1Splunky 	if (!rv)
165384153c1Splunky 		err(EXIT_FAILURE, "sdp_service_search_attribute");
166384153c1Splunky 
167384153c1Splunky 	while (sdp_get_seq(&rsp, &rec)) {
168384153c1Splunky 		if (!rv)
169384153c1Splunky 			printf("\n\n");
170384153c1Splunky 		else
171384153c1Splunky 			rv = false;
172384153c1Splunky 
173384153c1Splunky 		print_record(&rec);
174384153c1Splunky 	}
175384153c1Splunky 
176384153c1Splunky 	if (rsp.next != rsp.end) {
177384153c1Splunky 		printf("\n\nAdditional Data:\n");
178384153c1Splunky 		sdp_data_print(&rsp, 4);
179384153c1Splunky 	}
180384153c1Splunky 
181384153c1Splunky 	sdp_close(ss);
182384153c1Splunky 
183384153c1Splunky 	return EXIT_SUCCESS;
184384153c1Splunky }
185384153c1Splunky 
186384153c1Splunky static sdp_session_t
open_session(void)187384153c1Splunky open_session(void)
188384153c1Splunky {
189384153c1Splunky 	sdp_session_t ss;
190384153c1Splunky 
191384153c1Splunky 	if (bdaddr_any(&remote_addr))
192384153c1Splunky 		ss = sdp_open_local(control_socket);
193384153c1Splunky 	else
194384153c1Splunky 		ss = sdp_open(&local_addr, &remote_addr);
195384153c1Splunky 
196384153c1Splunky 	if (ss == NULL)
197384153c1Splunky 		err(EXIT_FAILURE, "sdp_open");
198384153c1Splunky 
199384153c1Splunky 	return ss;
200384153c1Splunky }
201384153c1Splunky 
202384153c1Splunky /*
203384153c1Splunky  * build ServiceSearchPattern from arglist
204384153c1Splunky  */
205384153c1Splunky static void
build_ssp(sdp_data_t * ssp,int argc,const char ** argv)206384153c1Splunky build_ssp(sdp_data_t *ssp, int argc, const char **argv)
207384153c1Splunky {
2080fbc382dSplunky 	static uint8_t	data[12 * sizeof(uuid_t)];
209384153c1Splunky 	char *		ep;
2100fbc382dSplunky 	uintmax_t	umax;
2110fbc382dSplunky 	uuid_t		uuid;
2120fbc382dSplunky 	uint32_t	status;
213384153c1Splunky 	int		i;
214384153c1Splunky 
215384153c1Splunky 	ssp->next = data;
216384153c1Splunky 	ssp->end = data + sizeof(data);
217384153c1Splunky 
218384153c1Splunky 	for (; argc-- > 0; argv++) {
2190fbc382dSplunky 		uuid_from_string(*argv, &uuid, &status);
2200fbc382dSplunky 		if (status != uuid_s_ok) {
2210fbc382dSplunky 			umax = strtoumax(*argv, &ep, 0);
222384153c1Splunky 			if (*argv[0] == '\0' || *ep != '\0') {
223384153c1Splunky 				for (i = 0;; i++) {
224384153c1Splunky 					if (i == __arraycount(aliases))
225384153c1Splunky 						errx(EXIT_FAILURE,
2260fbc382dSplunky 						    "%s: Bad UUID", *argv);
227384153c1Splunky 
2280fbc382dSplunky 					if (strcasecmp(aliases[i].name,
2290fbc382dSplunky 					    *argv) == 0)
230384153c1Splunky 						break;
231384153c1Splunky 				}
232384153c1Splunky 
2330fbc382dSplunky 				umax = aliases[i].uuid;
2340fbc382dSplunky 			} else if (umax > UINT32_MAX)
2350fbc382dSplunky 				errx(EXIT_FAILURE, "%s: Bad UUID", *argv);
2360fbc382dSplunky 
2370fbc382dSplunky 			uuid = BLUETOOTH_BASE_UUID;
2380fbc382dSplunky 			uuid.time_low = (uint32_t)umax;
239384153c1Splunky 		}
240384153c1Splunky 
2410fbc382dSplunky 		sdp_put_uuid(ssp, &uuid);
242384153c1Splunky 	}
243384153c1Splunky 
244384153c1Splunky 	ssp->end = ssp->next;
245384153c1Splunky 	ssp->next = data;
246384153c1Splunky }
247