xref: /netbsd-src/usr.bin/sdpquery/command.c (revision 57a185009a99c0e9773538928d7a228ffa2cb424)
1 /*	$NetBSD: command.c,v 1.6 2023/12/17 14:38:49 andvar Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Iain Hibbert.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: command.c,v 1.6 2023/12/17 14:38:49 andvar Exp $");
34 
35 #include <bluetooth.h>
36 #include <err.h>
37 #include <sdp.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include "sdpquery.h"
42 
43 static sdp_session_t open_session(void);
44 static void build_ssp(sdp_data_t *, int, const char **);
45 
46 static struct alias {
47 	uint16_t	uuid;
48 	const char *	name;
49 	const char *	desc;
50 } aliases[] = {
51 	{ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION,
52 	  "A2DP",	"Advanced Audio Distribution Profile"		},
53 	{ SDP_UUID_PROTOCOL_BNEP,
54 	  "BNEP",	"Bluetooth Network Encapsulation Protocol"	},
55 	{ SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS,
56 	  "CIP",	"Common ISDN Access Service"			},
57 	{ SDP_SERVICE_CLASS_CORDLESS_TELEPHONY,
58 	  "CTP",	"Cordless Telephony Service"			},
59 	{ SDP_SERVICE_CLASS_DIALUP_NETWORKING,
60 	  "DUN",	"Dial Up Networking Service"			},
61 	{ SDP_SERVICE_CLASS_FAX,
62 	  "FAX",	"Fax Service"					},
63 	{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
64 	  "FTRN",	"File Transfer Service"				},
65 	{ SDP_SERVICE_CLASS_GN,
66 	  "GN",		"Group ad-hoc Network Service"			},
67 	{ SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
68 	  "HID",	"Human Interface Device Service"		},
69 	{ SDP_SERVICE_CLASS_HANDSFREE,
70 	  "HF",		"Handsfree Service"				},
71 	{ SDP_SERVICE_CLASS_HEADSET,
72 	  "HSET",	"Headset Service"				},
73 	{ SDP_UUID_PROTOCOL_L2CAP,
74 	  "L2CAP",	"Logical Link Control and Adaptation Protocol"	},
75 	{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
76 	  "LAN",	"Lan access using PPP Service"			},
77 	{ SDP_SERVICE_CLASS_NAP,
78 	  "NAP",	"Network Access Point Service"			},
79 	{ SDP_UUID_PROTOCOL_OBEX,
80 	  "OBEX",	"Object Exchange Protocol"			},
81 	{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
82 	  "OPUSH",	"Object Push Service"				},
83 	{ SDP_SERVICE_CLASS_PANU,
84 	  "PANU",	"Personal Area Networking User Service"		},
85 	{ SDP_SERVICE_CLASS_PNP_INFORMATION,
86 	  "PNP",	"PNP Information Service"			},
87 	{ SDP_UUID_PROTOCOL_RFCOMM,
88 	  "RFCOMM",	"RFCOMM Protocol"				},
89 	{ SDP_UUID_PROTOCOL_SDP,
90 	  "SDP",	"Service Discovery Protocol"			},
91 	{ SDP_SERVICE_CLASS_SERIAL_PORT,
92 	  "SP",		"Serial Port Service"				},
93 	{ SDP_SERVICE_CLASS_IR_MC_SYNC,
94 	  "SYNC",	"IrMC Sync Client Service"			},
95 };
96 
97 int
do_sdp_browse(int argc,const char ** argv)98 do_sdp_browse(int argc, const char **argv)
99 {
100 	const char *av = ___STRING(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
101 
102 	if (argc > 1)
103 		errx(EXIT_FAILURE, "Too many arguments");
104 
105 	if (argc == 0) {
106 		argc = 1;
107 		argv = &av;
108 	}
109 
110 	return do_sdp_search(argc, argv);
111 }
112 
113 int
do_sdp_record(int argc,const char ** argv)114 do_sdp_record(int argc, const char **argv)
115 {
116 	sdp_session_t	ss;
117 	sdp_data_t	rsp;
118 	char *		ep;
119 	unsigned long	handle;
120 	bool		rv;
121 
122 	if (argc == 0)
123 		errx(EXIT_FAILURE, "Record handle required");
124 
125 	ss = open_session();
126 
127 	for (; argc-- > 0; argv++) {
128 		handle = strtoul(*argv, &ep, 0);
129 		if (*argv[0] == '\0' || *ep != '\0' || handle > UINT32_MAX)
130 			errx(EXIT_FAILURE, "Invalid handle: %s", *argv);
131 
132 		rv = sdp_service_attribute(ss, (uint32_t)handle, NULL, &rsp);
133 		if (!rv)
134 			warn("%s", *argv);
135 		else
136 			print_record(&rsp);
137 
138 		if (argc > 0)
139 			printf("\n\n");
140 	}
141 
142 	sdp_close(ss);
143 	return EXIT_SUCCESS;
144 }
145 
146 int
do_sdp_search(int argc,const char ** argv)147 do_sdp_search(int argc, const char **argv)
148 {
149 	sdp_session_t	ss;
150 	sdp_data_t	ssp, rec, rsp;
151 	bool		rv;
152 
153 	if (argc < 1)
154 		errx(EXIT_FAILURE, "UUID required");
155 
156 	if (argc > 12)
157 		errx(EXIT_FAILURE, "Too many UUIDs");
158 
159 	build_ssp(&ssp, argc, argv);
160 
161 	ss = open_session();
162 
163 	rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp);
164 	if (!rv)
165 		err(EXIT_FAILURE, "sdp_service_search_attribute");
166 
167 	while (sdp_get_seq(&rsp, &rec)) {
168 		if (!rv)
169 			printf("\n\n");
170 		else
171 			rv = false;
172 
173 		print_record(&rec);
174 	}
175 
176 	if (rsp.next != rsp.end) {
177 		printf("\n\nAdditional Data:\n");
178 		sdp_data_print(&rsp, 4);
179 	}
180 
181 	sdp_close(ss);
182 
183 	return EXIT_SUCCESS;
184 }
185 
186 static sdp_session_t
open_session(void)187 open_session(void)
188 {
189 	sdp_session_t ss;
190 
191 	if (bdaddr_any(&remote_addr))
192 		ss = sdp_open_local(control_socket);
193 	else
194 		ss = sdp_open(&local_addr, &remote_addr);
195 
196 	if (ss == NULL)
197 		err(EXIT_FAILURE, "sdp_open");
198 
199 	return ss;
200 }
201 
202 /*
203  * build ServiceSearchPattern from arglist
204  */
205 static void
build_ssp(sdp_data_t * ssp,int argc,const char ** argv)206 build_ssp(sdp_data_t *ssp, int argc, const char **argv)
207 {
208 	static uint8_t	data[12 * sizeof(uuid_t)];
209 	char *		ep;
210 	uintmax_t	umax;
211 	uuid_t		uuid;
212 	uint32_t	status;
213 	int		i;
214 
215 	ssp->next = data;
216 	ssp->end = data + sizeof(data);
217 
218 	for (; argc-- > 0; argv++) {
219 		uuid_from_string(*argv, &uuid, &status);
220 		if (status != uuid_s_ok) {
221 			umax = strtoumax(*argv, &ep, 0);
222 			if (*argv[0] == '\0' || *ep != '\0') {
223 				for (i = 0;; i++) {
224 					if (i == __arraycount(aliases))
225 						errx(EXIT_FAILURE,
226 						    "%s: Bad UUID", *argv);
227 
228 					if (strcasecmp(aliases[i].name,
229 					    *argv) == 0)
230 						break;
231 				}
232 
233 				umax = aliases[i].uuid;
234 			} else if (umax > UINT32_MAX)
235 				errx(EXIT_FAILURE, "%s: Bad UUID", *argv);
236 
237 			uuid = BLUETOOTH_BASE_UUID;
238 			uuid.time_low = (uint32_t)umax;
239 		}
240 
241 		sdp_put_uuid(ssp, &uuid);
242 	}
243 
244 	ssp->end = ssp->next;
245 	ssp->next = data;
246 }
247