• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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