OSDN Git Service

eclair snapshot
[android-x86/external-bluetooth-bluez.git] / network / common.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2004-2009  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/wait.h>
36 #include <net/if.h>
37
38 #include <bluetooth/bluetooth.h>
39 #include <bluetooth/l2cap.h>
40 #include <bluetooth/bnep.h>
41
42 #include <glib.h>
43
44 #include "logging.h"
45 #include "common.h"
46
47 static int ctl;
48 static GSList *pids;
49
50 static struct {
51         const char      *name;          /* Friendly name */
52         const char      *uuid128;       /* UUID 128 */
53         uint16_t        id;             /* Service class identifier */
54 } __svc[] = {
55         { "panu",       PANU_UUID,      BNEP_SVC_PANU   },
56         { "gn",         GN_UUID,        BNEP_SVC_GN     },
57         { "nap",        NAP_UUID,       BNEP_SVC_NAP    },
58         { NULL }
59 };
60
61 static const char *panu = NULL;
62 static const char *gn = NULL;
63 static const char *nap = NULL;
64
65 struct bnep_data {
66         char *devname;
67         char *script;
68         int pid;
69 };
70
71 static gint find_devname(gconstpointer a, gconstpointer b)
72 {
73         struct bnep_data *data = (struct bnep_data *) a;
74         const char *devname = b;
75
76         return strcmp(data->devname, devname);
77 }
78
79 static void script_exited(GPid pid, gint status, gpointer data)
80 {
81         if (WIFEXITED(status))
82                 debug("%d exited with status %d", pid, WEXITSTATUS(status));
83         else
84                 debug("%d was killed by signal %d", pid, WTERMSIG(status));
85
86         g_spawn_close_pid(pid);
87 }
88
89 uint16_t bnep_service_id(const char *svc)
90 {
91         int i;
92         uint16_t id;
93
94         /* Friendly service name */
95         for (i = 0; __svc[i].name; i++)
96                 if (!strcasecmp(svc, __svc[i].name)) {
97                         return __svc[i].id;
98                 }
99
100         /* UUID 128 string */
101         for (i = 0; __svc[i].uuid128; i++)
102                 if (!strcasecmp(svc, __svc[i].uuid128)) {
103                         return __svc[i].id;
104                 }
105
106         /* Try convert to HEX */
107         id = strtol(svc, NULL, 16);
108         if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN))
109                 return 0;
110
111         return id;
112 }
113
114 const char *bnep_uuid(uint16_t id)
115 {
116         int i;
117
118         for (i = 0; __svc[i].uuid128; i++)
119                 if (__svc[i].id == id)
120                         return __svc[i].uuid128;
121         return NULL;
122 }
123
124 const char *bnep_name(uint16_t id)
125 {
126         int i;
127
128         for (i = 0; __svc[i].name; i++)
129                 if (__svc[i].id == id)
130                         return __svc[i].name;
131         return NULL;
132 }
133
134 int bnep_init(const char *panu_script, const char *gn_script,
135                 const char *nap_script)
136 {
137         ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
138
139         if (ctl < 0) {
140                 int err = errno;
141                 error("Failed to open control socket: %s (%d)",
142                                                 strerror(err), err);
143                 return -err;
144         }
145
146         panu = panu_script;
147         gn = gn_script;
148         nap = nap_script;
149         return 0;
150 }
151
152 int bnep_cleanup(void)
153 {
154         close(ctl);
155         return 0;
156 }
157
158 int bnep_kill_connection(bdaddr_t *dst)
159 {
160         struct bnep_conndel_req req;
161
162         memset(&req, 0, sizeof(req));
163         baswap((bdaddr_t *)&req.dst, dst);
164         req.flags = 0;
165         if (ioctl(ctl, BNEPCONNDEL, &req)) {
166                 int err = errno;
167                 error("Failed to kill connection: %s (%d)",
168                                                 strerror(err), err);
169                 return -err;
170         }
171         return 0;
172 }
173
174 int bnep_kill_all_connections(void)
175 {
176         struct bnep_connlist_req req;
177         struct bnep_conninfo ci[7];
178         unsigned int i;
179         int err;
180
181         memset(&req, 0, sizeof(req));
182         req.cnum = 7;
183         req.ci   = ci;
184         if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
185                 err = errno;
186                 error("Failed to get connection list: %s (%d)",
187                                                 strerror(err), err);
188                 return -err;
189         }
190
191         for (i = 0; i < req.cnum; i++) {
192                 struct bnep_conndel_req del;
193
194                 memset(&del, 0, sizeof(del));
195                 memcpy(del.dst, ci[i].dst, ETH_ALEN);
196                 del.flags = 0;
197                 ioctl(ctl, BNEPCONNDEL, &del);
198         }
199         return 0;
200 }
201
202 int bnep_connadd(int sk, uint16_t role, char *dev)
203 {
204         struct bnep_connadd_req req;
205
206         memset(&req, 0, sizeof(req));
207         strncpy(req.device, dev, 16);
208         req.device[15] = '\0';
209         req.sock = sk;
210         req.role = role;
211         if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
212                 int err = errno;
213                 error("Failed to add device %s: %s(%d)",
214                                 dev, strerror(err), err);
215                 return -err;
216         }
217
218         strncpy(dev, req.device, 16);
219         return 0;
220 }
221
222 static void bnep_setup(gpointer data)
223 {
224 }
225
226 static int bnep_exec(const char **argv)
227 {
228         int pid;
229         GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
230
231         if (!g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup, NULL,
232                                 &pid, NULL)) {
233                 error("Unable to execute %s %s", argv[0], argv[1]);
234                 return -EINVAL;
235         }
236
237         return pid;
238 }
239
240 int bnep_if_up(const char *devname, uint16_t id)
241 {
242         int sd, err;
243         struct ifreq ifr;
244         const char *argv[5];
245         struct bnep_data *bnep = NULL;
246         GSList *l;
247
248         /* Check if a script is running */
249         l = g_slist_find_custom(pids, devname, find_devname);
250         if (l) {
251                 bnep = l->data;
252
253                 if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
254                         argv[0] = bnep->script;
255                         argv[1] = devname;
256                         argv[2] = "--refresh";
257                         argv[3] = NULL;
258
259                         bnep->pid = bnep_exec(argv);
260                 }
261         }
262
263         sd = socket(AF_INET, SOCK_DGRAM, 0);
264         memset(&ifr, 0, sizeof(ifr));
265         strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
266
267         ifr.ifr_flags |= IFF_UP;
268         ifr.ifr_flags |= IFF_MULTICAST;
269
270         if ((ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr)) < 0) {
271                 err = errno;
272                 error("Could not bring up %s. %s(%d)", devname, strerror(err),
273                         err);
274                 return -err;
275         }
276
277         if (bnep)
278                 return bnep->pid;
279
280         bnep = g_new0(struct bnep_data, 1);
281         bnep->devname = g_strdup(devname);
282
283         if (!id)
284                 goto done;
285
286         if (id == BNEP_SVC_PANU)
287                 bnep->script = g_strdup(panu);
288         else if (id == BNEP_SVC_GN)
289                 bnep->script = g_strdup(gn);
290         else
291                 bnep->script = g_strdup(nap);
292
293         if (!bnep->script)
294                 goto done;
295
296         argv[0] = bnep->script;
297         argv[1] = devname;
298
299         if (!strcmp(bnep->script, "avahi-autoipd")) {
300                 argv[2] = "--no-drop-root";
301                 argv[3] = "--no-chroot";
302                 argv[4] = NULL;
303         } else
304                 argv[2] = NULL;
305
306         bnep->pid = bnep_exec(argv);
307         g_child_watch_add(bnep->pid, script_exited, bnep);
308
309 done:
310         pids = g_slist_append(pids, bnep);
311
312         return bnep->pid;
313 }
314
315 int bnep_if_down(const char *devname)
316 {
317         int sd, err, pid;
318         struct ifreq ifr;
319         struct bnep_data *bnep;
320         GSList *l;
321         GSpawnFlags flags;
322         const char *argv[4];
323
324         l = g_slist_find_custom(pids, devname, find_devname);
325         if (!l)
326                 return 0;
327
328         bnep = l->data;
329
330         if (!bnep->pid)
331                 goto done;
332
333         if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
334                 argv[0] = bnep->script;
335                 argv[1] = devname;
336                 argv[2] = "--kill";
337                 argv[3] = NULL;
338
339                 flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
340                 g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup,
341                                 (gpointer) devname, &pid, NULL);
342
343                 goto done;
344         }
345
346         /* Kill script */
347         err = kill(bnep->pid, SIGTERM);
348         if (err < 0)
349                 error("kill(%d, SIGTERM): %s (%d)", bnep->pid,
350                         strerror(errno), errno);
351
352 done:
353         sd = socket(AF_INET, SOCK_DGRAM, 0);
354         memset(&ifr, 0, sizeof(ifr));
355         strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
356
357         ifr.ifr_flags &= ~IFF_UP;
358
359         /* Bring down the interface */
360         ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr);
361
362         pids = g_slist_remove(pids, bnep);
363
364         if (bnep->devname)
365                 g_free(bnep->devname);
366
367         if (bnep->script)
368                 g_free(bnep->script);
369
370         g_free(bnep);
371
372         return 0;
373 }