• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2004-2010  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 #include <linux/sockios.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 "log.h"
46 #include "common.h"
47 
48 static int ctl;
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 
bnep_service_id(const char * svc)61 uint16_t bnep_service_id(const char *svc)
62 {
63 	int i;
64 	uint16_t id;
65 
66 	/* Friendly service name */
67 	for (i = 0; __svc[i].name; i++)
68 		if (!strcasecmp(svc, __svc[i].name)) {
69 			return __svc[i].id;
70 		}
71 
72 	/* UUID 128 string */
73 	for (i = 0; __svc[i].uuid128; i++)
74 		if (!strcasecmp(svc, __svc[i].uuid128)) {
75 			return __svc[i].id;
76 		}
77 
78 	/* Try convert to HEX */
79 	id = strtol(svc, NULL, 16);
80 	if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN))
81 		return 0;
82 
83 	return id;
84 }
85 
bnep_uuid(uint16_t id)86 const char *bnep_uuid(uint16_t id)
87 {
88 	int i;
89 
90 	for (i = 0; __svc[i].uuid128; i++)
91 		if (__svc[i].id == id)
92 			return __svc[i].uuid128;
93 	return NULL;
94 }
95 
bnep_name(uint16_t id)96 const char *bnep_name(uint16_t id)
97 {
98 	int i;
99 
100 	for (i = 0; __svc[i].name; i++)
101 		if (__svc[i].id == id)
102 			return __svc[i].name;
103 	return NULL;
104 }
105 
bnep_init(void)106 int bnep_init(void)
107 {
108 	ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
109 
110 	if (ctl < 0) {
111 		int err = errno;
112 		error("Failed to open control socket: %s (%d)",
113 						strerror(err), err);
114 		return -err;
115 	}
116 
117 	return 0;
118 }
119 
bnep_cleanup(void)120 int bnep_cleanup(void)
121 {
122 	close(ctl);
123 	return 0;
124 }
125 
bnep_kill_connection(bdaddr_t * dst)126 int bnep_kill_connection(bdaddr_t *dst)
127 {
128 	struct bnep_conndel_req req;
129 
130 	memset(&req, 0, sizeof(req));
131 	baswap((bdaddr_t *)&req.dst, dst);
132 	req.flags = 0;
133 	if (ioctl(ctl, BNEPCONNDEL, &req)) {
134 		int err = errno;
135 		error("Failed to kill connection: %s (%d)",
136 						strerror(err), err);
137 		return -err;
138 	}
139 	return 0;
140 }
141 
bnep_kill_all_connections(void)142 int bnep_kill_all_connections(void)
143 {
144 	struct bnep_connlist_req req;
145 	struct bnep_conninfo ci[7];
146 	unsigned int i;
147 	int err;
148 
149 	memset(&req, 0, sizeof(req));
150 	req.cnum = 7;
151 	req.ci   = ci;
152 	if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
153 		err = errno;
154 		error("Failed to get connection list: %s (%d)",
155 						strerror(err), err);
156 		return -err;
157 	}
158 
159 	for (i = 0; i < req.cnum; i++) {
160 		struct bnep_conndel_req del;
161 
162 		memset(&del, 0, sizeof(del));
163 		memcpy(del.dst, ci[i].dst, ETH_ALEN);
164 		del.flags = 0;
165 		ioctl(ctl, BNEPCONNDEL, &del);
166 	}
167 	return 0;
168 }
169 
bnep_connadd(int sk,uint16_t role,char * dev)170 int bnep_connadd(int sk, uint16_t role, char *dev)
171 {
172 	struct bnep_connadd_req req;
173 
174 	memset(&req, 0, sizeof(req));
175 	strncpy(req.device, dev, 16);
176 	req.device[15] = '\0';
177 	req.sock = sk;
178 	req.role = role;
179 	if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
180 		int err = errno;
181 		error("Failed to add device %s: %s(%d)",
182 				dev, strerror(err), err);
183 		return -err;
184 	}
185 
186 	strncpy(dev, req.device, 16);
187 	return 0;
188 }
189 
bnep_if_up(const char * devname)190 int bnep_if_up(const char *devname)
191 {
192 	struct ifreq ifr;
193 	int sk, err;
194 
195 	sk = socket(AF_INET, SOCK_DGRAM, 0);
196 
197 	memset(&ifr, 0, sizeof(ifr));
198 	strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
199 
200 	ifr.ifr_flags |= IFF_UP;
201 	ifr.ifr_flags |= IFF_MULTICAST;
202 
203 	err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
204 
205 	close(sk);
206 
207 	if (err < 0) {
208 		error("Could not bring up %s", devname);
209 		return err;
210 	}
211 
212 	return 0;
213 }
214 
bnep_if_down(const char * devname)215 int bnep_if_down(const char *devname)
216 {
217 	struct ifreq ifr;
218 	int sk, err;
219 
220 	sk = socket(AF_INET, SOCK_DGRAM, 0);
221 
222 	memset(&ifr, 0, sizeof(ifr));
223 	strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
224 
225 	ifr.ifr_flags &= ~IFF_UP;
226 
227 	/* Bring down the interface */
228 	err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
229 
230 	close(sk);
231 
232 	if (err < 0) {
233 		error("Could not bring down %s", devname);
234 		return err;
235 	}
236 
237 	return 0;
238 }
239 
bnep_add_to_bridge(const char * devname,const char * bridge)240 int bnep_add_to_bridge(const char *devname, const char *bridge)
241 {
242 	int ifindex = if_nametoindex(devname);
243 	struct ifreq ifr;
244 	int sk, err;
245 
246 	if (!devname || !bridge)
247 		return -EINVAL;
248 
249 	sk = socket(AF_INET, SOCK_STREAM, 0);
250 	if (sk < 0)
251 		return -1;
252 
253 	memset(&ifr, 0, sizeof(ifr));
254 	strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
255 	ifr.ifr_ifindex = ifindex;
256 
257 	err = ioctl(sk, SIOCBRADDIF, &ifr);
258 
259 	close(sk);
260 
261 	if (err < 0)
262 		return err;
263 
264 	info("bridge %s: interface %s added", bridge, devname);
265 
266 	return 0;
267 }
268