Fix the bug : TIVI-204 Fail to connect to bluetooth network
[profile/ivi/bluez.git] / network / server.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 <unistd.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #include <bluetooth/bluetooth.h>
34 #include <bluetooth/bnep.h>
35 #include <bluetooth/sdp.h>
36 #include <bluetooth/sdp_lib.h>
37 #include <bluetooth/uuid.h>
38 #include <netinet/in.h>
39
40 #include <glib.h>
41 #include <gdbus.h>
42
43 #include "../src/dbus-common.h"
44 #include "../src/adapter.h"
45
46 #include "log.h"
47 #include "error.h"
48 #include "sdpd.h"
49 #include "btio.h"
50
51 #include "common.h"
52 #include "server.h"
53
54 #define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer"
55 #define SETUP_TIMEOUT           1
56
57 /* Pending Authorization */
58 struct network_session {
59         bdaddr_t        dst;            /* Remote Bluetooth Address */
60         GIOChannel      *io;            /* Pending connect channel */
61         guint           watch;          /* BNEP socket watch */
62 };
63
64 struct network_adapter {
65         struct btd_adapter *adapter;    /* Adapter pointer */
66         GIOChannel      *io;            /* Bnep socket */
67         struct network_session *setup;  /* Setup in progress */
68         GSList          *servers;       /* Server register to adapter */
69 };
70
71 /* Main server structure */
72 struct network_server {
73         bdaddr_t        src;            /* Bluetooth Local Address */
74         char            *iface;         /* DBus interface */
75         char            *name;          /* Server service name */
76         char            *bridge;        /* Bridge name */
77         uint32_t        record_id;      /* Service record id */
78         uint16_t        id;             /* Service class identifier */
79         GSList          *sessions;      /* Active connections */
80         struct network_adapter *na;     /* Adapter reference */
81         guint           watch_id;       /* Client service watch */
82 };
83
84 static DBusConnection *connection = NULL;
85 static GSList *adapters = NULL;
86 static gboolean security = TRUE;
87
88 static struct network_adapter *find_adapter(GSList *list,
89                                         struct btd_adapter *adapter)
90 {
91         for (; list; list = list->next) {
92                 struct network_adapter *na = list->data;
93
94                 if (na->adapter == adapter)
95                         return na;
96         }
97
98         return NULL;
99 }
100
101 static struct network_server *find_server(GSList *list, uint16_t id)
102 {
103         for (; list; list = list->next) {
104                 struct network_server *ns = list->data;
105
106                 if (ns->id == id)
107                         return ns;
108         }
109
110         return NULL;
111 }
112
113 static sdp_record_t *server_record_new(const char *name, uint16_t id)
114 {
115         sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
116         uuid_t root_uuid, pan, l2cap, bnep;
117         sdp_profile_desc_t profile[1];
118         sdp_list_t *proto[2];
119         sdp_data_t *v, *p;
120         uint16_t psm = BNEP_PSM, version = 0x0100;
121         uint16_t security_desc = (security ? 0x0001 : 0x0000);
122         uint16_t net_access_type = 0xfffe;
123         uint32_t max_net_access_rate = 0;
124         const char *desc = "Network service";
125         sdp_record_t *record;
126
127         record = sdp_record_alloc();
128         if (!record)
129                 return NULL;
130
131         record->attrlist = NULL;
132         record->pattern = NULL;
133
134         switch (id) {
135         case BNEP_SVC_NAP:
136                 sdp_uuid16_create(&pan, NAP_SVCLASS_ID);
137                 svclass = sdp_list_append(NULL, &pan);
138                 sdp_set_service_classes(record, svclass);
139
140                 sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
141                 profile[0].version = 0x0100;
142                 pfseq = sdp_list_append(NULL, &profile[0]);
143                 sdp_set_profile_descs(record, pfseq);
144
145                 sdp_set_info_attr(record, name, NULL, desc);
146
147                 sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE,
148                                         SDP_UINT16, &net_access_type);
149                 sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE,
150                                         SDP_UINT32, &max_net_access_rate);
151                 break;
152         case BNEP_SVC_GN:
153                 sdp_uuid16_create(&pan, GN_SVCLASS_ID);
154                 svclass = sdp_list_append(NULL, &pan);
155                 sdp_set_service_classes(record, svclass);
156
157                 sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
158                 profile[0].version = 0x0100;
159                 pfseq = sdp_list_append(NULL, &profile[0]);
160                 sdp_set_profile_descs(record, pfseq);
161
162                 sdp_set_info_attr(record, name, NULL, desc);
163                 break;
164         case BNEP_SVC_PANU:
165                 sdp_uuid16_create(&pan, PANU_SVCLASS_ID);
166                 svclass = sdp_list_append(NULL, &pan);
167                 sdp_set_service_classes(record, svclass);
168
169                 sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
170                 profile[0].version = 0x0100;
171                 pfseq = sdp_list_append(NULL, &profile[0]);
172                 sdp_set_profile_descs(record, pfseq);
173
174                 sdp_set_info_attr(record, name, NULL, desc);
175                 break;
176         default:
177                 sdp_record_free(record);
178                 return NULL;
179         }
180
181         sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
182         root = sdp_list_append(NULL, &root_uuid);
183         sdp_set_browse_groups(record, root);
184
185         sdp_uuid16_create(&l2cap, L2CAP_UUID);
186         proto[0] = sdp_list_append(NULL, &l2cap);
187         p = sdp_data_alloc(SDP_UINT16, &psm);
188         proto[0] = sdp_list_append(proto[0], p);
189         apseq    = sdp_list_append(NULL, proto[0]);
190
191         sdp_uuid16_create(&bnep, BNEP_UUID);
192         proto[1] = sdp_list_append(NULL, &bnep);
193         v = sdp_data_alloc(SDP_UINT16, &version);
194         proto[1] = sdp_list_append(proto[1], v);
195
196         /* Supported protocols */
197         {
198                 uint16_t ptype[] = {
199                         0x0800,  /* IPv4 */
200                         0x0806,  /* ARP */
201                 };
202                 sdp_data_t *head, *pseq;
203                 int p;
204
205                 for (p = 0, head = NULL; p < 2; p++) {
206                         sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
207                         if (head)
208                                 sdp_seq_append(head, data);
209                         else
210                                 head = data;
211                 }
212                 pseq = sdp_data_alloc(SDP_SEQ16, head);
213                 proto[1] = sdp_list_append(proto[1], pseq);
214         }
215
216         apseq = sdp_list_append(apseq, proto[1]);
217
218         aproto = sdp_list_append(NULL, apseq);
219         sdp_set_access_protos(record, aproto);
220
221         sdp_add_lang_attr(record);
222
223         sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC,
224                                 SDP_UINT16, &security_desc);
225
226         sdp_data_free(p);
227         sdp_data_free(v);
228         sdp_list_free(apseq, NULL);
229         sdp_list_free(root, NULL);
230         sdp_list_free(aproto, NULL);
231         sdp_list_free(proto[0], NULL);
232         sdp_list_free(proto[1], NULL);
233         sdp_list_free(svclass, NULL);
234         sdp_list_free(pfseq, NULL);
235
236         return record;
237 }
238
239 static ssize_t send_bnep_ctrl_rsp(int sk, uint16_t val)
240 {
241         struct bnep_control_rsp rsp;
242
243         rsp.type = BNEP_CONTROL;
244         rsp.ctrl = BNEP_SETUP_CONN_RSP;
245         rsp.resp = htons(val);
246
247         return send(sk, &rsp, sizeof(rsp), 0);
248 }
249
250 static int server_connadd(struct network_server *ns,
251                                 struct network_session *session,
252                                 uint16_t dst_role)
253 {
254         char devname[16];
255         int err, nsk;
256
257         memset(devname, 0, sizeof(devname));
258         strcpy(devname, "bnep%d");
259
260         nsk = g_io_channel_unix_get_fd(session->io);
261         err = bnep_connadd(nsk, dst_role, devname);
262         if (err < 0)
263                 return err;
264
265         info("Added new connection: %s", devname);
266
267         if (bnep_add_to_bridge(devname, ns->bridge) < 0) {
268                 error("Can't add %s to the bridge %s: %s(%d)",
269                                 devname, ns->bridge, strerror(errno), errno);
270                 return -EPERM;
271         }
272
273         bnep_if_up(devname);
274
275         ns->sessions = g_slist_append(ns->sessions, session);
276
277         return 0;
278 }
279
280 static uint16_t bnep_setup_chk(uint16_t dst_role, uint16_t src_role)
281 {
282         /* Allowed PAN Profile scenarios */
283         switch (dst_role) {
284         case BNEP_SVC_NAP:
285         case BNEP_SVC_GN:
286                 if (src_role == BNEP_SVC_PANU)
287                         return 0;
288                 return BNEP_CONN_INVALID_SRC;
289         case BNEP_SVC_PANU:
290                 if (src_role == BNEP_SVC_PANU ||
291                                 src_role == BNEP_SVC_GN ||
292                                 src_role == BNEP_SVC_NAP)
293                         return 0;
294
295                 return BNEP_CONN_INVALID_SRC;
296         }
297
298         return BNEP_CONN_INVALID_DST;
299 }
300
301 static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req,
302                                 uint16_t *dst_role, uint16_t *src_role)
303 {
304         uint8_t *dest, *source;
305
306         dest = req->service;
307         source = req->service + req->uuid_size;
308
309         switch (req->uuid_size) {
310         case 2: /* UUID16 */
311                 *dst_role = bt_get_be16(dest);
312                 *src_role = bt_get_be16(source);
313                 break;
314         case 4: /* UUID32 */
315         case 16: /* UUID128 */
316                 *dst_role = bt_get_be32(dest);
317                 *src_role = bt_get_be32(source);
318                 break;
319         default:
320                 return BNEP_CONN_INVALID_SVC;
321         }
322
323         return 0;
324 }
325
326 static void session_free(void *data)
327 {
328         struct network_session *session = data;
329
330         if (session->watch)
331                 g_source_remove(session->watch);
332
333         if (session->io)
334                 g_io_channel_unref(session->io);
335
336         g_free(session);
337 }
338
339 static void setup_destroy(void *user_data)
340 {
341         struct network_adapter *na = user_data;
342         struct network_session *setup = na->setup;
343
344         if (!setup)
345                 return;
346
347         na->setup = NULL;
348
349         session_free(setup);
350 }
351
352 static gboolean bnep_setup(GIOChannel *chan,
353                         GIOCondition cond, gpointer user_data)
354 {
355         struct network_adapter *na = user_data;
356         struct network_server *ns;
357         uint8_t packet[BNEP_MTU];
358         struct bnep_setup_conn_req *req = (void *) packet;
359         uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
360         int n, sk;
361
362         if (cond & G_IO_NVAL)
363                 return FALSE;
364
365         if (cond & (G_IO_ERR | G_IO_HUP)) {
366                 error("Hangup or error on BNEP socket");
367                 return FALSE;
368         }
369
370         sk = g_io_channel_unix_get_fd(chan);
371
372         /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
373         n = read(sk, packet, sizeof(packet));
374         if (n < 0) {
375                 error("read(): %s(%d)", strerror(errno), errno);
376                 return FALSE;
377         }
378
379         /* Highest known Control command ID
380          * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */
381         if (req->type == BNEP_CONTROL &&
382                                 req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
383                 uint8_t pkt[3];
384
385                 pkt[0] = BNEP_CONTROL;
386                 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
387                 pkt[2] = req->ctrl;
388
389                 send(sk, pkt, sizeof(pkt), 0);
390
391                 return FALSE;
392         }
393
394         if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
395                 return FALSE;
396
397         rsp = bnep_setup_decode(req, &dst_role, &src_role);
398         if (rsp)
399                 goto reply;
400
401         rsp = bnep_setup_chk(dst_role, src_role);
402         if (rsp)
403                 goto reply;
404
405         ns = find_server(na->servers, dst_role);
406         if (!ns) {
407                 error("Server unavailable: (0x%x)", dst_role);
408                 goto reply;
409         }
410
411         if (!ns->record_id) {
412                 error("Service record not available");
413                 goto reply;
414         }
415
416         if (!ns->bridge) {
417                 error("Bridge interface not configured");
418                 goto reply;
419         }
420
421         if (server_connadd(ns, na->setup, dst_role) < 0)
422                 goto reply;
423
424         na->setup = NULL;
425
426         rsp = BNEP_SUCCESS;
427
428 reply:
429         send_bnep_ctrl_rsp(sk, rsp);
430
431         return FALSE;
432 }
433
434 static void connect_event(GIOChannel *chan, GError *err, gpointer user_data)
435 {
436         struct network_adapter *na = user_data;
437
438         if (err) {
439                 error("%s", err->message);
440                 setup_destroy(na);
441                 return;
442         }
443
444         g_io_channel_set_close_on_unref(chan, TRUE);
445
446         na->setup->watch = g_io_add_watch_full(chan, G_PRIORITY_DEFAULT,
447                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
448                                 bnep_setup, na, setup_destroy);
449 }
450
451 static void auth_cb(DBusError *derr, void *user_data)
452 {
453         struct network_adapter *na = user_data;
454         GError *err = NULL;
455
456         if (derr) {
457                 error("Access denied: %s", derr->message);
458                 goto reject;
459         }
460
461         if (!bt_io_accept(na->setup->io, connect_event, na, NULL,
462                                                         &err)) {
463                 error("bt_io_accept: %s", err->message);
464                 g_error_free(err);
465                 goto reject;
466         }
467
468         return;
469
470 reject:
471         g_io_channel_shutdown(na->setup->io, TRUE, NULL);
472         setup_destroy(na);
473 }
474
475 static void confirm_event(GIOChannel *chan, gpointer user_data)
476 {
477         struct network_adapter *na = user_data;
478         struct network_server *ns;
479         int perr;
480         bdaddr_t src, dst;
481         char address[18];
482         GError *err = NULL;
483
484         bt_io_get(chan, BT_IO_L2CAP, &err,
485                         BT_IO_OPT_SOURCE_BDADDR, &src,
486                         BT_IO_OPT_DEST_BDADDR, &dst,
487                         BT_IO_OPT_DEST, address,
488                         BT_IO_OPT_INVALID);
489         if (err) {
490                 error("%s", err->message);
491                 g_error_free(err);
492                 goto drop;
493         }
494
495         DBG("BNEP: incoming connect from %s", address);
496
497         if (na->setup) {
498                 error("Refusing connect from %s: setup in progress", address);
499                 goto drop;
500         }
501
502         ns = find_server(na->servers, BNEP_SVC_NAP);
503         if (!ns)
504                 goto drop;
505
506         if (!ns->record_id)
507                 goto drop;
508
509         if (!ns->bridge)
510                 goto drop;
511
512         na->setup = g_new0(struct network_session, 1);
513         bacpy(&na->setup->dst, &dst);
514         na->setup->io = g_io_channel_ref(chan);
515
516         perr = btd_request_authorization(&src, &dst, BNEP_SVC_UUID,
517                                         auth_cb, na);
518         if (perr < 0) {
519                 error("Refusing connect from %s: %s (%d)", address,
520                                 strerror(-perr), -perr);
521                 setup_destroy(na);
522                 goto drop;
523         }
524
525         return;
526
527 drop:
528         g_io_channel_shutdown(chan, TRUE, NULL);
529 }
530
531 int server_init(DBusConnection *conn, gboolean secure)
532 {
533         security = secure;
534         connection = dbus_connection_ref(conn);
535
536         return 0;
537 }
538
539 void server_exit(void)
540 {
541         dbus_connection_unref(connection);
542         connection = NULL;
543 }
544
545 static uint32_t register_server_record(struct network_server *ns)
546 {
547         sdp_record_t *record;
548
549         record = server_record_new(ns->name, ns->id);
550         if (!record) {
551                 error("Unable to allocate new service record");
552                 return 0;
553         }
554
555         if (add_record_to_server(&ns->src, record) < 0) {
556                 error("Failed to register service record");
557                 sdp_record_free(record);
558                 return 0;
559         }
560
561         DBG("got record id 0x%x", record->handle);
562
563         return record->handle;
564 }
565
566 static void server_disconnect(DBusConnection *conn, void *user_data)
567 {
568         struct network_server *ns = user_data;
569
570         ns->watch_id = 0;
571
572         if (ns->record_id) {
573                 remove_record_from_server(ns->record_id);
574                 ns->record_id = 0;
575         }
576
577         g_free(ns->bridge);
578         ns->bridge = NULL;
579 }
580
581 static DBusMessage *register_server(DBusConnection *conn,
582                                 DBusMessage *msg, void *data)
583 {
584         struct network_server *ns = data;
585         DBusMessage *reply;
586         const char *uuid, *bridge;
587
588         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
589                                 DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID))
590                 return NULL;
591
592         if (g_strcmp0(uuid, "nap"))
593                 return btd_error_failed(msg, "Invalid UUID");
594
595         if (ns->record_id)
596                 return btd_error_already_exists(msg);
597
598         reply = dbus_message_new_method_return(msg);
599         if (!reply)
600                 return NULL;
601
602         ns->record_id = register_server_record(ns);
603         if (!ns->record_id)
604                 return btd_error_failed(msg, "SDP record registration failed");
605
606         g_free(ns->bridge);
607         ns->bridge = g_strdup(bridge);
608
609         ns->watch_id = g_dbus_add_disconnect_watch(conn,
610                                         dbus_message_get_sender(msg),
611                                         server_disconnect, ns, NULL);
612
613         return reply;
614 }
615
616 static DBusMessage *unregister_server(DBusConnection *conn,
617                                         DBusMessage *msg, void *data)
618 {
619         struct network_server *ns = data;
620         DBusMessage *reply;
621         const char *uuid;
622
623         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
624                                                         DBUS_TYPE_INVALID))
625                 return NULL;
626
627         if (g_strcmp0(uuid, "nap"))
628                 return btd_error_failed(msg, "Invalid UUID");
629
630         reply = dbus_message_new_method_return(msg);
631         if (!reply)
632                 return NULL;
633
634         g_dbus_remove_watch(conn, ns->watch_id);
635
636         server_disconnect(conn, ns);
637
638         return reply;
639 }
640
641 static void adapter_free(struct network_adapter *na)
642 {
643         if (na->io != NULL) {
644                 g_io_channel_shutdown(na->io, TRUE, NULL);
645                 g_io_channel_unref(na->io);
646         }
647
648         setup_destroy(na);
649         btd_adapter_unref(na->adapter);
650         g_free(na);
651 }
652
653 static void server_free(struct network_server *ns)
654 {
655         if (!ns)
656                 return;
657
658         /* FIXME: Missing release/free all bnepX interfaces */
659         if (ns->record_id)
660                 remove_record_from_server(ns->record_id);
661
662         g_free(ns->iface);
663         g_free(ns->name);
664         g_free(ns->bridge);
665
666         g_slist_free_full(ns->sessions, session_free);
667
668         g_free(ns);
669 }
670
671 static void path_unregister(void *data)
672 {
673         struct network_server *ns = data;
674         struct network_adapter *na = ns->na;
675
676         DBG("Unregistered interface %s on path %s",
677                 ns->iface, adapter_get_path(na->adapter));
678
679         na->servers = g_slist_remove(na->servers, ns);
680         server_free(ns);
681
682         if (na->servers)
683                 return;
684
685         adapters = g_slist_remove(adapters, na);
686         adapter_free(na);
687 }
688
689 static const GDBusMethodTable server_methods[] = {
690         { GDBUS_METHOD("Register",
691                         GDBUS_ARGS({ "uuid", "s" }, { "bridge", "s" }), NULL,
692                         register_server) },
693         { GDBUS_METHOD("Unregister",
694                         GDBUS_ARGS({ "uuid", "s" }), NULL,
695                         unregister_server) },
696         { }
697 };
698
699 static struct network_adapter *create_adapter(struct btd_adapter *adapter)
700 {
701         struct network_adapter *na;
702         GError *err = NULL;
703         bdaddr_t src;
704
705         na = g_new0(struct network_adapter, 1);
706         na->adapter = btd_adapter_ref(adapter);
707
708         adapter_get_address(adapter, &src);
709
710         na->io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, na,
711                                 NULL, &err,
712                                 BT_IO_OPT_SOURCE_BDADDR, &src,
713                                 BT_IO_OPT_PSM, BNEP_PSM,
714                                 BT_IO_OPT_OMTU, BNEP_MTU,
715                                 BT_IO_OPT_IMTU, BNEP_MTU,
716                                 BT_IO_OPT_SEC_LEVEL,
717                                 security ? BT_IO_SEC_MEDIUM : BT_IO_SEC_LOW,
718                                 BT_IO_OPT_INVALID);
719         if (!na->io) {
720                 error("%s", err->message);
721                 g_error_free(err);
722                 adapter_free(na);
723                 return NULL;
724         }
725
726         return na;
727 }
728
729 int server_register(struct btd_adapter *adapter)
730 {
731         struct network_adapter *na;
732         struct network_server *ns;
733         const char *path;
734
735         na = find_adapter(adapters, adapter);
736         if (!na) {
737                 na = create_adapter(adapter);
738                 if (!na)
739                         return -EINVAL;
740                 adapters = g_slist_append(adapters, na);
741         }
742
743         ns = find_server(na->servers, BNEP_SVC_NAP);
744         if (ns)
745                 return 0;
746
747         ns = g_new0(struct network_server, 1);
748
749         ns->iface = g_strdup(NETWORK_SERVER_INTERFACE);
750         ns->name = g_strdup("Network service");
751
752         path = adapter_get_path(adapter);
753
754         if (!g_dbus_register_interface(connection, path, ns->iface,
755                                         server_methods, NULL, NULL,
756                                         ns, path_unregister)) {
757                 error("D-Bus failed to register %s interface",
758                                 ns->iface);
759                 server_free(ns);
760                 return -1;
761         }
762
763         adapter_get_address(adapter, &ns->src);
764         ns->id = BNEP_SVC_NAP;
765         ns->na = na;
766         ns->record_id = 0;
767         na->servers = g_slist_append(na->servers, ns);
768
769         DBG("Registered interface %s on path %s", ns->iface, path);
770
771         return 0;
772 }
773
774 int server_unregister(struct btd_adapter *adapter)
775 {
776         struct network_adapter *na;
777         struct network_server *ns;
778         uint16_t id = BNEP_SVC_NAP;
779
780         na = find_adapter(adapters, adapter);
781         if (!na)
782                 return -EINVAL;
783
784         ns = find_server(na->servers, id);
785         if (!ns)
786                 return -EINVAL;
787
788         g_dbus_unregister_interface(connection, adapter_get_path(adapter),
789                                         ns->iface);
790
791         return 0;
792 }