1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
6 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35
36 #include <bluetooth/bluetooth.h>
37 #include <bluetooth/bnep.h>
38
39 #include <netinet/in.h>
40
41 #include "pand.h"
42
43 static int ctl;
44
45 /* Compatibility with old ioctls */
46 #define OLD_BNEPCONADD 1
47 #define OLD_BNEPCONDEL 2
48 #define OLD_BNEPGETCONLIST 3
49 #define OLD_BNEPGETCONINFO 4
50
51 static unsigned long bnepconnadd;
52 static unsigned long bnepconndel;
53 static unsigned long bnepgetconnlist;
54 static unsigned long bnepgetconninfo;
55
56 static struct {
57 char *str;
58 uint16_t uuid;
59 } __svc[] = {
60 { "PANU", BNEP_SVC_PANU },
61 { "NAP", BNEP_SVC_NAP },
62 { "GN", BNEP_SVC_GN },
63 { NULL }
64 };
65
bnep_str2svc(char * svc,uint16_t * uuid)66 int bnep_str2svc(char *svc, uint16_t *uuid)
67 {
68 int i;
69 for (i = 0; __svc[i].str; i++)
70 if (!strcasecmp(svc, __svc[i].str)) {
71 *uuid = __svc[i].uuid;
72 return 0;
73 }
74 return -1;
75 }
76
bnep_svc2str(uint16_t uuid)77 char *bnep_svc2str(uint16_t uuid)
78 {
79 int i;
80 for (i = 0; __svc[i].str; i++)
81 if (__svc[i].uuid == uuid)
82 return __svc[i].str;
83 return NULL;
84 }
85
bnep_init(void)86 int bnep_init(void)
87 {
88 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
89 if (ctl < 0) {
90 perror("Failed to open control socket");
91 return 1;
92 }
93
94 /* Temporary ioctl compatibility hack */
95 {
96 struct bnep_connlist_req req;
97 struct bnep_conninfo ci[1];
98
99 req.cnum = 1;
100 req.ci = ci;
101
102 if (!ioctl(ctl, BNEPGETCONNLIST, &req)) {
103 /* New ioctls */
104 bnepconnadd = BNEPCONNADD;
105 bnepconndel = BNEPCONNDEL;
106 bnepgetconnlist = BNEPGETCONNLIST;
107 bnepgetconninfo = BNEPGETCONNINFO;
108 } else {
109 /* Old ioctls */
110 bnepconnadd = OLD_BNEPCONADD;
111 bnepconndel = OLD_BNEPCONDEL;
112 bnepgetconnlist = OLD_BNEPGETCONLIST;
113 bnepgetconninfo = OLD_BNEPGETCONINFO;
114 }
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_show_connections(void)126 int bnep_show_connections(void)
127 {
128 struct bnep_connlist_req req;
129 struct bnep_conninfo ci[48];
130 unsigned int i;
131
132 req.cnum = 48;
133 req.ci = ci;
134 if (ioctl(ctl, bnepgetconnlist, &req)) {
135 perror("Failed to get connection list");
136 return -1;
137 }
138
139 for (i = 0; i < req.cnum; i++) {
140 char addr[18];
141 ba2str((bdaddr_t *) ci[i].dst, addr);
142 printf("%s %s %s\n", ci[i].device,
143 addr, bnep_svc2str(ci[i].role));
144 }
145 return 0;
146 }
147
bnep_kill_connection(uint8_t * dst)148 int bnep_kill_connection(uint8_t *dst)
149 {
150 struct bnep_conndel_req req;
151
152 memcpy(req.dst, dst, ETH_ALEN);
153 req.flags = 0;
154 if (ioctl(ctl, bnepconndel, &req)) {
155 perror("Failed to kill connection");
156 return -1;
157 }
158 return 0;
159 }
160
bnep_kill_all_connections(void)161 int bnep_kill_all_connections(void)
162 {
163 struct bnep_connlist_req req;
164 struct bnep_conninfo ci[48];
165 unsigned int i;
166
167 req.cnum = 48;
168 req.ci = ci;
169 if (ioctl(ctl, bnepgetconnlist, &req)) {
170 perror("Failed to get connection list");
171 return -1;
172 }
173
174 for (i = 0; i < req.cnum; i++) {
175 struct bnep_conndel_req req;
176 memcpy(req.dst, ci[i].dst, ETH_ALEN);
177 req.flags = 0;
178 ioctl(ctl, bnepconndel, &req);
179 }
180 return 0;
181 }
182
bnep_connadd(int sk,uint16_t role,char * dev)183 static int bnep_connadd(int sk, uint16_t role, char *dev)
184 {
185 struct bnep_connadd_req req;
186
187 strncpy(req.device, dev, 16);
188 req.device[15] = '\0';
189 req.sock = sk;
190 req.role = role;
191 if (ioctl(ctl, bnepconnadd, &req))
192 return -1;
193 strncpy(dev, req.device, 16);
194 return 0;
195 }
196
197 struct __service_16 {
198 uint16_t dst;
199 uint16_t src;
200 } __attribute__ ((packed));
201
202 struct __service_32 {
203 uint16_t unused1;
204 uint16_t dst;
205 uint16_t unused2;
206 uint16_t src;
207 } __attribute__ ((packed));
208
209 struct __service_128 {
210 uint16_t unused1;
211 uint16_t dst;
212 uint16_t unused2[8];
213 uint16_t src;
214 uint16_t unused3[7];
215 } __attribute__ ((packed));
216
bnep_accept_connection(int sk,uint16_t role,char * dev)217 int bnep_accept_connection(int sk, uint16_t role, char *dev)
218 {
219 struct bnep_setup_conn_req *req;
220 struct bnep_control_rsp *rsp;
221 unsigned char pkt[BNEP_MTU];
222 ssize_t r;
223
224 r = recv(sk, pkt, BNEP_MTU, 0);
225 if (r <= 0)
226 return -1;
227
228 errno = EPROTO;
229
230 if ((size_t) r < sizeof(*req))
231 return -1;
232
233 req = (void *) pkt;
234
235 /* Highest known Control command ID
236 * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */
237 if (req->type == BNEP_CONTROL &&
238 req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
239 uint8_t pkt[3];
240
241 pkt[0] = BNEP_CONTROL;
242 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
243 pkt[2] = req->ctrl;
244
245 send(sk, pkt, sizeof(pkt), 0);
246
247 return -1;
248 }
249
250 if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
251 return -1;
252
253 /* FIXME: Check role UUIDs */
254
255 rsp = (void *) pkt;
256 rsp->type = BNEP_CONTROL;
257 rsp->ctrl = BNEP_SETUP_CONN_RSP;
258 rsp->resp = htons(BNEP_SUCCESS);
259 if (send(sk, rsp, sizeof(*rsp), 0) < 0)
260 return -1;
261
262 return bnep_connadd(sk, role, dev);
263 }
264
265 /* Create BNEP connection
266 * sk - Connect L2CAP socket
267 * role - Local role
268 * service - Remote service
269 * dev - Network device (contains actual dev name on return)
270 */
bnep_create_connection(int sk,uint16_t role,uint16_t svc,char * dev)271 int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev)
272 {
273 struct bnep_setup_conn_req *req;
274 struct bnep_control_rsp *rsp;
275 struct __service_16 *s;
276 struct timeval timeo;
277 unsigned char pkt[BNEP_MTU];
278 ssize_t r;
279
280 /* Send request */
281 req = (void *) pkt;
282 req->type = BNEP_CONTROL;
283 req->ctrl = BNEP_SETUP_CONN_REQ;
284 req->uuid_size = 2; /* 16bit UUID */
285
286 s = (void *) req->service;
287 s->dst = htons(svc);
288 s->src = htons(role);
289
290 memset(&timeo, 0, sizeof(timeo));
291 timeo.tv_sec = 30;
292
293 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
294
295 if (send(sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0)
296 return -1;
297
298 receive:
299 /* Get response */
300 r = recv(sk, pkt, BNEP_MTU, 0);
301 if (r <= 0)
302 return -1;
303
304 memset(&timeo, 0, sizeof(timeo));
305 timeo.tv_sec = 0;
306
307 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
308
309 errno = EPROTO;
310
311 if ((size_t) r < sizeof(*rsp))
312 return -1;
313
314 rsp = (void *) pkt;
315 if (rsp->type != BNEP_CONTROL)
316 return -1;
317
318 if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
319 goto receive;
320
321 r = ntohs(rsp->resp);
322
323 switch (r) {
324 case BNEP_SUCCESS:
325 break;
326
327 case BNEP_CONN_INVALID_DST:
328 case BNEP_CONN_INVALID_SRC:
329 case BNEP_CONN_INVALID_SVC:
330 errno = EPROTO;
331 return -1;
332
333 case BNEP_CONN_NOT_ALLOWED:
334 errno = EACCES;
335 return -1;
336 }
337
338 return bnep_connadd(sk, role, dev);
339 }
340