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