3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
38 #include <bluetooth/bluetooth.h>
39 #include <bluetooth/l2cap.h>
40 #include <bluetooth/bnep.h>
51 const char *name; /* Friendly name */
52 const char *uuid128; /* UUID 128 */
53 uint16_t id; /* Service class identifier */
55 { "panu", PANU_UUID, BNEP_SVC_PANU },
56 { "gn", GN_UUID, BNEP_SVC_GN },
57 { "nap", NAP_UUID, BNEP_SVC_NAP },
61 static const char *panu = NULL;
62 static const char *gn = NULL;
63 static const char *nap = NULL;
71 static gint find_devname(gconstpointer a, gconstpointer b)
73 struct bnep_data *data = (struct bnep_data *) a;
74 const char *devname = b;
76 return strcmp(data->devname, devname);
79 static void script_exited(GPid pid, gint status, gpointer data)
81 if (WIFEXITED(status))
82 debug("%d exited with status %d", pid, WEXITSTATUS(status));
84 debug("%d was killed by signal %d", pid, WTERMSIG(status));
86 g_spawn_close_pid(pid);
89 uint16_t bnep_service_id(const char *svc)
94 /* Friendly service name */
95 for (i = 0; __svc[i].name; i++)
96 if (!strcasecmp(svc, __svc[i].name)) {
100 /* UUID 128 string */
101 for (i = 0; __svc[i].uuid128; i++)
102 if (!strcasecmp(svc, __svc[i].uuid128)) {
106 /* Try convert to HEX */
107 id = strtol(svc, NULL, 16);
108 if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN))
114 const char *bnep_uuid(uint16_t id)
118 for (i = 0; __svc[i].uuid128; i++)
119 if (__svc[i].id == id)
120 return __svc[i].uuid128;
124 const char *bnep_name(uint16_t id)
128 for (i = 0; __svc[i].name; i++)
129 if (__svc[i].id == id)
130 return __svc[i].name;
134 int bnep_init(const char *panu_script, const char *gn_script,
135 const char *nap_script)
137 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
141 error("Failed to open control socket: %s (%d)",
152 int bnep_cleanup(void)
158 int bnep_kill_connection(bdaddr_t *dst)
160 struct bnep_conndel_req req;
162 memset(&req, 0, sizeof(req));
163 baswap((bdaddr_t *)&req.dst, dst);
165 if (ioctl(ctl, BNEPCONNDEL, &req)) {
167 error("Failed to kill connection: %s (%d)",
174 int bnep_kill_all_connections(void)
176 struct bnep_connlist_req req;
177 struct bnep_conninfo ci[7];
181 memset(&req, 0, sizeof(req));
184 if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
186 error("Failed to get connection list: %s (%d)",
191 for (i = 0; i < req.cnum; i++) {
192 struct bnep_conndel_req del;
194 memset(&del, 0, sizeof(del));
195 memcpy(del.dst, ci[i].dst, ETH_ALEN);
197 ioctl(ctl, BNEPCONNDEL, &del);
202 int bnep_connadd(int sk, uint16_t role, char *dev)
204 struct bnep_connadd_req req;
206 memset(&req, 0, sizeof(req));
207 strncpy(req.device, dev, 16);
208 req.device[15] = '\0';
211 if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
213 error("Failed to add device %s: %s(%d)",
214 dev, strerror(err), err);
218 strncpy(dev, req.device, 16);
222 static void bnep_setup(gpointer data)
226 static int bnep_exec(const char **argv)
229 GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
231 if (!g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup, NULL,
233 error("Unable to execute %s %s", argv[0], argv[1]);
240 int bnep_if_up(const char *devname, uint16_t id)
245 struct bnep_data *bnep = NULL;
248 /* Check if a script is running */
249 l = g_slist_find_custom(pids, devname, find_devname);
253 if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
254 argv[0] = bnep->script;
256 argv[2] = "--refresh";
259 bnep->pid = bnep_exec(argv);
263 sd = socket(AF_INET, SOCK_DGRAM, 0);
264 memset(&ifr, 0, sizeof(ifr));
265 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
267 ifr.ifr_flags |= IFF_UP;
268 ifr.ifr_flags |= IFF_MULTICAST;
270 if ((ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr)) < 0) {
272 error("Could not bring up %s. %s(%d)", devname, strerror(err),
280 bnep = g_new0(struct bnep_data, 1);
281 bnep->devname = g_strdup(devname);
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);
291 bnep->script = g_strdup(nap);
296 argv[0] = bnep->script;
299 if (!strcmp(bnep->script, "avahi-autoipd")) {
300 argv[2] = "--no-drop-root";
301 argv[3] = "--no-chroot";
306 bnep->pid = bnep_exec(argv);
307 g_child_watch_add(bnep->pid, script_exited, bnep);
310 pids = g_slist_append(pids, bnep);
315 int bnep_if_down(const char *devname)
319 struct bnep_data *bnep;
324 l = g_slist_find_custom(pids, devname, find_devname);
333 if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
334 argv[0] = bnep->script;
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);
347 err = kill(bnep->pid, SIGTERM);
349 error("kill(%d, SIGTERM): %s (%d)", bnep->pid,
350 strerror(errno), errno);
353 sd = socket(AF_INET, SOCK_DGRAM, 0);
354 memset(&ifr, 0, sizeof(ifr));
355 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
357 ifr.ifr_flags &= ~IFF_UP;
359 /* Bring down the interface */
360 ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr);
362 pids = g_slist_remove(pids, bnep);
365 g_free(bnep->devname);
368 g_free(bnep->script);