Upgrade bluez5_37 :Merge the code from private
[platform/upstream/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 struct __service_16 {
71         uint16_t dst;
72         uint16_t src;
73 } __attribute__ ((packed));
74
75 struct bnep {
76         GIOChannel      *io;
77         uint16_t        src;
78         uint16_t        dst;
79         bdaddr_t        dst_addr;
80         char    iface[16];
81         guint   attempts;
82         guint   setup_to;
83         guint   watch;
84         bnep_connect_cb conn_cb;
85         void    *conn_data;
86         bnep_disconnect_cb disconn_cb;
87         void    *disconn_data;
88 };
89
90 int bnep_init(void)
91 {
92         ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
93         if (ctl < 0) {
94                 int err = -errno;
95
96                 if (err == -EPROTONOSUPPORT)
97                         warn("kernel lacks bnep-protocol support");
98                 else
99                         error("bnep: Failed to open control socket: %s (%d)",
100                                                         strerror(-err), -err);
101
102                 return err;
103         }
104 #ifdef __TIZEN_PATCH__
105 /* Temporary ioctl compatibility hack */
106 {
107         struct bnep_connlist_req req;
108         struct bnep_conninfo ci[1];
109
110         req.cnum = 1;
111         req.ci   = ci;
112
113         if (!ioctl(ctl, BNEPGETCONNLIST, &req)) {
114                 /* New ioctls */
115                 bnepconnadd     = BNEPCONNADD;
116                 bnepconndel     = BNEPCONNDEL;
117                 bnepgetconnlist = BNEPGETCONNLIST;
118                 bnepgetconninfo = BNEPGETCONNINFO;
119         } else {
120                 /* Old ioctls */
121                 bnepconnadd     = OLD_BNEPCONADD;
122                 bnepconndel     = OLD_BNEPCONDEL;
123                 bnepgetconnlist = OLD_BNEPGETCONLIST;
124                 bnepgetconninfo = OLD_BNEPGETCONINFO;
125         }
126 }
127 #endif
128         return 0;
129 }
130
131 int bnep_cleanup(void)
132 {
133         close(ctl);
134         return 0;
135 }
136
137 static int bnep_conndel(const bdaddr_t *dst)
138 {
139         struct bnep_conndel_req req;
140
141         memset(&req, 0, sizeof(req));
142         baswap((bdaddr_t *)&req.dst, dst);
143         req.flags = 0;
144         if (ioctl(ctl, BNEPCONNDEL, &req) < 0) {
145                 int err = -errno;
146                 error("bnep: Failed to kill connection: %s (%d)",
147                                                         strerror(-err), -err);
148                 return err;
149         }
150         return 0;
151 }
152
153 static int bnep_connadd(int sk, uint16_t role, char *dev)
154 {
155         struct bnep_connadd_req req;
156
157         memset(&req, 0, sizeof(req));
158         strncpy(req.device, dev, 16);
159         req.device[15] = '\0';
160
161         req.sock = sk;
162         req.role = role;
163         req.flags = (1 << BNEP_SETUP_RESPONSE);
164         if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
165                 int err = -errno;
166                 error("bnep: Failed to add device %s: %s(%d)",
167                                                 dev, strerror(-err), -err);
168                 return err;
169         }
170
171         strncpy(dev, req.device, 16);
172         return 0;
173 }
174
175 static uint32_t bnep_getsuppfeat(void)
176 {
177         uint32_t feat;
178
179         if (ioctl(ctl, BNEPGETSUPPFEAT, &feat) < 0)
180                 feat = 0;
181
182         DBG("supported features: 0x%x", feat);
183
184         return feat;
185 }
186
187 static int bnep_if_up(const char *devname)
188 {
189         struct ifreq ifr;
190         int sk, err = 0;
191
192         sk = socket(AF_INET, SOCK_DGRAM, 0);
193
194         memset(&ifr, 0, sizeof(ifr));
195         strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
196
197         ifr.ifr_flags |= IFF_UP;
198         ifr.ifr_flags |= IFF_MULTICAST;
199
200         if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
201                 err = -errno;
202                 error("bnep: Could not bring up %s: %s(%d)",
203                                                 devname, strerror(-err), -err);
204         }
205
206         close(sk);
207
208         return err;
209 }
210
211 static int bnep_if_down(const char *devname)
212 {
213         struct ifreq ifr;
214         int sk, err = 0;
215
216         sk = socket(AF_INET, SOCK_DGRAM, 0);
217
218 #ifdef __TIZEN_PATCH__
219         if (sk < 0)
220                 return -1;
221 #endif
222
223         memset(&ifr, 0, sizeof(ifr));
224         strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
225
226         ifr.ifr_flags &= ~IFF_UP;
227
228         /* Bring down the interface */
229         if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
230                 err = -errno;
231                 error("bnep: Could not bring down %s: %s(%d)",
232                                                 devname, strerror(-err), -err);
233         }
234
235         close(sk);
236
237         return err;
238 }
239
240 static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
241                                                                 gpointer data)
242 {
243         struct bnep *session = data;
244
245         if (session->disconn_cb)
246                 session->disconn_cb(session->disconn_data);
247
248         return FALSE;
249 }
250
251 static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
252                                                                 gpointer data)
253 {
254         struct bnep *session = data;
255         struct bnep_control_rsp *rsp;
256         struct timeval timeo;
257         char pkt[BNEP_MTU];
258         ssize_t r;
259         int sk;
260
261         if (cond & G_IO_NVAL)
262                 return FALSE;
263
264         if (session->setup_to > 0) {
265                 g_source_remove(session->setup_to);
266                 session->setup_to = 0;
267         }
268
269         if (cond & (G_IO_HUP | G_IO_ERR)) {
270                 error("bnep: Hangup or error on l2cap server socket");
271                 goto failed;
272         }
273
274         sk = g_io_channel_unix_get_fd(chan);
275         memset(pkt, 0, BNEP_MTU);
276         r = read(sk, pkt, sizeof(pkt) - 1);
277         if (r < 0) {
278                 error("bnep: IO Channel read error");
279                 goto failed;
280         }
281
282         if (r == 0) {
283                 error("bnep: No packet received on l2cap socket");
284                 goto failed;
285         }
286
287         errno = EPROTO;
288
289         if ((size_t) r < sizeof(*rsp)) {
290                 error("bnep: Packet received is not bnep type");
291                 goto failed;
292         }
293
294         rsp = (void *) pkt;
295         if (rsp->type != BNEP_CONTROL) {
296                 error("bnep: Packet received is not bnep type");
297                 goto failed;
298         }
299
300         if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
301                 return TRUE;
302
303         r = ntohs(rsp->resp);
304         if (r != BNEP_SUCCESS) {
305                 error("bnep: failed");
306                 goto failed;
307         }
308
309         memset(&timeo, 0, sizeof(timeo));
310         timeo.tv_sec = 0;
311         setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
312
313         sk = g_io_channel_unix_get_fd(session->io);
314         if (bnep_connadd(sk, session->src, session->iface) < 0)
315                 goto failed;
316
317         if (bnep_if_up(session->iface) < 0) {
318                 bnep_conndel(&session->dst_addr);
319                 goto failed;
320         }
321
322         session->watch = g_io_add_watch(session->io,
323                                         G_IO_ERR | G_IO_HUP | G_IO_NVAL,
324                                         (GIOFunc) bnep_watchdog_cb, session);
325         g_io_channel_unref(session->io);
326         session->io = NULL;
327
328         session->conn_cb(session->iface, 0, session->conn_data);
329
330         return FALSE;
331
332 failed:
333         session->conn_cb(NULL, -EIO, session->conn_data);
334
335         return FALSE;
336 }
337
338 static int bnep_setup_conn_req(struct bnep *session)
339 {
340         struct bnep_setup_conn_req *req;
341         struct __service_16 *s;
342         unsigned char pkt[BNEP_MTU];
343         int fd;
344
345         /* Send request */
346         req = (void *) pkt;
347         req->type = BNEP_CONTROL;
348         req->ctrl = BNEP_SETUP_CONN_REQ;
349         req->uuid_size = 2;     /* 16bit UUID */
350         s = (void *) req->service;
351         s->src = htons(session->src);
352         s->dst = htons(session->dst);
353
354         fd = g_io_channel_unix_get_fd(session->io);
355         if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
356                 error("bnep: connection req send failed: %s", strerror(errno));
357                 return -errno;
358         }
359
360         session->attempts++;
361
362         return 0;
363 }
364
365 static gboolean bnep_conn_req_to(gpointer user_data)
366 {
367         struct bnep *session = user_data;
368
369         if (session->attempts == CON_SETUP_RETRIES) {
370                 error("bnep: Too many bnep connection attempts");
371         } else {
372                 error("bnep: connection setup TO, retrying...");
373                 if (bnep_setup_conn_req(session) == 0)
374                         return TRUE;
375         }
376
377         session->conn_cb(NULL, -ETIMEDOUT, session->conn_data);
378
379         return FALSE;
380 }
381
382 struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
383                                                                 char *iface)
384 {
385         struct bnep *session;
386         int dup_fd;
387
388         dup_fd = dup(sk);
389         if (dup_fd < 0)
390                 return NULL;
391
392         session = g_new0(struct bnep, 1);
393         session->io = g_io_channel_unix_new(dup_fd);
394         session->src = local_role;
395         session->dst = remote_role;
396         strncpy(session->iface, iface, 16);
397         session->iface[15] = '\0';
398
399         g_io_channel_set_close_on_unref(session->io, TRUE);
400         session->watch = g_io_add_watch(session->io,
401                                 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
402                                         (GIOFunc) bnep_setup_cb, session);
403
404         return session;
405 }
406
407 void bnep_free(struct bnep *session)
408 {
409         if (!session)
410                 return;
411
412         if (session->io) {
413                 g_io_channel_shutdown(session->io, FALSE, NULL);
414                 g_io_channel_unref(session->io);
415                 session->io = NULL;
416         }
417
418         if (session->watch > 0) {
419                 g_source_remove(session->watch);
420                 session->watch = 0;
421         }
422
423         g_free(session);
424 }
425
426 int bnep_connect(struct bnep *session, bnep_connect_cb conn_cb,
427                                         bnep_disconnect_cb disconn_cb,
428                                         void *conn_data, void *disconn_data)
429 {
430         GError *gerr = NULL;
431         int err;
432
433         if (!session || !conn_cb || !disconn_cb)
434                 return -EINVAL;
435
436         session->attempts = 0;
437         session->conn_cb = conn_cb;
438         session->disconn_cb = disconn_cb;
439         session->conn_data = conn_data;
440         session->disconn_data = disconn_data;
441
442         bt_io_get(session->io, &gerr, BT_IO_OPT_DEST_BDADDR, &session->dst_addr,
443                                                         BT_IO_OPT_INVALID);
444         if (gerr) {
445                 error("bnep: connect failed: %s", gerr->message);
446                 g_error_free(gerr);
447                 return -EINVAL;
448         }
449
450         err = bnep_setup_conn_req(session);
451         if (err < 0)
452                 return err;
453
454         session->setup_to = g_timeout_add_seconds(CON_SETUP_TO,
455                                                 bnep_conn_req_to, session);
456         return 0;
457 }
458
459 void bnep_disconnect(struct bnep *session)
460 {
461         if (!session)
462                 return;
463
464 #ifndef __TIZEN_PATCH__
465         if (session->watch > 0) {
466                 g_source_remove(session->watch);
467                 session->watch = 0;
468         }
469 #endif
470         if (session->io) {
471                 g_io_channel_unref(session->io);
472                 session->io = NULL;
473         }
474
475         bnep_if_down(session->iface);
476         bnep_conndel(&session->dst_addr);
477 }
478
479 #ifndef  __TIZEN_PATCH__
480 static int bnep_add_to_bridge(const char *devname, const char *bridge)
481 {
482         int ifindex;
483         struct ifreq ifr;
484         int sk, err = 0;
485
486         if (!devname || !bridge)
487                 return -EINVAL;
488
489         ifindex = if_nametoindex(devname);
490
491         sk = socket(AF_INET, SOCK_STREAM, 0);
492         if (sk < 0)
493                 return -1;
494 #ifdef  __TIZEN_PATCH__
495         err = ioctl(sk, SIOCBRADDBR, bridge);
496         if (err < 0)
497         {
498                 info("bridge create err: %d", err);
499                 close(sk);
500                 return -errno;
501         }
502 #endif
503         memset(&ifr, 0, sizeof(ifr));
504         strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
505         ifr.ifr_ifindex = ifindex;
506
507         if (ioctl(sk, SIOCBRADDIF, &ifr) < 0) {
508                 err = -errno;
509                 error("bnep: Can't add %s to the bridge %s: %s(%d)",
510                                         devname, bridge, strerror(-err), -err);
511         } else {
512                 info("bnep: bridge %s: interface %s added", bridge, devname);
513         }
514
515         close(sk);
516
517         return err;
518 }
519 #endif
520
521 static int bnep_del_from_bridge(const char *devname, const char *bridge)
522 {
523         int ifindex;
524         struct ifreq ifr;
525         int sk, err = 0;
526
527         if (!devname || !bridge)
528                 return -EINVAL;
529
530         ifindex = if_nametoindex(devname);
531
532         sk = socket(AF_INET, SOCK_STREAM, 0);
533         if (sk < 0)
534                 return -1;
535
536         memset(&ifr, 0, sizeof(ifr));
537         strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
538         ifr.ifr_ifindex = ifindex;
539
540         if (ioctl(sk, SIOCBRDELIF, &ifr) < 0) {
541                 err = -errno;
542                 error("bnep: Can't delete %s from the bridge %s: %s(%d)",
543                                         devname, bridge, strerror(-err), -err);
544         } else {
545                 info("bnep: bridge %s: interface %s removed", bridge, devname);
546         }
547
548         close(sk);
549
550         return err;
551 }
552
553 static ssize_t bnep_send_ctrl_rsp(int sk, uint8_t ctrl, uint16_t resp)
554 {
555         ssize_t sent;
556
557         switch (ctrl) {
558         case BNEP_CMD_NOT_UNDERSTOOD: {
559                 struct bnep_ctrl_cmd_not_understood_cmd rsp;
560
561                 rsp.type = BNEP_CONTROL;
562                 rsp.ctrl = ctrl;
563                 rsp.unkn_ctrl = (uint8_t) resp;
564
565                 sent = send(sk, &rsp, sizeof(rsp), 0);
566                 break;
567         }
568         case BNEP_FILTER_MULT_ADDR_RSP:
569         case BNEP_FILTER_NET_TYPE_RSP:
570         case BNEP_SETUP_CONN_RSP: {
571                 struct bnep_control_rsp rsp;
572
573                 rsp.type = BNEP_CONTROL;
574                 rsp.ctrl = ctrl;
575                 rsp.resp = htons(resp);
576
577                 sent = send(sk, &rsp, sizeof(rsp), 0);
578                 break;
579         }
580         default:
581                 error("bnep: wrong response type");
582                 sent = -1;
583                 break;
584         }
585
586         return sent;
587 }
588
589 static uint16_t bnep_setup_decode(int sk, struct bnep_setup_conn_req *req,
590                                                                 uint16_t *dst)
591 {
592         const uint8_t bt_base[] = { 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
593                                         0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
594         uint16_t src;
595         uint8_t *dest, *source;
596         uint32_t val;
597
598         if (((req->type != BNEP_CONTROL) &&
599                 (req->type != (BNEP_CONTROL | BNEP_EXT_HEADER)))  ||
600                                         req->ctrl != BNEP_SETUP_CONN_REQ)
601                 return BNEP_CONN_NOT_ALLOWED;
602
603         dest = req->service;
604         source = req->service + req->uuid_size;
605
606         switch (req->uuid_size) {
607         case 2: /* UUID16 */
608                 *dst = get_be16(dest);
609                 src = get_be16(source);
610                 break;
611         case 16: /* UUID128 */
612                 /* Check that the bytes in the UUID, except the service ID
613                  * itself, are correct. The service ID is checked in
614                  * bnep_setup_chk(). */
615                 if (memcmp(&dest[4], bt_base, sizeof(bt_base)) != 0)
616                         return BNEP_CONN_INVALID_DST;
617                 if (memcmp(&source[4], bt_base, sizeof(bt_base)) != 0)
618                         return BNEP_CONN_INVALID_SRC;
619
620                 /* Intentional no-break */
621
622         case 4: /* UUID32 */
623                 val = get_be32(dest);
624                 if (val > 0xffff)
625                         return BNEP_CONN_INVALID_DST;
626
627                 *dst = val;
628
629                 val = get_be32(source);
630                 if (val > 0xffff)
631                         return BNEP_CONN_INVALID_SRC;
632
633                 src = val;
634                 break;
635         default:
636                 return BNEP_CONN_INVALID_SVC;
637         }
638
639         /* Allowed PAN Profile scenarios */
640         switch (*dst) {
641         case BNEP_SVC_NAP:
642         case BNEP_SVC_GN:
643                 if (src == BNEP_SVC_PANU)
644                         return BNEP_SUCCESS;
645                 return BNEP_CONN_INVALID_SRC;
646         case BNEP_SVC_PANU:
647                 if (src == BNEP_SVC_PANU || src == BNEP_SVC_GN ||
648                                                         src == BNEP_SVC_NAP)
649                         return BNEP_SUCCESS;
650
651                 return BNEP_CONN_INVALID_SRC;
652         }
653
654         return BNEP_CONN_INVALID_DST;
655 }
656
657 #ifdef  __TIZEN_PATCH__
658 int bnep_if_down_wrapper(const char *devname)
659 {
660         bnep_if_down(devname);
661         return 0;
662 }
663
664 int bnep_conndel_wrapper(const bdaddr_t *dst)
665 {
666         bnep_conndel(dst);
667         return 0;
668 }
669 #endif
670
671 static int bnep_server_add_legacy(int sk, uint16_t dst, char *bridge,
672                                         char *iface, const bdaddr_t *addr,
673                                         uint8_t *setup_data, int len)
674 {
675         int err, n;
676         uint16_t rsp;
677
678         n = read(sk, setup_data, len);
679         if (n != len) {
680                 err = -EIO;
681                 rsp = BNEP_CONN_NOT_ALLOWED;
682                 goto reply;
683         }
684
685         err = bnep_connadd(sk, dst, iface);
686         if (err < 0) {
687                 rsp = BNEP_CONN_NOT_ALLOWED;
688                 goto reply;
689         }
690
691 #ifndef  __TIZEN_PATCH__
692         err = bnep_add_to_bridge(iface, bridge);
693         if (err < 0) {
694                 bnep_conndel(addr);
695                 rsp = BNEP_CONN_NOT_ALLOWED;
696                 goto reply;
697         }
698 #endif
699
700         err = bnep_if_up(iface);
701         if (err < 0) {
702                 bnep_del_from_bridge(iface, bridge);
703                 bnep_conndel(addr);
704                 rsp = BNEP_CONN_NOT_ALLOWED;
705                 goto reply;
706         }
707
708         rsp = BNEP_SUCCESS;
709
710 reply:
711         if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
712                 err = -errno;
713                 error("bnep: send ctrl rsp error: %s (%d)", strerror(-err),
714                                                                         -err);
715         }
716
717         return err;
718 }
719
720 int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t *addr,
721                                                 uint8_t *setup_data, int len)
722 {
723         int err;
724         uint32_t feat;
725         uint16_t rsp, dst;
726         struct bnep_setup_conn_req *req = (void *) setup_data;
727
728         /* Highest known Control command ID
729          * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */
730         if (req->type == BNEP_CONTROL &&
731                                         req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
732                 error("bnep: cmd not understood");
733                 err = bnep_send_ctrl_rsp(sk, BNEP_CMD_NOT_UNDERSTOOD,
734                                                                 req->ctrl);
735                 if (err < 0)
736                         error("send not understood ctrl rsp error: %s (%d)",
737                                                         strerror(errno), errno);
738
739                 return err;
740         }
741
742         /* Processing BNEP_SETUP_CONNECTION_REQUEST_MSG */
743         rsp = bnep_setup_decode(sk, req, &dst);
744         if (rsp != BNEP_SUCCESS) {
745                 err = -rsp;
746                 error("bnep: error while decoding setup connection request: %d",
747                                                                         rsp);
748                 goto failed;
749         }
750
751         feat = bnep_getsuppfeat();
752
753         /*
754          * Take out setup data if kernel doesn't support handling it, especially
755          * setup request. If kernel would have set session flags, they should
756          * be checked and handled respectively.
757          */
758         if (!feat || !(feat & (1 << BNEP_SETUP_RESPONSE)))
759                 return bnep_server_add_legacy(sk, dst, bridge, iface, addr,
760                                                         setup_data, len);
761
762         err = bnep_connadd(sk, dst, iface);
763         if (err < 0) {
764                 rsp = BNEP_CONN_NOT_ALLOWED;
765                 goto failed;
766         }
767
768 #ifndef  __TIZEN_PATCH__
769         err = bnep_add_to_bridge(iface, bridge);
770         if (err < 0)
771                 goto failed_conn;
772 #endif
773
774         err = bnep_if_up(iface);
775         if (err < 0)
776                 goto failed_bridge;
777
778         return 0;
779
780 failed_bridge:
781         bnep_del_from_bridge(iface, bridge);
782
783 failed_conn:
784         bnep_conndel(addr);
785
786         return err;
787
788 failed:
789         if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
790                 err = -errno;
791                 error("bnep: send ctrl rsp error: %s (%d)", strerror(-err),
792                                                                         -err);
793         }
794
795         return err;
796 }
797
798 void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr)
799 {
800         if (!bridge || !iface || !addr)
801                 return;
802
803         bnep_del_from_bridge(iface, bridge);
804         bnep_if_down(iface);
805         bnep_conndel(addr);
806 }