btpand.c revision 1.8 1 1.8 andvar /* $NetBSD: btpand.c,v 1.8 2022/05/18 13:56:32 andvar Exp $ */
2 1.1 plunky
3 1.1 plunky /*-
4 1.4 plunky * Copyright (c) 2008-2009 Iain Hibbert
5 1.1 plunky * All rights reserved.
6 1.1 plunky *
7 1.1 plunky * Redistribution and use in source and binary forms, with or without
8 1.1 plunky * modification, are permitted provided that the following conditions
9 1.1 plunky * are met:
10 1.1 plunky * 1. Redistributions of source code must retain the above copyright
11 1.1 plunky * notice, this list of conditions and the following disclaimer.
12 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 plunky * notice, this list of conditions and the following disclaimer in the
14 1.1 plunky * documentation and/or other materials provided with the distribution.
15 1.1 plunky *
16 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 plunky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 plunky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 plunky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 plunky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 1.1 plunky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 1.1 plunky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 1.1 plunky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 1.1 plunky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 1.1 plunky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 1.1 plunky */
27 1.1 plunky
28 1.1 plunky #include <sys/cdefs.h>
29 1.4 plunky __COPYRIGHT("@(#) Copyright (c) 2008-2009 Iain Hibbert. All rights reserved.");
30 1.8 andvar __RCSID("$NetBSD: btpand.c,v 1.8 2022/05/18 13:56:32 andvar Exp $");
31 1.1 plunky
32 1.1 plunky #include <sys/wait.h>
33 1.1 plunky
34 1.1 plunky #include <bluetooth.h>
35 1.1 plunky #include <err.h>
36 1.1 plunky #include <fcntl.h>
37 1.1 plunky #include <paths.h>
38 1.1 plunky #include <sdp.h>
39 1.1 plunky #include <stdio.h>
40 1.1 plunky #include <signal.h>
41 1.1 plunky #include <stdlib.h>
42 1.1 plunky #include <string.h>
43 1.1 plunky #include <unistd.h>
44 1.1 plunky
45 1.1 plunky #include "btpand.h"
46 1.1 plunky
47 1.1 plunky /* global variables */
48 1.1 plunky const char * control_path; /* -c <path> */
49 1.1 plunky const char * interface_name; /* -i <ifname> */
50 1.4 plunky const char * service_type; /* -s <service> */
51 1.1 plunky uint16_t service_class;
52 1.4 plunky const char * service_name;
53 1.4 plunky const char * service_desc;
54 1.1 plunky
55 1.1 plunky bdaddr_t local_bdaddr; /* -d <addr> */
56 1.1 plunky bdaddr_t remote_bdaddr; /* -a <addr> */
57 1.1 plunky uint16_t l2cap_psm; /* -p <psm> */
58 1.1 plunky int l2cap_mode; /* -m <mode> */
59 1.1 plunky int server_limit; /* -n <limit> */
60 1.1 plunky
61 1.1 plunky static const struct {
62 1.4 plunky const char * type;
63 1.4 plunky uint16_t class;
64 1.1 plunky const char * name;
65 1.1 plunky const char * desc;
66 1.1 plunky } services[] = {
67 1.4 plunky { "PANU", SDP_SERVICE_CLASS_PANU,
68 1.4 plunky "Personal Ad-hoc User Service",
69 1.4 plunky "Personal Ad-hoc User Service"
70 1.4 plunky },
71 1.4 plunky { "NAP", SDP_SERVICE_CLASS_NAP,
72 1.8 andvar "Network Access Point",
73 1.4 plunky "Personal Ad-hoc Network Service"
74 1.4 plunky },
75 1.4 plunky { "GN", SDP_SERVICE_CLASS_GN,
76 1.4 plunky "Group Ad-hoc Network",
77 1.4 plunky "Personal Group Ad-hoc Network Service"
78 1.4 plunky },
79 1.1 plunky };
80 1.1 plunky
81 1.6 joerg __dead static void main_exit(int);
82 1.1 plunky static void main_detach(void);
83 1.6 joerg __dead static void usage(void);
84 1.1 plunky
85 1.1 plunky int
86 1.1 plunky main(int argc, char *argv[])
87 1.1 plunky {
88 1.1 plunky unsigned long ul;
89 1.1 plunky char * ep;
90 1.1 plunky int ch, status;
91 1.1 plunky
92 1.1 plunky while ((ch = getopt(argc, argv, "a:c:d:i:l:m:p:S:s:")) != -1) {
93 1.1 plunky switch (ch) {
94 1.1 plunky case 'a': /* remote address */
95 1.1 plunky if (!bt_aton(optarg, &remote_bdaddr)) {
96 1.1 plunky struct hostent *he;
97 1.1 plunky
98 1.1 plunky if ((he = bt_gethostbyname(optarg)) == NULL)
99 1.1 plunky errx(EXIT_FAILURE, "%s: %s",
100 1.1 plunky optarg, hstrerror(h_errno));
101 1.1 plunky
102 1.1 plunky bdaddr_copy(&remote_bdaddr, (bdaddr_t *)he->h_addr);
103 1.1 plunky }
104 1.1 plunky
105 1.1 plunky break;
106 1.1 plunky
107 1.1 plunky case 'c': /* control socket path */
108 1.1 plunky control_path = optarg;
109 1.1 plunky break;
110 1.1 plunky
111 1.1 plunky case 'd': /* local address */
112 1.1 plunky if (!bt_devaddr(optarg, &local_bdaddr))
113 1.1 plunky err(EXIT_FAILURE, "%s", optarg);
114 1.1 plunky
115 1.1 plunky break;
116 1.1 plunky
117 1.1 plunky case 'i': /* tap interface name */
118 1.1 plunky if (strchr(optarg, '/') == NULL) {
119 1.1 plunky asprintf(&ep, "/dev/%s", optarg);
120 1.1 plunky interface_name = ep;
121 1.1 plunky } else {
122 1.1 plunky interface_name = optarg;
123 1.1 plunky }
124 1.1 plunky
125 1.1 plunky break;
126 1.1 plunky
127 1.1 plunky case 'l': /* limit server sessions */
128 1.1 plunky ul = strtoul(optarg, &ep, 10);
129 1.1 plunky if (*optarg == '\0' || *ep != '\0' || ul == 0)
130 1.1 plunky errx(EXIT_FAILURE, "%s: invalid session limit", optarg);
131 1.1 plunky
132 1.1 plunky server_limit = ul;
133 1.1 plunky break;
134 1.1 plunky
135 1.1 plunky case 'm': /* link mode */
136 1.1 plunky if (strcasecmp(optarg, "auth") == 0)
137 1.1 plunky l2cap_mode = L2CAP_LM_AUTH;
138 1.1 plunky else if (strcasecmp(optarg, "encrypt") == 0)
139 1.1 plunky l2cap_mode = L2CAP_LM_ENCRYPT;
140 1.1 plunky else if (strcasecmp(optarg, "secure") == 0)
141 1.1 plunky l2cap_mode = L2CAP_LM_SECURE;
142 1.1 plunky else if (strcasecmp(optarg, "none"))
143 1.1 plunky errx(EXIT_FAILURE, "%s: unknown mode", optarg);
144 1.1 plunky
145 1.1 plunky break;
146 1.1 plunky
147 1.1 plunky case 'p': /* protocol/service multiplexer */
148 1.1 plunky ul = strtoul(optarg, &ep, 0);
149 1.1 plunky if (*optarg == '\0' || *ep != '\0'
150 1.1 plunky || ul > 0xffff || L2CAP_PSM_INVALID(ul))
151 1.1 plunky errx(EXIT_FAILURE, "%s: invalid PSM", optarg);
152 1.1 plunky
153 1.4 plunky l2cap_psm = (uint16_t)ul;
154 1.1 plunky break;
155 1.1 plunky
156 1.1 plunky case 's': /* service */
157 1.1 plunky case 'S': /* service (no SDP) */
158 1.4 plunky for (ul = 0; strcasecmp(optarg, services[ul].type); ul++) {
159 1.1 plunky if (ul == __arraycount(services))
160 1.1 plunky errx(EXIT_FAILURE, "%s: unknown service", optarg);
161 1.1 plunky }
162 1.1 plunky
163 1.4 plunky if (ch == 's') {
164 1.4 plunky service_type = services[ul].type;
165 1.1 plunky service_name = services[ul].name;
166 1.4 plunky service_desc = services[ul].desc;
167 1.4 plunky }
168 1.1 plunky
169 1.1 plunky service_class = services[ul].class;
170 1.1 plunky break;
171 1.1 plunky
172 1.1 plunky default:
173 1.1 plunky usage();
174 1.1 plunky /* NOTREACHED */
175 1.1 plunky }
176 1.1 plunky }
177 1.1 plunky
178 1.1 plunky argc -= optind;
179 1.1 plunky argv += optind;
180 1.1 plunky
181 1.1 plunky /* validate options */
182 1.1 plunky if (bdaddr_any(&local_bdaddr) || service_class == 0)
183 1.1 plunky usage();
184 1.1 plunky
185 1.1 plunky if (!bdaddr_any(&remote_bdaddr) && (server_limit != 0 ||
186 1.4 plunky control_path != 0 || (service_type != NULL && l2cap_psm != 0)))
187 1.1 plunky usage();
188 1.1 plunky
189 1.1 plunky /* default options */
190 1.1 plunky if (interface_name == NULL)
191 1.1 plunky interface_name = "/dev/tap";
192 1.1 plunky
193 1.1 plunky if (l2cap_psm == 0)
194 1.1 plunky l2cap_psm = L2CAP_PSM_BNEP;
195 1.1 plunky
196 1.1 plunky if (bdaddr_any(&remote_bdaddr) && server_limit == 0) {
197 1.1 plunky if (service_class == SDP_SERVICE_CLASS_PANU)
198 1.1 plunky server_limit = 1;
199 1.1 plunky else
200 1.1 plunky server_limit = 7;
201 1.1 plunky }
202 1.1 plunky
203 1.1 plunky #ifdef L2CAP_LM_MASTER
204 1.1 plunky if (server_limit > 1 && service_class != SDP_SERVICE_CLASS_PANU)
205 1.1 plunky l2cap_mode |= L2CAP_LM_MASTER;
206 1.1 plunky #endif
207 1.1 plunky
208 1.1 plunky /*
209 1.1 plunky * fork() now so that the setup can be done in the child process
210 1.1 plunky * (as kqueue is not inherited) but block in the parent until the
211 1.1 plunky * setup is finished so we can return an error if necessary.
212 1.1 plunky */
213 1.1 plunky switch(fork()) {
214 1.1 plunky case -1: /* bad */
215 1.1 plunky err(EXIT_FAILURE, "fork() failed");
216 1.7 christos /*NOTREACHED*/
217 1.1 plunky
218 1.1 plunky case 0: /* child */
219 1.1 plunky openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);
220 1.1 plunky
221 1.1 plunky channel_init();
222 1.3 plunky event_init();
223 1.1 plunky server_init();
224 1.1 plunky client_init();
225 1.1 plunky tap_init();
226 1.1 plunky
227 1.1 plunky main_detach();
228 1.1 plunky
229 1.1 plunky event_dispatch();
230 1.1 plunky break;
231 1.1 plunky
232 1.1 plunky default: /* parent */
233 1.1 plunky signal(SIGUSR1, main_exit);
234 1.1 plunky wait(&status);
235 1.1 plunky
236 1.1 plunky if (WIFEXITED(status))
237 1.1 plunky exit(WEXITSTATUS(status));
238 1.1 plunky
239 1.1 plunky break;
240 1.1 plunky }
241 1.1 plunky
242 1.1 plunky err(EXIT_FAILURE, "exiting");
243 1.1 plunky }
244 1.1 plunky
245 1.1 plunky static void
246 1.1 plunky main_exit(int s)
247 1.1 plunky {
248 1.1 plunky
249 1.1 plunky /* child is all grown up */
250 1.1 plunky _exit(EXIT_SUCCESS);
251 1.1 plunky }
252 1.1 plunky
253 1.1 plunky static void
254 1.1 plunky main_detach(void)
255 1.1 plunky {
256 1.1 plunky int fd;
257 1.1 plunky
258 1.1 plunky if (kill(getppid(), SIGUSR1) == -1)
259 1.1 plunky log_err("Could not signal main process: %m");
260 1.1 plunky
261 1.1 plunky if (setsid() == -1)
262 1.1 plunky log_err("setsid() failed");
263 1.1 plunky
264 1.1 plunky fd = open(_PATH_DEVNULL, O_RDWR, 0);
265 1.1 plunky if (fd == -1) {
266 1.1 plunky log_err("Could not open %s", _PATH_DEVNULL);
267 1.1 plunky } else {
268 1.1 plunky (void)dup2(fd, STDIN_FILENO);
269 1.1 plunky (void)dup2(fd, STDOUT_FILENO);
270 1.1 plunky (void)dup2(fd, STDERR_FILENO);
271 1.1 plunky close(fd);
272 1.1 plunky }
273 1.1 plunky }
274 1.1 plunky
275 1.1 plunky static void
276 1.1 plunky usage(void)
277 1.1 plunky {
278 1.1 plunky const char *p = getprogname();
279 1.4 plunky size_t n = strlen(p);
280 1.1 plunky
281 1.1 plunky fprintf(stderr,
282 1.1 plunky "usage: %s [-i ifname] [-m mode] -a address -d device\n"
283 1.1 plunky " %*s {-s service | -S service [-p psm]}\n"
284 1.1 plunky " %s [-c path] [-i ifname] [-l limit] [-m mode] [-p psm] -d device\n"
285 1.1 plunky " %*s {-s service | -S service}\n"
286 1.1 plunky "\n"
287 1.1 plunky "Where:\n"
288 1.1 plunky "\t-a address remote bluetooth device\n"
289 1.1 plunky "\t-c path SDP server socket\n"
290 1.1 plunky "\t-d device local bluetooth device\n"
291 1.1 plunky "\t-i ifname tap interface\n"
292 1.1 plunky "\t-l limit limit server sessions\n"
293 1.1 plunky "\t-m mode L2CAP link mode\n"
294 1.1 plunky "\t-p psm L2CAP PSM\n"
295 1.1 plunky "\t-S service service name (no SDP)\n"
296 1.1 plunky "\t-s service service name\n"
297 1.1 plunky "\n"
298 1.1 plunky "Known services:\n"
299 1.5 christos "", p, (int)n, "", p, (int)n, "");
300 1.1 plunky
301 1.4 plunky for (n = 0; n < __arraycount(services); n++)
302 1.4 plunky fprintf(stderr, "\t%s\t%s\n", services[n].type, services[n].name);
303 1.1 plunky
304 1.1 plunky exit(EXIT_FAILURE);
305 1.1 plunky }
306