• 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-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