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