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