1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
6 * Copyright (C) 2002-2009 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/l2cap.h>
38 #include <bluetooth/bnep.h>
39
40 #include <netinet/in.h>
41
42 #include "pand.h"
43
44 static int ctl;
45
46 /* Compatibility with old ioctls */
47 #define OLD_BNEPCONADD 1
48 #define OLD_BNEPCONDEL 2
49 #define OLD_BNEPGETCONLIST 3
50 #define OLD_BNEPGETCONINFO 4
51
52 static unsigned long bnepconnadd;
53 static unsigned long bnepconndel;
54 static unsigned long bnepgetconnlist;
55 static unsigned long bnepgetconninfo;
56
57 static struct {
58 char *str;
59 uint16_t uuid;
60 } __svc[] = {
61 { "PANU", BNEP_SVC_PANU },
62 { "NAP", BNEP_SVC_NAP },
63 { "GN", BNEP_SVC_GN },
64 { NULL }
65 };
66
bnep_str2svc(char * svc,uint16_t * uuid)67 int bnep_str2svc(char *svc, uint16_t *uuid)
68 {
69 int i;
70 for (i = 0; __svc[i].str; i++)
71 if (!strcasecmp(svc, __svc[i].str)) {
72 *uuid = __svc[i].uuid;
73 return 0;
74 }
75 return -1;
76 }
77
bnep_svc2str(uint16_t uuid)78 char *bnep_svc2str(uint16_t uuid)
79 {
80 int i;
81 for (i = 0; __svc[i].str; i++)
82 if (__svc[i].uuid == uuid)
83 return __svc[i].str;
84 return NULL;
85 }
86
bnep_init(void)87 int bnep_init(void)
88 {
89 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
90 if (ctl < 0) {
91 perror("Failed to open control socket");
92 return 1;
93 }
94
95 /* Temporary ioctl compatibility hack */
96 {
97 struct bnep_connlist_req req;
98 struct bnep_conninfo ci[1];
99
100 req.cnum = 1;
101 req.ci = ci;
102
103 if (!ioctl(ctl, BNEPGETCONNLIST, &req)) {
104 /* New ioctls */
105 bnepconnadd = BNEPCONNADD;
106 bnepconndel = BNEPCONNDEL;
107 bnepgetconnlist = BNEPGETCONNLIST;
108 bnepgetconninfo = BNEPGETCONNINFO;
109 } else {
110 /* Old ioctls */
111 bnepconnadd = OLD_BNEPCONADD;
112 bnepconndel = OLD_BNEPCONDEL;
113 bnepgetconnlist = OLD_BNEPGETCONLIST;
114 bnepgetconninfo = OLD_BNEPGETCONINFO;
115 }
116 }
117
118 return 0;
119 }
120
bnep_cleanup(void)121 int bnep_cleanup(void)
122 {
123 close(ctl);
124 return 0;
125 }
126
bnep_show_connections(void)127 int bnep_show_connections(void)
128 {
129 struct bnep_connlist_req req;
130 struct bnep_conninfo ci[48];
131 unsigned int i;
132
133 req.cnum = 48;
134 req.ci = ci;
135 if (ioctl(ctl, bnepgetconnlist, &req)) {
136 perror("Failed to get connection list");
137 return -1;
138 }
139
140 for (i = 0; i < req.cnum; i++) {
141 printf("%s %s %s\n", ci[i].device,
142 batostr((bdaddr_t *) ci[i].dst),
143 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 if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
235 return -1;
236
237 /* FIXME: Check role UUIDs */
238
239 rsp = (void *) pkt;
240 rsp->type = BNEP_CONTROL;
241 rsp->ctrl = BNEP_SETUP_CONN_RSP;
242 rsp->resp = htons(BNEP_SUCCESS);
243 if (send(sk, rsp, sizeof(*rsp), 0) < 0)
244 return -1;
245
246 return bnep_connadd(sk, role, dev);
247 }
248
249 /* Create BNEP connection
250 * sk - Connect L2CAP socket
251 * role - Local role
252 * service - Remote service
253 * dev - Network device (contains actual dev name on return)
254 */
bnep_create_connection(int sk,uint16_t role,uint16_t svc,char * dev)255 int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev)
256 {
257 struct bnep_setup_conn_req *req;
258 struct bnep_control_rsp *rsp;
259 struct __service_16 *s;
260 struct timeval timeo;
261 unsigned char pkt[BNEP_MTU];
262 ssize_t r;
263
264 /* Send request */
265 req = (void *) pkt;
266 req->type = BNEP_CONTROL;
267 req->ctrl = BNEP_SETUP_CONN_REQ;
268 req->uuid_size = 2; /* 16bit UUID */
269
270 s = (void *) req->service;
271 s->dst = htons(svc);
272 s->src = htons(role);
273
274 memset(&timeo, 0, sizeof(timeo));
275 timeo.tv_sec = 30;
276
277 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
278
279 if (send(sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0)
280 return -1;
281
282 receive:
283 /* Get response */
284 r = recv(sk, pkt, BNEP_MTU, 0);
285 if (r <= 0)
286 return -1;
287
288 memset(&timeo, 0, sizeof(timeo));
289 timeo.tv_sec = 0;
290
291 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
292
293 errno = EPROTO;
294
295 if ((size_t) r < sizeof(*rsp))
296 return -1;
297
298 rsp = (void *) pkt;
299 if (rsp->type != BNEP_CONTROL)
300 return -1;
301
302 if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
303 goto receive;
304
305 r = ntohs(rsp->resp);
306
307 switch (r) {
308 case BNEP_SUCCESS:
309 break;
310
311 case BNEP_CONN_INVALID_DST:
312 case BNEP_CONN_INVALID_SRC:
313 case BNEP_CONN_INVALID_SVC:
314 errno = EPROTO;
315 return -1;
316
317 case BNEP_CONN_NOT_ALLOWED:
318 errno = EACCES;
319 return -1;
320 }
321
322 return bnep_connadd(sk, role, dev);
323 }
324