tizen 2.3.1 release
[framework/connectivity/bluez.git] / profiles / network / bnep.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 #include <sys/wait.h>
36 #include <net/if.h>
37 #include <linux/sockios.h>
38
39 #include <glib.h>
40
41 #include "lib/bluetooth.h"
42 #include "lib/l2cap.h"
43 #include "lib/bnep.h"
44 #include "lib/uuid.h"
45
46 #include "src/log.h"
47 #include "src/shared/util.h"
48 #include "btio/btio.h"
49
50 #include "bnep.h"
51
52 #define CON_SETUP_RETRIES      3
53 #define CON_SETUP_TO           9
54
55 static int ctl;
56
57 #ifdef __TIZEN_PATCH__
58 /* Compatibility with old ioctls */
59 #define OLD_BNEPCONADD      1
60 #define OLD_BNEPCONDEL      2
61 #define OLD_BNEPGETCONLIST  3
62 #define OLD_BNEPGETCONINFO  4
63
64 static unsigned long bnepconnadd;
65 static unsigned long bnepconndel;
66 static unsigned long bnepgetconnlist;
67 static unsigned long bnepgetconninfo;
68 #endif
69
70 static struct {
71         const char      *name;          /* Friendly name */
72         const char      *uuid128;       /* UUID 128 */
73         uint16_t        id;             /* Service class identifier */
74 } __svc[] = {
75         { "panu",       PANU_UUID,      BNEP_SVC_PANU   },
76         { "gn",         GN_UUID,        BNEP_SVC_GN     },
77         { "nap",        NAP_UUID,       BNEP_SVC_NAP    },
78         { NULL }
79 };
80
81 struct __service_16 {
82         uint16_t dst;
83         uint16_t src;
84 } __attribute__ ((packed));
85
86 struct bnep {
87         GIOChannel      *io;
88         uint16_t        src;
89         uint16_t        dst;
90         bdaddr_t        dst_addr;
91         char    iface[16];
92         guint   attempts;
93         guint   setup_to;
94         guint   watch;
95         bnep_connect_cb conn_cb;
96         void    *conn_data;
97         bnep_disconnect_cb disconn_cb;
98         void    *disconn_data;
99 };
100
101 const char *bnep_uuid(uint16_t id)
102 {
103         int i;
104
105         for (i = 0; __svc[i].uuid128; i++)
106                 if (__svc[i].id == id)
107                         return __svc[i].uuid128;
108         return NULL;
109 }
110
111 const char *bnep_name(uint16_t id)
112 {
113         int i;
114
115         for (i = 0; __svc[i].name; i++)
116                 if (__svc[i].id == id)
117                         return __svc[i].name;
118         return NULL;
119 }
120
121 int bnep_init(void)
122 {
123         ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
124         if (ctl < 0) {
125                 int err = -errno;
126
127                 if (err == -EPROTONOSUPPORT)
128                         warn("kernel lacks bnep-protocol support");
129                 else
130                         error("bnep: Failed to open control socket: %s (%d)",
131                                                         strerror(-err), -err);
132
133                 return err;
134         }
135 #ifdef __TIZEN_PATCH__
136 /* Temporary ioctl compatibility hack */
137 {
138         struct bnep_connlist_req req;
139         struct bnep_conninfo ci[1];
140
141         req.cnum = 1;
142         req.ci   = ci;
143
144         if (!ioctl(ctl, BNEPGETCONNLIST, &req)) {
145                 /* New ioctls */
146                 bnepconnadd     = BNEPCONNADD;
147                 bnepconndel     = BNEPCONNDEL;
148                 bnepgetconnlist = BNEPGETCONNLIST;
149                 bnepgetconninfo = BNEPGETCONNINFO;
150         } else {
151                 /* Old ioctls */
152                 bnepconnadd     = OLD_BNEPCONADD;
153                 bnepconndel     = OLD_BNEPCONDEL;
154                 bnepgetconnlist = OLD_BNEPGETCONLIST;
155                 bnepgetconninfo = OLD_BNEPGETCONINFO;
156         }
157 }
158 #endif
159         return 0;
160 }
161
162 int bnep_cleanup(void)
163 {
164         close(ctl);
165         return 0;
166 }
167
168 static int bnep_conndel(const bdaddr_t *dst)
169 {
170         struct bnep_conndel_req req;
171
172         memset(&req, 0, sizeof(req));
173         baswap((bdaddr_t *)&req.dst, dst);
174         req.flags = 0;
175         if (ioctl(ctl, BNEPCONNDEL, &req) < 0) {
176                 int err = -errno;
177                 error("bnep: Failed to kill connection: %s (%d)",
178                                                         strerror(-err), -err);
179                 return err;
180         }
181         return 0;
182 }
183
184 static int bnep_connadd(int sk, uint16_t role, char *dev)
185 {
186         struct bnep_connadd_req req;
187
188         memset(&req, 0, sizeof(req));
189         strncpy(req.device, dev, 16);
190         req.device[15] = '\0';
191
192         req.sock = sk;
193         req.role = role;
194         if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
195                 int err = -errno;
196                 error("bnep: Failed to add device %s: %s(%d)",
197                                                 dev, strerror(-err), -err);
198                 return err;
199         }
200
201         strncpy(dev, req.device, 16);
202         return 0;
203 }
204
205 static int bnep_if_up(const char *devname)
206 {
207         struct ifreq ifr;
208         int sk, err = 0;
209
210         sk = socket(AF_INET, SOCK_DGRAM, 0);
211
212         memset(&ifr, 0, sizeof(ifr));
213         strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
214
215         ifr.ifr_flags |= IFF_UP;
216         ifr.ifr_flags |= IFF_MULTICAST;
217
218         if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
219                 err = -errno;
220                 error("bnep: Could not bring up %s: %s(%d)",
221                                                 devname, strerror(-err), -err);
222         }
223
224         close(sk);
225
226         return err;
227 }
228
229 static int bnep_if_down(const char *devname)
230 {
231         struct ifreq ifr;
232         int sk, err = 0;
233
234         sk = socket(AF_INET, SOCK_DGRAM, 0);
235
236 #ifdef __TIZEN_PATCH__
237         if (sk < 0)
238                 return -1;
239 #endif
240
241         memset(&ifr, 0, sizeof(ifr));
242         strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
243
244         ifr.ifr_flags &= ~IFF_UP;
245
246         /* Bring down the interface */
247         if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
248                 err = -errno;
249                 error("bnep: Could not bring down %s: %s(%d)",
250                                                 devname, strerror(-err), -err);
251         }
252
253         close(sk);
254
255         return err;
256 }
257
258 static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
259                                                                 gpointer data)
260 {
261         struct bnep *session = data;
262
263         if (session->disconn_cb)
264                 session->disconn_cb(session->disconn_data);
265
266         return FALSE;
267 }
268
269 static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
270                                                                 gpointer data)
271 {
272         struct bnep *session = data;
273         struct bnep_control_rsp *rsp;
274         struct timeval timeo;
275         char pkt[BNEP_MTU];
276         ssize_t r;
277         int sk;
278
279         if (cond & G_IO_NVAL)
280                 return FALSE;
281
282         if (session->setup_to > 0) {
283                 g_source_remove(session->setup_to);
284                 session->setup_to = 0;
285         }
286
287         if (cond & (G_IO_HUP | G_IO_ERR)) {
288                 error("bnep: Hangup or error on l2cap server socket");
289                 goto failed;
290         }
291
292         sk = g_io_channel_unix_get_fd(chan);
293         memset(pkt, 0, BNEP_MTU);
294         r = read(sk, pkt, sizeof(pkt) - 1);
295         if (r < 0) {
296                 error("bnep: IO Channel read error");
297                 goto failed;
298         }
299
300         if (r == 0) {
301                 error("bnep: No packet received on l2cap socket");
302                 goto failed;
303         }
304
305         errno = EPROTO;
306
307         if ((size_t) r < sizeof(*rsp)) {
308                 error("bnep: Packet received is not bnep type");
309                 goto failed;
310         }
311
312         rsp = (void *) pkt;
313         if (rsp->type != BNEP_CONTROL) {
314                 error("bnep: Packet received is not bnep type");
315                 goto failed;
316         }
317
318         if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
319                 return TRUE;
320
321         r = ntohs(rsp->resp);
322         if (r != BNEP_SUCCESS) {
323                 error("bnep: failed");
324                 goto failed;
325         }
326
327         memset(&timeo, 0, sizeof(timeo));
328         timeo.tv_sec = 0;
329         setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
330
331         sk = g_io_channel_unix_get_fd(session->io);
332         if (bnep_connadd(sk, session->src, session->iface) < 0)
333                 goto failed;
334
335         if (bnep_if_up(session->iface) < 0) {
336                 bnep_conndel(&session->dst_addr);
337                 goto failed;
338         }
339
340         session->watch = g_io_add_watch(session->io,
341                                         G_IO_ERR | G_IO_HUP | G_IO_NVAL,
342                                         (GIOFunc) bnep_watchdog_cb, session);
343         g_io_channel_unref(session->io);
344         session->io = NULL;
345
346         session->conn_cb(session->iface, 0, session->conn_data);
347
348         return FALSE;
349
350 failed:
351         session->conn_cb(NULL, -EIO, session->conn_data);
352
353         return FALSE;
354 }
355
356 static int bnep_setup_conn_req(struct bnep *session)
357 {
358         struct bnep_setup_conn_req *req;
359         struct __service_16 *s;
360         unsigned char pkt[BNEP_MTU];
361         int fd;
362
363         /* Send request */
364         req = (void *) pkt;
365         req->type = BNEP_CONTROL;
366         req->ctrl = BNEP_SETUP_CONN_REQ;
367         req->uuid_size = 2;     /* 16bit UUID */
368         s = (void *) req->service;
369         s->src = htons(session->src);
370         s->dst = htons(session->dst);
371
372         fd = g_io_channel_unix_get_fd(session->io);
373         if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
374                 error("bnep: connection req send failed: %s", strerror(errno));
375                 return -errno;
376         }
377
378         session->attempts++;
379
380         return 0;
381 }
382
383 static gboolean bnep_conn_req_to(gpointer user_data)
384 {
385         struct bnep *session = user_data;
386
387         if (session->attempts == CON_SETUP_RETRIES) {
388                 error("bnep: Too many bnep connection attempts");
389         } else {
390                 error("bnep: connection setup TO, retrying...");
391                 if (bnep_setup_conn_req(session) == 0)
392                         return TRUE;
393         }
394
395         session->conn_cb(NULL, -ETIMEDOUT, session->conn_data);
396
397         return FALSE;
398 }
399
400 struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
401                                                                 char *iface)
402 {
403         struct bnep *session;
404         int dup_fd;
405
406         dup_fd = dup(sk);
407         if (dup_fd < 0)
408                 return NULL;
409
410         session = g_new0(struct bnep, 1);
411         session->io = g_io_channel_unix_new(dup_fd);
412         session->src = local_role;
413         session->dst = remote_role;
414         strncpy(session->iface, iface, 16);
415         session->iface[15] = '\0';
416
417         g_io_channel_set_close_on_unref(session->io, TRUE);
418         session->watch = g_io_add_watch(session->io,
419                                 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
420                                         (GIOFunc) bnep_setup_cb, session);
421
422         return session;
423 }
424
425 void bnep_free(struct bnep *session)
426 {
427         if (!session)
428                 return;
429
430         if (session->io) {
431                 g_io_channel_shutdown(session->io, FALSE, NULL);
432                 g_io_channel_unref(session->io);
433                 session->io = NULL;
434         }
435
436         if (session->watch > 0) {
437                 g_source_remove(session->watch);
438                 session->watch = 0;
439         }
440
441         g_free(session);
442 }
443
444 int bnep_connect(struct bnep *session, bnep_connect_cb conn_cb, void *data)
445 {
446         GError *gerr = NULL;
447         int err;
448
449         if (!session || !conn_cb)
450                 return -EINVAL;
451
452         session->attempts = 0;
453         session->conn_cb = conn_cb;
454         session->conn_data = data;
455
456         bt_io_get(session->io, &gerr, BT_IO_OPT_DEST_BDADDR, &session->dst_addr,
457                                                         BT_IO_OPT_INVALID);
458         if (gerr) {
459                 error("bnep: connect failed: %s", gerr->message);
460                 g_error_free(gerr);
461                 return -EINVAL;
462         }
463
464         err = bnep_setup_conn_req(session);
465         if (err < 0)
466                 return err;
467
468         session->setup_to = g_timeout_add_seconds(CON_SETUP_TO,
469                                                 bnep_conn_req_to, session);
470         return 0;
471 }
472
473 void bnep_disconnect(struct bnep *session)
474 {
475         if (!session)
476                 return;
477
478 #ifndef __TIZEN_PATCH__
479         if (session->watch > 0) {
480                 g_source_remove(session->watch);
481                 session->watch = 0;
482         }
483 #endif
484         if (session->io) {
485                 g_io_channel_unref(session->io);
486                 session->io = NULL;
487         }
488
489         bnep_if_down(session->iface);
490         bnep_conndel(&session->dst_addr);
491 }
492
493 void bnep_set_disconnect(struct bnep *session, bnep_disconnect_cb disconn_cb,
494                                                                 void *data)
495 {
496         if (!session || !disconn_cb)
497                 return;
498
499         if (!session->disconn_cb && !session->disconn_data) {
500                 session->disconn_cb = disconn_cb;
501                 session->disconn_data = data;
502         }
503 }
504
505 #ifndef  __TIZEN_PATCH__
506 static int bnep_add_to_bridge(const char *devname, const char *bridge)
507 {
508         int ifindex;
509         struct ifreq ifr;
510         int sk, err = 0;
511
512         if (!devname || !bridge)
513                 return -EINVAL;
514
515         ifindex = if_nametoindex(devname);
516
517         sk = socket(AF_INET, SOCK_STREAM, 0);
518         if (sk < 0)
519                 return -1;
520 #ifdef  __TIZEN_PATCH__
521         err = ioctl(sk, SIOCBRADDBR, bridge);
522         if (err < 0)
523         {
524                 info("bridge create err: %d", err);
525                 close(sk);
526                 return -errno;
527         }
528 #endif
529         memset(&ifr, 0, sizeof(ifr));
530         strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
531         ifr.ifr_ifindex = ifindex;
532
533         if (ioctl(sk, SIOCBRADDIF, &ifr) < 0) {
534                 err = -errno;
535                 error("bnep: Can't add %s to the bridge %s: %s(%d)",
536                                         devname, bridge, strerror(-err), -err);
537         } else {
538                 info("bnep: bridge %s: interface %s added", bridge, devname);
539         }
540
541         close(sk);
542
543         return err;
544 }
545 #endif
546
547 static int bnep_del_from_bridge(const char *devname, const char *bridge)
548 {
549         int ifindex;
550         struct ifreq ifr;
551         int sk, err = 0;
552
553         if (!devname || !bridge)
554                 return -EINVAL;
555
556         ifindex = if_nametoindex(devname);
557
558         sk = socket(AF_INET, SOCK_STREAM, 0);
559         if (sk < 0)
560                 return -1;
561
562         memset(&ifr, 0, sizeof(ifr));
563         strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
564         ifr.ifr_ifindex = ifindex;
565
566         if (ioctl(sk, SIOCBRDELIF, &ifr) < 0) {
567                 err = -errno;
568                 error("bnep: Can't delete %s from the bridge %s: %s(%d)",
569                                         devname, bridge, strerror(-err), -err);
570         } else {
571                 info("bnep: bridge %s: interface %s removed", bridge, devname);
572         }
573
574         close(sk);
575
576         return err;
577 }
578
579 int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
580                                                 const bdaddr_t *addr)
581 {
582         int err;
583
584         if (!bridge || !iface || !addr)
585                 return -EINVAL;
586
587         err = bnep_connadd(sk, dst, iface);
588         if (err < 0)
589                 return err;
590
591 #ifndef  __TIZEN_PATCH__
592         err = bnep_add_to_bridge(iface, bridge);
593         if (err < 0) {
594                 bnep_conndel(addr);
595                 return err;
596         }
597 #endif
598
599         return bnep_if_up(iface);
600 }
601
602 void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr)
603 {
604         if (!bridge || !iface || !addr)
605                 return;
606
607         bnep_del_from_bridge(iface, bridge);
608         bnep_if_down(iface);
609         bnep_conndel(addr);
610 }
611
612 ssize_t bnep_send_ctrl_rsp(int sk, uint8_t type, uint8_t ctrl, uint16_t resp)
613 {
614         struct bnep_control_rsp rsp;
615
616         rsp.type = type;
617         rsp.ctrl = ctrl;
618         rsp.resp = htons(resp);
619
620         return send(sk, &rsp, sizeof(rsp), 0);
621 }
622
623 uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
624                                                                 uint16_t *src)
625 {
626         const uint8_t bt_base[] = { 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
627                                         0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
628         uint8_t *dest, *source;
629         uint32_t val;
630
631         dest = req->service;
632         source = req->service + req->uuid_size;
633
634         switch (req->uuid_size) {
635         case 2: /* UUID16 */
636                 *dst = get_be16(dest);
637                 *src = get_be16(source);
638                 break;
639         case 16: /* UUID128 */
640                 /* Check that the bytes in the UUID, except the service ID
641                  * itself, are correct. The service ID is checked in
642                  * bnep_setup_chk(). */
643                 if (memcmp(&dest[4], bt_base, sizeof(bt_base)) != 0)
644                         return BNEP_CONN_INVALID_DST;
645                 if (memcmp(&source[4], bt_base, sizeof(bt_base)) != 0)
646                         return BNEP_CONN_INVALID_SRC;
647
648                 /* Intentional no-break */
649
650         case 4: /* UUID32 */
651                 val = get_be32(dest);
652                 if (val > 0xffff)
653                         return BNEP_CONN_INVALID_DST;
654
655                 *dst = val;
656
657                 val = get_be32(source);
658                 if (val > 0xffff)
659                         return BNEP_CONN_INVALID_SRC;
660
661                 *src = val;
662                 break;
663         default:
664                 return BNEP_CONN_INVALID_SVC;
665         }
666
667         /* Allowed PAN Profile scenarios */
668         switch (*dst) {
669         case BNEP_SVC_NAP:
670         case BNEP_SVC_GN:
671                 if (*src == BNEP_SVC_PANU)
672                         return BNEP_SUCCESS;
673                 return BNEP_CONN_INVALID_SRC;
674         case BNEP_SVC_PANU:
675                 if (*src == BNEP_SVC_PANU || *src == BNEP_SVC_GN ||
676                                                         *src == BNEP_SVC_NAP)
677                         return BNEP_SUCCESS;
678
679                 return BNEP_CONN_INVALID_SRC;
680         }
681
682         return BNEP_CONN_INVALID_DST;
683 }
684
685 #ifdef  __TIZEN_PATCH__
686 int bnep_if_down_wrapper(const char *devname)
687 {
688         bnep_if_down(devname);
689         return 0;
690 }
691
692 int bnep_conndel_wrapper(const bdaddr_t *dst)
693 {
694         bnep_conndel(dst);
695         return 0;
696 }
697 #endif
698