1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37 #include <net/if.h>
38
39 #include <bluetooth/bluetooth.h>
40 #include <bluetooth/l2cap.h>
41 #include <bluetooth/bnep.h>
42
43 #include <glib.h>
44
45 #include "logging.h"
46 #include "common.h"
47 #include "textfile.h"
48
49 static int ctl;
50 static GSList *pids;
51
52 #define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb"
53 #define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb"
54 #define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
55
56 static struct {
57 const char *name; /* Friendly name */
58 const char *uuid128; /* UUID 128 */
59 uint16_t id; /* Service class identifier */
60 } __svc[] = {
61 { "panu", PANU_UUID, BNEP_SVC_PANU },
62 { "gn", GN_UUID, BNEP_SVC_GN },
63 { "nap", NAP_UUID, BNEP_SVC_NAP },
64 { NULL }
65 };
66
67 static const char *panu = NULL;
68 static const char *gn = NULL;
69 static const char *nap = NULL;
70
71 struct bnep_data {
72 char *devname;
73 char *script;
74 int pid;
75 };
76
find_devname(gconstpointer a,gconstpointer b)77 static gint find_devname(gconstpointer a, gconstpointer b)
78 {
79 struct bnep_data *data = (struct bnep_data *) a;
80 const char *devname = b;
81
82 return strcmp(data->devname, devname);
83 }
84
script_exited(GPid pid,gint status,gpointer data)85 static void script_exited(GPid pid, gint status, gpointer data)
86 {
87 if (WIFEXITED(status))
88 debug("%d exited with status %d", pid, WEXITSTATUS(status));
89 else
90 debug("%d was killed by signal %d", pid, WTERMSIG(status));
91
92 g_spawn_close_pid(pid);
93 }
94
bnep_service_id(const char * svc)95 uint16_t bnep_service_id(const char *svc)
96 {
97 int i;
98 uint16_t id;
99
100 /* Friendly service name */
101 for (i = 0; __svc[i].name; i++)
102 if (!strcasecmp(svc, __svc[i].name)) {
103 return __svc[i].id;
104 }
105
106 /* UUID 128 string */
107 for (i = 0; __svc[i].uuid128; i++)
108 if (!strcasecmp(svc, __svc[i].uuid128)) {
109 return __svc[i].id;
110 }
111
112 /* Try convert to HEX */
113 id = strtol(svc, NULL, 16);
114 if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN))
115 return 0;
116
117 return id;
118 }
119
bnep_uuid(uint16_t id)120 const char *bnep_uuid(uint16_t id)
121 {
122 int i;
123
124 for (i = 0; __svc[i].uuid128; i++)
125 if (__svc[i].id == id)
126 return __svc[i].uuid128;
127 return NULL;
128 }
129
bnep_name(uint16_t id)130 const char *bnep_name(uint16_t id)
131 {
132 int i;
133
134 for (i = 0; __svc[i].name; i++)
135 if (__svc[i].id == id)
136 return __svc[i].name;
137 return NULL;
138 }
139
bnep_init(const char * panu_script,const char * gn_script,const char * nap_script)140 int bnep_init(const char *panu_script, const char *gn_script,
141 const char *nap_script)
142 {
143 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
144
145 if (ctl < 0) {
146 int err = errno;
147 error("Failed to open control socket: %s (%d)",
148 strerror(err), err);
149 return -err;
150 }
151
152 panu = panu_script;
153 gn = gn_script;
154 nap = nap_script;
155 return 0;
156 }
157
bnep_cleanup(void)158 int bnep_cleanup(void)
159 {
160 close(ctl);
161 return 0;
162 }
163
bnep_kill_connection(bdaddr_t * dst)164 int bnep_kill_connection(bdaddr_t *dst)
165 {
166 struct bnep_conndel_req req;
167
168 memset(&req, 0, sizeof(req));
169 baswap((bdaddr_t *)&req.dst, dst);
170 req.flags = 0;
171 if (ioctl(ctl, BNEPCONNDEL, &req)) {
172 int err = errno;
173 error("Failed to kill connection: %s (%d)",
174 strerror(err), err);
175 return -err;
176 }
177 return 0;
178 }
179
bnep_kill_all_connections(void)180 int bnep_kill_all_connections(void)
181 {
182 struct bnep_connlist_req req;
183 struct bnep_conninfo ci[7];
184 int i, err;
185
186 memset(&req, 0, sizeof(req));
187 req.cnum = 7;
188 req.ci = ci;
189 if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
190 err = errno;
191 error("Failed to get connection list: %s (%d)",
192 strerror(err), err);
193 return -err;
194 }
195
196 for (i=0; i < req.cnum; i++) {
197 struct bnep_conndel_req del;
198
199 memset(&del, 0, sizeof(del));
200 memcpy(del.dst, ci[i].dst, ETH_ALEN);
201 del.flags = 0;
202 ioctl(ctl, BNEPCONNDEL, &del);
203 }
204 return 0;
205 }
206
bnep_connadd(int sk,uint16_t role,char * dev)207 int bnep_connadd(int sk, uint16_t role, char *dev)
208 {
209 struct bnep_connadd_req req;
210
211 memset(&req, 0, sizeof(req));
212 strncpy(req.device, dev, 16);
213 req.device[15] = '\0';
214 req.sock = sk;
215 req.role = role;
216 if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
217 int err = errno;
218 error("Failed to add device %s: %s(%d)",
219 dev, strerror(err), err);
220 return -err;
221 }
222
223 strncpy(dev, req.device, 16);
224 return 0;
225 }
226
bnep_setup(gpointer data)227 static void bnep_setup(gpointer data)
228 {
229 }
230
bnep_exec(const char ** argv)231 static int bnep_exec(const char **argv)
232 {
233 int pid;
234 GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
235
236 if (!g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup, NULL,
237 &pid, NULL)) {
238 error("Unable to execute %s %s", *argv[0], *argv[1]);
239 return -EINVAL;
240 }
241
242 return pid;
243 }
244
bnep_if_up(const char * devname,uint16_t id)245 int bnep_if_up(const char *devname, uint16_t id)
246 {
247 int sd, err;
248 struct ifreq ifr;
249 const char *argv[5];
250 struct bnep_data *bnep = NULL;
251 GSList *l;
252
253 /* Check if a script is running */
254 l = g_slist_find_custom(pids, devname, find_devname);
255 if (l) {
256 bnep = l->data;
257
258 if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
259 argv[0] = bnep->script;
260 argv[1] = devname;
261 argv[2] = "--refresh";
262 argv[3] = NULL;
263
264 bnep->pid = bnep_exec(argv);
265 }
266 }
267
268 sd = socket(AF_INET6, SOCK_DGRAM, 0);
269 memset(&ifr, 0, sizeof(ifr));
270 strcpy(ifr.ifr_name, devname);
271
272 ifr.ifr_flags |= IFF_UP;
273 ifr.ifr_flags |= IFF_MULTICAST;
274
275 if ((ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr)) < 0) {
276 err = errno;
277 error("Could not bring up %s. %s(%d)", devname, strerror(err),
278 err);
279 return -err;
280 }
281
282 if (bnep)
283 return bnep->pid;
284
285 bnep = g_new0(struct bnep_data, 1);
286 bnep->devname = g_strdup(devname);
287
288 if (!id)
289 goto done;
290
291 if (id == BNEP_SVC_PANU)
292 bnep->script = g_strdup(panu);
293 else if (id == BNEP_SVC_GN)
294 bnep->script = g_strdup(gn);
295 else
296 bnep->script = g_strdup(nap);
297
298 if (!bnep->script)
299 goto done;
300
301 argv[0] = bnep->script;
302 argv[1] = devname;
303
304 if (!strcmp(bnep->script, "avahi-autoipd")) {
305 argv[2] = "--no-drop-root";
306 argv[3] = "--no-chroot";
307 argv[4] = NULL;
308 } else
309 argv[2] = NULL;
310
311 bnep->pid = bnep_exec(argv);
312 g_child_watch_add(bnep->pid, script_exited, bnep);
313
314 done:
315 pids = g_slist_append(pids, bnep);
316
317 return bnep->pid;
318 }
319
bnep_if_down(const char * devname)320 int bnep_if_down(const char *devname)
321 {
322 int sd, err, pid;
323 struct ifreq ifr;
324 struct bnep_data *bnep;
325 GSList *l;
326 GSpawnFlags flags;
327 const char *argv[4];
328
329 l = g_slist_find_custom(pids, devname, find_devname);
330 if (!l)
331 return 0;
332
333 bnep = l->data;
334
335 if (!bnep->pid)
336 goto done;
337
338 if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
339 argv[0] = bnep->script;
340 argv[1] = devname;
341 argv[2] = "--kill";
342 argv[3] = NULL;
343
344 flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
345 g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup,
346 (gpointer) devname, &pid, NULL);
347
348 goto done;
349 }
350
351 /* Kill script */
352 err = kill(bnep->pid, SIGTERM);
353 if (err < 0)
354 error("kill(%d, SIGTERM): %s (%d)", bnep->pid,
355 strerror(errno), errno);
356
357 done:
358 sd = socket(AF_INET6, SOCK_DGRAM, 0);
359 memset(&ifr, 0, sizeof(ifr));
360 strcpy(ifr.ifr_name, devname);
361
362 ifr.ifr_flags &= ~IFF_UP;
363
364 /* Bring down the interface */
365 ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr);
366
367 pids = g_slist_remove(pids, bnep);
368
369 if (bnep->devname)
370 g_free(bnep->devname);
371
372 if (bnep->script)
373 g_free(bnep->script);
374
375 g_free(bnep);
376
377 return 0;
378 }
379
read_remote_name(bdaddr_t * src,bdaddr_t * dst,char * buf,size_t size)380 int read_remote_name(bdaddr_t *src, bdaddr_t *dst, char *buf, size_t size)
381 {
382 char filename[PATH_MAX + 1], addr[18], *str;
383
384 ba2str(src, addr);
385 create_name(filename, PATH_MAX, STORAGEDIR, addr, "names");
386
387 ba2str(dst, addr);
388 str = textfile_get(filename, addr);
389 if (!str)
390 return -ENOENT;
391
392 snprintf(buf, size, "%s", str);
393 free(str);
394
395 return 0;
396 }
397