Git init
[framework/connectivity/bluez.git] / compat / bnep.c
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
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
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
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
120 int bnep_cleanup(void)
121 {
122         close(ctl);
123         return 0;
124 }
125
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
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
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
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
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  */
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 }