btpand.c revision 1.3 1 1.3 plunky /* $NetBSD: btpand.c,v 1.3 2009/05/12 21:08:30 plunky Exp $ */
2 1.1 plunky
3 1.1 plunky /*-
4 1.1 plunky * Copyright (c) 2008 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.1 plunky __COPYRIGHT("@(#) Copyright (c) 2008 Iain Hibbert. All rights reserved.");
30 1.3 plunky __RCSID("$NetBSD: btpand.c,v 1.3 2009/05/12 21:08:30 plunky 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.1 plunky const char * service_name; /* -s <service> */
51 1.1 plunky uint16_t service_class;
52 1.1 plunky
53 1.1 plunky bdaddr_t local_bdaddr; /* -d <addr> */
54 1.1 plunky bdaddr_t remote_bdaddr; /* -a <addr> */
55 1.1 plunky uint16_t l2cap_psm; /* -p <psm> */
56 1.1 plunky int l2cap_mode; /* -m <mode> */
57 1.1 plunky
58 1.1 plunky int server_limit; /* -n <limit> */
59 1.1 plunky
60 1.1 plunky static const struct {
61 1.1 plunky const char * name;
62 1.1 plunky uint16_t class;
63 1.1 plunky const char * desc;
64 1.1 plunky } services[] = {
65 1.1 plunky { "PANU", SDP_SERVICE_CLASS_PANU, "Personal Area Networking User" },
66 1.1 plunky { "NAP", SDP_SERVICE_CLASS_NAP, "Network Acess Point" },
67 1.1 plunky { "GN", SDP_SERVICE_CLASS_GN, "Group Network" },
68 1.1 plunky };
69 1.1 plunky
70 1.1 plunky static void main_exit(int);
71 1.1 plunky static void main_detach(void);
72 1.1 plunky static void usage(void);
73 1.1 plunky
74 1.1 plunky int
75 1.1 plunky main(int argc, char *argv[])
76 1.1 plunky {
77 1.1 plunky unsigned long ul;
78 1.1 plunky char * ep;
79 1.1 plunky int ch, status;
80 1.1 plunky
81 1.1 plunky while ((ch = getopt(argc, argv, "a:c:d:i:l:m:p:S:s:")) != -1) {
82 1.1 plunky switch (ch) {
83 1.1 plunky case 'a': /* remote address */
84 1.1 plunky if (!bt_aton(optarg, &remote_bdaddr)) {
85 1.1 plunky struct hostent *he;
86 1.1 plunky
87 1.1 plunky if ((he = bt_gethostbyname(optarg)) == NULL)
88 1.1 plunky errx(EXIT_FAILURE, "%s: %s",
89 1.1 plunky optarg, hstrerror(h_errno));
90 1.1 plunky
91 1.1 plunky bdaddr_copy(&remote_bdaddr, (bdaddr_t *)he->h_addr);
92 1.1 plunky }
93 1.1 plunky
94 1.1 plunky break;
95 1.1 plunky
96 1.1 plunky case 'c': /* control socket path */
97 1.1 plunky control_path = optarg;
98 1.1 plunky break;
99 1.1 plunky
100 1.1 plunky case 'd': /* local address */
101 1.1 plunky if (!bt_devaddr(optarg, &local_bdaddr))
102 1.1 plunky err(EXIT_FAILURE, "%s", optarg);
103 1.1 plunky
104 1.1 plunky break;
105 1.1 plunky
106 1.1 plunky case 'i': /* tap interface name */
107 1.1 plunky if (strchr(optarg, '/') == NULL) {
108 1.1 plunky asprintf(&ep, "/dev/%s", optarg);
109 1.1 plunky interface_name = ep;
110 1.1 plunky } else {
111 1.1 plunky interface_name = optarg;
112 1.1 plunky }
113 1.1 plunky
114 1.1 plunky break;
115 1.1 plunky
116 1.1 plunky case 'l': /* limit server sessions */
117 1.1 plunky ul = strtoul(optarg, &ep, 10);
118 1.1 plunky if (*optarg == '\0' || *ep != '\0' || ul == 0)
119 1.1 plunky errx(EXIT_FAILURE, "%s: invalid session limit", optarg);
120 1.1 plunky
121 1.1 plunky server_limit = ul;
122 1.1 plunky break;
123 1.1 plunky
124 1.1 plunky case 'm': /* link mode */
125 1.1 plunky if (strcasecmp(optarg, "auth") == 0)
126 1.1 plunky l2cap_mode = L2CAP_LM_AUTH;
127 1.1 plunky else if (strcasecmp(optarg, "encrypt") == 0)
128 1.1 plunky l2cap_mode = L2CAP_LM_ENCRYPT;
129 1.1 plunky else if (strcasecmp(optarg, "secure") == 0)
130 1.1 plunky l2cap_mode = L2CAP_LM_SECURE;
131 1.1 plunky else if (strcasecmp(optarg, "none"))
132 1.1 plunky errx(EXIT_FAILURE, "%s: unknown mode", optarg);
133 1.1 plunky
134 1.1 plunky break;
135 1.1 plunky
136 1.1 plunky case 'p': /* protocol/service multiplexer */
137 1.1 plunky ul = strtoul(optarg, &ep, 0);
138 1.1 plunky if (*optarg == '\0' || *ep != '\0'
139 1.1 plunky || ul > 0xffff || L2CAP_PSM_INVALID(ul))
140 1.1 plunky errx(EXIT_FAILURE, "%s: invalid PSM", optarg);
141 1.1 plunky
142 1.1 plunky l2cap_psm = ul;
143 1.1 plunky break;
144 1.1 plunky
145 1.1 plunky case 's': /* service */
146 1.1 plunky case 'S': /* service (no SDP) */
147 1.1 plunky for (ul = 0; strcasecmp(optarg, services[ul].name); ul++) {
148 1.1 plunky if (ul == __arraycount(services))
149 1.1 plunky errx(EXIT_FAILURE, "%s: unknown service", optarg);
150 1.1 plunky }
151 1.1 plunky
152 1.1 plunky if (ch == 's')
153 1.1 plunky service_name = services[ul].name;
154 1.1 plunky
155 1.1 plunky service_class = services[ul].class;
156 1.1 plunky break;
157 1.1 plunky
158 1.1 plunky default:
159 1.1 plunky usage();
160 1.1 plunky /* NOTREACHED */
161 1.1 plunky }
162 1.1 plunky }
163 1.1 plunky
164 1.1 plunky argc -= optind;
165 1.1 plunky argv += optind;
166 1.1 plunky
167 1.1 plunky /* validate options */
168 1.1 plunky if (bdaddr_any(&local_bdaddr) || service_class == 0)
169 1.1 plunky usage();
170 1.1 plunky
171 1.1 plunky if (!bdaddr_any(&remote_bdaddr) && (server_limit != 0 ||
172 1.1 plunky control_path != 0 || (service_name != NULL && l2cap_psm != 0)))
173 1.1 plunky usage();
174 1.1 plunky
175 1.1 plunky /* default options */
176 1.1 plunky if (interface_name == NULL)
177 1.1 plunky interface_name = "/dev/tap";
178 1.1 plunky
179 1.1 plunky if (l2cap_psm == 0)
180 1.1 plunky l2cap_psm = L2CAP_PSM_BNEP;
181 1.1 plunky
182 1.1 plunky if (bdaddr_any(&remote_bdaddr) && server_limit == 0) {
183 1.1 plunky if (service_class == SDP_SERVICE_CLASS_PANU)
184 1.1 plunky server_limit = 1;
185 1.1 plunky else
186 1.1 plunky server_limit = 7;
187 1.1 plunky }
188 1.1 plunky
189 1.1 plunky #ifdef L2CAP_LM_MASTER
190 1.1 plunky if (server_limit > 1 && service_class != SDP_SERVICE_CLASS_PANU)
191 1.1 plunky l2cap_mode |= L2CAP_LM_MASTER;
192 1.1 plunky #endif
193 1.1 plunky
194 1.1 plunky /*
195 1.1 plunky * fork() now so that the setup can be done in the child process
196 1.1 plunky * (as kqueue is not inherited) but block in the parent until the
197 1.1 plunky * setup is finished so we can return an error if necessary.
198 1.1 plunky */
199 1.1 plunky switch(fork()) {
200 1.1 plunky case -1: /* bad */
201 1.1 plunky err(EXIT_FAILURE, "fork() failed");
202 1.1 plunky
203 1.1 plunky case 0: /* child */
204 1.1 plunky openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);
205 1.1 plunky
206 1.1 plunky channel_init();
207 1.3 plunky event_init();
208 1.1 plunky server_init();
209 1.1 plunky client_init();
210 1.1 plunky tap_init();
211 1.1 plunky
212 1.1 plunky main_detach();
213 1.1 plunky
214 1.1 plunky event_dispatch();
215 1.1 plunky break;
216 1.1 plunky
217 1.1 plunky default: /* parent */
218 1.1 plunky signal(SIGUSR1, main_exit);
219 1.1 plunky wait(&status);
220 1.1 plunky
221 1.1 plunky if (WIFEXITED(status))
222 1.1 plunky exit(WEXITSTATUS(status));
223 1.1 plunky
224 1.1 plunky break;
225 1.1 plunky }
226 1.1 plunky
227 1.1 plunky err(EXIT_FAILURE, "exiting");
228 1.1 plunky }
229 1.1 plunky
230 1.1 plunky static void
231 1.1 plunky main_exit(int s)
232 1.1 plunky {
233 1.1 plunky
234 1.1 plunky /* child is all grown up */
235 1.1 plunky _exit(EXIT_SUCCESS);
236 1.1 plunky }
237 1.1 plunky
238 1.1 plunky static void
239 1.1 plunky main_detach(void)
240 1.1 plunky {
241 1.1 plunky int fd;
242 1.1 plunky
243 1.1 plunky if (kill(getppid(), SIGUSR1) == -1)
244 1.1 plunky log_err("Could not signal main process: %m");
245 1.1 plunky
246 1.1 plunky if (setsid() == -1)
247 1.1 plunky log_err("setsid() failed");
248 1.1 plunky
249 1.1 plunky fd = open(_PATH_DEVNULL, O_RDWR, 0);
250 1.1 plunky if (fd == -1) {
251 1.1 plunky log_err("Could not open %s", _PATH_DEVNULL);
252 1.1 plunky } else {
253 1.1 plunky (void)dup2(fd, STDIN_FILENO);
254 1.1 plunky (void)dup2(fd, STDOUT_FILENO);
255 1.1 plunky (void)dup2(fd, STDERR_FILENO);
256 1.1 plunky close(fd);
257 1.1 plunky }
258 1.1 plunky }
259 1.1 plunky
260 1.1 plunky static void
261 1.1 plunky usage(void)
262 1.1 plunky {
263 1.1 plunky const char *p = getprogname();
264 1.1 plunky int n = strlen(p);
265 1.1 plunky
266 1.1 plunky fprintf(stderr,
267 1.1 plunky "usage: %s [-i ifname] [-m mode] -a address -d device\n"
268 1.1 plunky " %*s {-s service | -S service [-p psm]}\n"
269 1.1 plunky " %s [-c path] [-i ifname] [-l limit] [-m mode] [-p psm] -d device\n"
270 1.1 plunky " %*s {-s service | -S service}\n"
271 1.1 plunky "\n"
272 1.1 plunky "Where:\n"
273 1.1 plunky "\t-a address remote bluetooth device\n"
274 1.1 plunky "\t-c path SDP server socket\n"
275 1.1 plunky "\t-d device local bluetooth device\n"
276 1.1 plunky "\t-i ifname tap interface\n"
277 1.1 plunky "\t-l limit limit server sessions\n"
278 1.1 plunky "\t-m mode L2CAP link mode\n"
279 1.1 plunky "\t-p psm L2CAP PSM\n"
280 1.1 plunky "\t-S service service name (no SDP)\n"
281 1.1 plunky "\t-s service service name\n"
282 1.1 plunky "\n"
283 1.1 plunky "Known services:\n"
284 1.1 plunky "", p, n, "", p, n, "");
285 1.1 plunky
286 1.2 lukem for (n = 0; n < (int)__arraycount(services); n++)
287 1.1 plunky fprintf(stderr, "\t%s\t%s\n", services[n].name, services[n].desc);
288 1.1 plunky
289 1.1 plunky exit(EXIT_FAILURE);
290 1.1 plunky }
291