Home | History | Annotate | Download | only in network
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel (at) 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/hci.h>
     35 #include <bluetooth/bnep.h>
     36 #include <bluetooth/l2cap.h>
     37 #include <bluetooth/sdp.h>
     38 #include <bluetooth/sdp_lib.h>
     39 #include <netinet/in.h>
     40 
     41 #include <glib.h>
     42 #include <gdbus.h>
     43 
     44 #include "../src/dbus-common.h"
     45 #include "../src/adapter.h"
     46 
     47 #include "logging.h"
     48 #include "error.h"
     49 #include "sdpd.h"
     50 #include "btio.h"
     51 #include "glib-helper.h"
     52 
     53 #include "bridge.h"
     54 #include "common.h"
     55 #include "server.h"
     56 
     57 #define NETWORK_PEER_INTERFACE "org.bluez.NetworkPeer"
     58 #define NETWORK_HUB_INTERFACE "org.bluez.NetworkHub"
     59 #define NETWORK_ROUTER_INTERFACE "org.bluez.NetworkRouter"
     60 #define SETUP_TIMEOUT		1
     61 
     62 /* Pending Authorization */
     63 struct network_session {
     64 	bdaddr_t	dst;		/* Remote Bluetooth Address */
     65 	GIOChannel	*io;		/* Pending connect channel */
     66 	guint		watch;		/* BNEP socket watch */
     67 };
     68 
     69 struct network_adapter {
     70 	struct btd_adapter *adapter;	/* Adapter pointer */
     71 	GIOChannel	*io;		/* Bnep socket */
     72 	struct network_session *setup;	/* Setup in progress */
     73 	GSList		*servers;	/* Server register to adapter */
     74 };
     75 
     76 /* Main server structure */
     77 struct network_server {
     78 	bdaddr_t	src;		/* Bluetooth Local Address */
     79 	char		*iface;		/* DBus interface */
     80 	char		*name;		/* Server service name */
     81 	char		*range;		/* IP Address range */
     82 	gboolean	enable;		/* Enable flag */
     83 	uint32_t	record_id;	/* Service record id */
     84 	uint16_t	id;		/* Service class identifier */
     85 	GSList		*sessions;	/* Active connections */
     86 	struct network_adapter *na;	/* Adapter reference */
     87 };
     88 
     89 static DBusConnection *connection = NULL;
     90 static GSList *adapters = NULL;
     91 static const char *prefix = NULL;
     92 static gboolean security = TRUE;
     93 
     94 static struct network_adapter *find_adapter(GSList *list,
     95 					struct btd_adapter *adapter)
     96 {
     97 	GSList *l;
     98 
     99 	for (l = list; l; l = l->next) {
    100 		struct network_adapter *na = l->data;
    101 
    102 		if (na->adapter == adapter)
    103 			return na;
    104 	}
    105 
    106 	return NULL;
    107 }
    108 
    109 static struct network_server *find_server(GSList *list, uint16_t id)
    110 {
    111 	GSList *l;
    112 
    113 	for (l = list; l; l = l->next) {
    114 		struct network_server *ns = l->data;
    115 
    116 		if (ns->id == id)
    117 			return ns;
    118 	}
    119 
    120 	return NULL;
    121 }
    122 
    123 static void add_lang_attr(sdp_record_t *r)
    124 {
    125 	sdp_lang_attr_t base_lang;
    126 	sdp_list_t *langs = 0;
    127 
    128 	/* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
    129 	base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
    130 	base_lang.encoding = 106;
    131 	base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
    132 	langs = sdp_list_append(0, &base_lang);
    133 	sdp_set_lang_attr(r, langs);
    134 	sdp_list_free(langs, 0);
    135 }
    136 
    137 static sdp_record_t *server_record_new(const char *name, uint16_t id)
    138 {
    139 	sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
    140 	uuid_t root_uuid, pan, l2cap, bnep;
    141 	sdp_profile_desc_t profile[1];
    142 	sdp_list_t *proto[2];
    143 	sdp_data_t *v, *p;
    144 	uint16_t psm = BNEP_PSM, version = 0x0100;
    145 	uint16_t security_desc = (security ? 0x0001 : 0x0000);
    146 	uint16_t net_access_type = 0xfffe;
    147 	uint32_t max_net_access_rate = 0;
    148 	const char *desc = "BlueZ PAN service";
    149 	sdp_record_t *record;
    150 
    151 	record = sdp_record_alloc();
    152 	if (!record)
    153 		return NULL;
    154 
    155 	record->attrlist = NULL;
    156 	record->pattern = NULL;
    157 
    158 	switch (id) {
    159 	case BNEP_SVC_NAP:
    160 		sdp_uuid16_create(&pan, NAP_SVCLASS_ID);
    161 		svclass = sdp_list_append(NULL, &pan);
    162 		sdp_set_service_classes(record, svclass);
    163 
    164 		sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
    165 		profile[0].version = 0x0100;
    166 		pfseq = sdp_list_append(NULL, &profile[0]);
    167 		sdp_set_profile_descs(record, pfseq);
    168 
    169 		sdp_set_info_attr(record, name, NULL, desc);
    170 
    171 		sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE,
    172 					SDP_UINT16, &net_access_type);
    173 		sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE,
    174 					SDP_UINT32, &max_net_access_rate);
    175 		break;
    176 	case BNEP_SVC_GN:
    177 		sdp_uuid16_create(&pan, GN_SVCLASS_ID);
    178 		svclass = sdp_list_append(NULL, &pan);
    179 		sdp_set_service_classes(record, svclass);
    180 
    181 		sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
    182 		profile[0].version = 0x0100;
    183 		pfseq = sdp_list_append(NULL, &profile[0]);
    184 		sdp_set_profile_descs(record, pfseq);
    185 
    186 		sdp_set_info_attr(record, name, NULL, desc);
    187 		break;
    188 	case BNEP_SVC_PANU:
    189 		sdp_uuid16_create(&pan, PANU_SVCLASS_ID);
    190 		svclass = sdp_list_append(NULL, &pan);
    191 		sdp_set_service_classes(record, svclass);
    192 
    193 		sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
    194 		profile[0].version = 0x0100;
    195 		pfseq = sdp_list_append(NULL, &profile[0]);
    196 		sdp_set_profile_descs(record, pfseq);
    197 
    198 		sdp_set_info_attr(record, name, NULL, desc);
    199 		break;
    200 	default:
    201 		sdp_record_free(record);
    202 		return NULL;
    203 	}
    204 
    205 	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
    206 	root = sdp_list_append(NULL, &root_uuid);
    207 	sdp_set_browse_groups(record, root);
    208 
    209 	sdp_uuid16_create(&l2cap, L2CAP_UUID);
    210 	proto[0] = sdp_list_append(NULL, &l2cap);
    211 	p = sdp_data_alloc(SDP_UINT16, &psm);
    212 	proto[0] = sdp_list_append(proto[0], p);
    213 	apseq    = sdp_list_append(NULL, proto[0]);
    214 
    215 	sdp_uuid16_create(&bnep, BNEP_UUID);
    216 	proto[1] = sdp_list_append(NULL, &bnep);
    217 	v = sdp_data_alloc(SDP_UINT16, &version);
    218 	proto[1] = sdp_list_append(proto[1], v);
    219 
    220 	/* Supported protocols */
    221 	{
    222 		uint16_t ptype[] = {
    223 			0x0800,  /* IPv4 */
    224 			0x0806,  /* ARP */
    225 		};
    226 		sdp_data_t *head, *pseq;
    227 		int p;
    228 
    229 		for (p = 0, head = NULL; p < 2; p++) {
    230 			sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
    231 			if (head)
    232 				sdp_seq_append(head, data);
    233 			else
    234 				head = data;
    235 		}
    236 		pseq = sdp_data_alloc(SDP_SEQ16, head);
    237 		proto[1] = sdp_list_append(proto[1], pseq);
    238 	}
    239 
    240 	apseq = sdp_list_append(apseq, proto[1]);
    241 
    242 	aproto = sdp_list_append(NULL, apseq);
    243 	sdp_set_access_protos(record, aproto);
    244 
    245 	add_lang_attr(record);
    246 
    247 	sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC,
    248 				SDP_UINT16, &security_desc);
    249 
    250 	sdp_data_free(p);
    251 	sdp_data_free(v);
    252 	sdp_list_free(apseq, NULL);
    253 	sdp_list_free(root, NULL);
    254 	sdp_list_free(aproto, NULL);
    255 	sdp_list_free(proto[0], NULL);
    256 	sdp_list_free(proto[1], NULL);
    257 	sdp_list_free(svclass, NULL);
    258 	sdp_list_free(pfseq, NULL);
    259 
    260 	return record;
    261 }
    262 
    263 static ssize_t send_bnep_ctrl_rsp(int sk, uint16_t val)
    264 {
    265 	struct bnep_control_rsp rsp;
    266 
    267 	rsp.type = BNEP_CONTROL;
    268 	rsp.ctrl = BNEP_SETUP_CONN_RSP;
    269 	rsp.resp = htons(val);
    270 
    271 	return send(sk, &rsp, sizeof(rsp), 0);
    272 }
    273 
    274 static int server_connadd(struct network_server *ns,
    275 				struct network_session *session,
    276 				uint16_t dst_role)
    277 {
    278 	char devname[16];
    279 	const char *bridge;
    280 	int err, nsk;
    281 
    282 	/* Server can be disabled in the meantime */
    283 	if (ns->enable == FALSE)
    284 		return -EPERM;
    285 
    286 	memset(devname, 0, 16);
    287 	strncpy(devname, prefix, sizeof(devname) - 1);
    288 
    289 	nsk = g_io_channel_unix_get_fd(session->io);
    290 	err = bnep_connadd(nsk, dst_role, devname);
    291 	if (err < 0)
    292 		return err;
    293 
    294 	info("Added new connection: %s", devname);
    295 
    296 	bridge = bridge_get_name(ns->id);
    297 	if (bridge) {
    298 		if (bridge_add_interface(ns->id, devname) < 0) {
    299 			error("Can't add %s to the bridge %s: %s(%d)",
    300 					devname, bridge, strerror(errno),
    301 					errno);
    302 			return -EPERM;
    303 		}
    304 
    305 		bnep_if_up(devname, 0);
    306 	} else
    307 		bnep_if_up(devname, ns->id);
    308 
    309 	ns->sessions = g_slist_append(ns->sessions, session);
    310 
    311 	return 0;
    312 }
    313 
    314 static uint16_t bnep_setup_chk(uint16_t dst_role, uint16_t src_role)
    315 {
    316 	/* Allowed PAN Profile scenarios */
    317 	switch (dst_role) {
    318 	case BNEP_SVC_NAP:
    319 	case BNEP_SVC_GN:
    320 		if (src_role == BNEP_SVC_PANU)
    321 			return 0;
    322 		return BNEP_CONN_INVALID_SRC;
    323 	case BNEP_SVC_PANU:
    324 		if (src_role == BNEP_SVC_PANU ||
    325 			src_role == BNEP_SVC_GN ||
    326 			src_role == BNEP_SVC_NAP)
    327 			return 0;
    328 
    329 		return BNEP_CONN_INVALID_SRC;
    330 	}
    331 
    332 	return BNEP_CONN_INVALID_DST;
    333 }
    334 
    335 static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req,
    336 				uint16_t *dst_role, uint16_t *src_role)
    337 {
    338 	uint8_t *dest, *source;
    339 
    340 	dest = req->service;
    341 	source = req->service + req->uuid_size;
    342 
    343 	switch (req->uuid_size) {
    344 	case 2: /* UUID16 */
    345 		*dst_role = ntohs(bt_get_unaligned((uint16_t *) dest));
    346 		*src_role = ntohs(bt_get_unaligned((uint16_t *) source));
    347 		break;
    348 	case 4: /* UUID32 */
    349 	case 16: /* UUID128 */
    350 		*dst_role = ntohl(bt_get_unaligned((uint32_t *) dest));
    351 		*src_role = ntohl(bt_get_unaligned((uint32_t *) source));
    352 		break;
    353 	default:
    354 		return BNEP_CONN_INVALID_SVC;
    355 	}
    356 
    357 	return 0;
    358 }
    359 
    360 static void session_free(void *data)
    361 {
    362 	struct network_session *session = data;
    363 
    364 	if (session->watch)
    365 		g_source_remove(session->watch);
    366 
    367 	if (session->io)
    368 		g_io_channel_unref(session->io);
    369 
    370 	g_free(session);
    371 }
    372 
    373 static void setup_destroy(void *user_data)
    374 {
    375 	struct network_adapter *na = user_data;
    376 	struct network_session *setup = na->setup;
    377 
    378 	if (!setup)
    379 		return;
    380 
    381 	na->setup = NULL;
    382 
    383 	session_free(setup);
    384 }
    385 
    386 static gboolean bnep_setup(GIOChannel *chan,
    387 			GIOCondition cond, gpointer user_data)
    388 {
    389 	struct network_adapter *na = user_data;
    390 	struct network_server *ns;
    391 	uint8_t packet[BNEP_MTU];
    392 	struct bnep_setup_conn_req *req = (void *) packet;
    393 	uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
    394 	int n, sk;
    395 
    396 	if (cond & G_IO_NVAL)
    397 		return FALSE;
    398 
    399 	if (cond & (G_IO_ERR | G_IO_HUP)) {
    400 		error("Hangup or error on BNEP socket");
    401 		return FALSE;
    402 	}
    403 
    404 	sk = g_io_channel_unix_get_fd(chan);
    405 
    406 	/* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
    407 	n = read(sk, packet, sizeof(packet));
    408 	if (n < 0) {
    409 		error("read(): %s(%d)", strerror(errno), errno);
    410 		return FALSE;
    411 	}
    412 
    413 	if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
    414 		return FALSE;
    415 
    416 	rsp = bnep_setup_decode(req, &dst_role, &src_role);
    417 	if (rsp)
    418 		goto reply;
    419 
    420 	rsp = bnep_setup_chk(dst_role, src_role);
    421 	if (rsp)
    422 		goto reply;
    423 
    424 	ns = find_server(na->servers, dst_role);
    425 	if (!ns || ns->enable == FALSE) {
    426 		error("Server unavailable: (0x%x)", dst_role);
    427 		goto reply;
    428 	}
    429 
    430 	if (server_connadd(ns, na->setup, dst_role) < 0)
    431 		goto reply;
    432 
    433 	na->setup = NULL;
    434 
    435 	rsp = BNEP_SUCCESS;
    436 
    437 reply:
    438 	send_bnep_ctrl_rsp(sk, rsp);
    439 
    440 	return FALSE;
    441 }
    442 
    443 static void connect_event(GIOChannel *chan, GError *err, gpointer user_data)
    444 {
    445 	struct network_adapter *na = user_data;
    446 
    447 	if (err) {
    448 		error("%s", err->message);
    449 		setup_destroy(na);
    450 		return;
    451 	}
    452 
    453 	g_io_channel_set_close_on_unref(chan, TRUE);
    454 
    455 	na->setup->watch = g_io_add_watch_full(chan, G_PRIORITY_DEFAULT,
    456 				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
    457 				bnep_setup, na, setup_destroy);
    458 }
    459 
    460 static void auth_cb(DBusError *derr, void *user_data)
    461 {
    462 	struct network_adapter *na = user_data;
    463 	GError *err = NULL;
    464 
    465 	if (derr) {
    466 		error("Access denied: %s", derr->message);
    467 		goto reject;
    468 	}
    469 
    470 	if (!bt_io_accept(na->setup->io, connect_event, na, NULL,
    471 							&err)) {
    472 		error("bt_io_accept: %s", err->message);
    473 		g_error_free(err);
    474 		goto reject;
    475 	}
    476 
    477 	return;
    478 
    479 reject:
    480 	g_io_channel_shutdown(na->setup->io, TRUE, NULL);
    481 	setup_destroy(na);
    482 }
    483 
    484 static void confirm_event(GIOChannel *chan, gpointer user_data)
    485 {
    486 	struct network_adapter *na = user_data;
    487 	int perr;
    488 	bdaddr_t src, dst;
    489 	char address[18];
    490 	GError *err = NULL;
    491 
    492 	bt_io_get(chan, BT_IO_L2CAP, &err,
    493 			BT_IO_OPT_SOURCE_BDADDR, &src,
    494 			BT_IO_OPT_DEST_BDADDR, &dst,
    495 			BT_IO_OPT_DEST, address,
    496 			BT_IO_OPT_INVALID);
    497 	if (err) {
    498 		error("%s", err->message);
    499 		g_error_free(err);
    500 		goto drop;
    501 	}
    502 
    503 	debug("BNEP: incoming connect from %s", address);
    504 
    505 	if (na->setup) {
    506 		error("Refusing connect from %s: setup in progress", address);
    507 		goto drop;
    508 	}
    509 
    510 	na->setup = g_new0(struct network_session, 1);
    511 	bacpy(&na->setup->dst, &dst);
    512 	na->setup->io = g_io_channel_ref(chan);
    513 
    514 	perr = btd_request_authorization(&src, &dst, BNEP_SVC_UUID,
    515 					auth_cb, na);
    516 	if (perr < 0) {
    517 		error("Refusing connect from %s: %s (%d)", address,
    518 				strerror(-perr), -perr);
    519 		setup_destroy(na);
    520 		goto drop;
    521 	}
    522 
    523 	return;
    524 
    525 drop:
    526 	g_io_channel_shutdown(chan, TRUE, NULL);
    527 }
    528 
    529 int server_init(DBusConnection *conn, const char *iface_prefix,
    530 		gboolean secure)
    531 {
    532 	security = secure;
    533 	connection = dbus_connection_ref(conn);
    534 	prefix = iface_prefix;
    535 
    536 	if (bridge_create(BNEP_SVC_GN) < 0)
    537 		error("Can't create GN bridge");
    538 
    539 	return 0;
    540 }
    541 
    542 void server_exit()
    543 {
    544 	if (bridge_remove(BNEP_SVC_GN) < 0)
    545 		error("Can't remove GN bridge");
    546 
    547 	dbus_connection_unref(connection);
    548 	connection = NULL;
    549 }
    550 
    551 static uint32_t register_server_record(struct network_server *ns)
    552 {
    553 	sdp_record_t *record;
    554 
    555 	record = server_record_new(ns->name, ns->id);
    556 	if (!record) {
    557 		error("Unable to allocate new service record");
    558 		return 0;
    559 	}
    560 
    561 	if (add_record_to_server(&ns->src, record) < 0) {
    562 		error("Failed to register service record");
    563 		sdp_record_free(record);
    564 		return 0;
    565 	}
    566 
    567 	debug("register_server_record: got record id 0x%x", record->handle);
    568 
    569 	return record->handle;
    570 }
    571 
    572 
    573 static inline DBusMessage *failed(DBusMessage *msg, const char *description)
    574 {
    575 	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
    576 				description);
    577 }
    578 
    579 static inline DBusMessage *invalid_arguments(DBusMessage *msg,
    580 					const char *description)
    581 {
    582 	return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
    583 				description);
    584 }
    585 
    586 static DBusMessage *enable(DBusConnection *conn,
    587 			DBusMessage *msg, void *data)
    588 {
    589 	struct network_server *ns = data;
    590 	DBusMessage *reply;
    591 
    592 	if (ns->enable)
    593 		return g_dbus_create_error(msg, ERROR_INTERFACE
    594 						".AlreadyExist",
    595 						"Server already enabled");
    596 
    597 	reply = dbus_message_new_method_return(msg);
    598 	if (!reply)
    599 		return NULL;
    600 
    601 	/* Add the service record */
    602 	ns->record_id = register_server_record(ns);
    603 	if (!ns->record_id) {
    604 		dbus_message_unref(reply);
    605 		return failed(msg, "Service record registration failed");
    606 	}
    607 
    608 	ns->enable = TRUE;
    609 
    610 	return reply;
    611 }
    612 
    613 static DBusMessage *disable(DBusConnection *conn,
    614 				DBusMessage *msg, void *data)
    615 {
    616 	struct network_server *ns = data;
    617 	DBusMessage *reply;
    618 
    619 	reply = dbus_message_new_method_return(msg);
    620 	if (!reply)
    621 		return NULL;
    622 
    623 	if (!ns->enable)
    624 		return failed(msg, "Not enabled");
    625 
    626 	/* Remove the service record */
    627 	if (ns->record_id) {
    628 		remove_record_from_server(ns->record_id);
    629 		ns->record_id = 0;
    630 	}
    631 
    632 	ns->enable = FALSE;
    633 
    634 	g_slist_foreach(ns->sessions, (GFunc) session_free, NULL);
    635 	g_slist_free(ns->sessions);
    636 
    637 	return reply;
    638 }
    639 
    640 static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
    641 				const char *name, void *data)
    642 {
    643 	struct network_server *ns = data;
    644 	DBusMessage *reply;
    645 
    646 	reply = dbus_message_new_method_return(msg);
    647 	if (!reply)
    648 		return NULL;
    649 
    650 	if (!name || (strlen(name) == 0))
    651 		return invalid_arguments(msg, "Invalid name");
    652 
    653 	if (ns->name)
    654 		g_free(ns->name);
    655 	ns->name = g_strdup(name);
    656 
    657 	if (ns->enable && ns->record_id) {
    658 		uint32_t handle = register_server_record(ns);
    659 		if (!handle) {
    660 			dbus_message_unref(reply);
    661 			return failed(msg,
    662 				"Service record attribute update failed");
    663 		}
    664 
    665 		remove_record_from_server(ns->record_id);
    666 		ns->record_id = handle;
    667 	}
    668 
    669 	return reply;
    670 }
    671 
    672 static DBusMessage *get_properties(DBusConnection *conn,
    673 				DBusMessage *msg, void *data)
    674 {
    675 	struct network_server *ns = data;
    676 	DBusMessage *reply;
    677 	DBusMessageIter iter;
    678 	DBusMessageIter dict;
    679 	const char *uuid;
    680 
    681 	reply = dbus_message_new_method_return(msg);
    682 	if (!reply)
    683 		return NULL;
    684 
    685 	dbus_message_iter_init_append(reply, &iter);
    686 
    687 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
    688 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
    689 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
    690 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
    691 
    692 	dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ns->name);
    693 
    694 	uuid = bnep_uuid(ns->id);
    695 	dict_append_entry(&dict, "Uuid", DBUS_TYPE_STRING, &uuid);
    696 
    697 	dict_append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &ns->enable);
    698 
    699 	dbus_message_iter_close_container(&iter, &dict);
    700 
    701 	return reply;
    702 }
    703 
    704 static DBusMessage *set_property(DBusConnection *conn,
    705 					DBusMessage *msg, void *data)
    706 {
    707 	DBusMessageIter iter;
    708 	DBusMessageIter sub;
    709 	const char *property;
    710 
    711 	if (!dbus_message_iter_init(msg, &iter))
    712 		return invalid_arguments(msg, "Not a dict");
    713 
    714 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
    715 		return invalid_arguments(msg, "Key not a string");
    716 
    717 	dbus_message_iter_get_basic(&iter, &property);
    718 	dbus_message_iter_next(&iter);
    719 
    720 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
    721 		return invalid_arguments(msg, "Value not a variant");
    722 	dbus_message_iter_recurse(&iter, &sub);
    723 
    724 	if (g_str_equal("Name", property)) {
    725 		const char *name;
    726 
    727 		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
    728 			return invalid_arguments(msg, "Value not string");
    729 		dbus_message_iter_get_basic(&sub, &name);
    730 
    731 		return set_name(conn, msg, name, data);
    732 	} else if (g_str_equal("Enabled", property)) {
    733 		gboolean enabled;
    734 
    735 		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
    736 			return invalid_arguments(msg, "Value not boolean");
    737 		dbus_message_iter_get_basic(&sub, &enabled);
    738 
    739 		return enabled ? enable(conn, msg, data) :
    740 				disable(conn, msg, data);
    741 	}
    742 
    743 	return invalid_arguments(msg, "Property does not exist");
    744 }
    745 
    746 static void adapter_free(struct network_adapter *na)
    747 {
    748 	if (na->io != NULL) {
    749 		g_io_channel_shutdown(na->io, TRUE, NULL);
    750 		g_io_channel_unref(na->io);
    751 	}
    752 
    753 	setup_destroy(na);
    754 	btd_adapter_unref(na->adapter);
    755 	g_free(na);
    756 }
    757 
    758 static void server_free(struct network_server *ns)
    759 {
    760 	if (!ns)
    761 		return;
    762 
    763 	/* FIXME: Missing release/free all bnepX interfaces */
    764 	if (ns->record_id)
    765 		remove_record_from_server(ns->record_id);
    766 
    767 	if (ns->iface)
    768 		g_free(ns->iface);
    769 
    770 	if (ns->name)
    771 		g_free(ns->name);
    772 
    773 	if (ns->range)
    774 		g_free(ns->range);
    775 
    776 	if (ns->sessions) {
    777 		g_slist_foreach(ns->sessions, (GFunc) session_free, NULL);
    778 		g_slist_free(ns->sessions);
    779 	}
    780 
    781 	g_free(ns);
    782 }
    783 
    784 static void path_unregister(void *data)
    785 {
    786 	struct network_server *ns = data;
    787 	struct network_adapter *na = ns->na;
    788 
    789 	debug("Unregistered interface %s on path %s",
    790 		ns->iface, adapter_get_path(na->adapter));
    791 
    792 	na->servers = g_slist_remove(na->servers, ns);
    793 	server_free(ns);
    794 
    795 	if (na->servers)
    796 		return;
    797 
    798 	adapters = g_slist_remove(adapters, na);
    799 	adapter_free(na);
    800 }
    801 
    802 static GDBusMethodTable server_methods[] = {
    803 	{ "SetProperty",	"sv",	"",	set_property },
    804 	{ "GetProperties",	"",	"a{sv}",get_properties },
    805 	{ }
    806 };
    807 
    808 static GDBusSignalTable server_signals[] = {
    809 	{ "PropertyChanged",		"sv"		},
    810 	{ }
    811 };
    812 
    813 static struct network_adapter *create_adapter(struct btd_adapter *adapter)
    814 {
    815 	struct network_adapter *na;
    816 	GError *err = NULL;
    817 	bdaddr_t src;
    818 
    819 	na = g_new0(struct network_adapter, 1);
    820 	na->adapter = btd_adapter_ref(adapter);
    821 
    822 	adapter_get_address(adapter, &src);
    823 
    824 	na->io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, na,
    825 				NULL, &err,
    826 				BT_IO_OPT_SOURCE_BDADDR, &src,
    827 				BT_IO_OPT_PSM, BNEP_PSM,
    828 				BT_IO_OPT_OMTU, BNEP_MTU,
    829 				BT_IO_OPT_IMTU, BNEP_MTU,
    830 				BT_IO_OPT_SEC_LEVEL,
    831 				security ? BT_IO_SEC_MEDIUM : BT_IO_SEC_LOW,
    832 				BT_IO_OPT_INVALID);
    833 	if (!na->io) {
    834 		error("%s", err->message);
    835 		g_error_free(err);
    836 		adapter_free(na);
    837 		return NULL;
    838 	}
    839 
    840 	return na;
    841 }
    842 
    843 int server_register(struct btd_adapter *adapter, uint16_t id)
    844 {
    845 	struct network_adapter *na;
    846 	struct network_server *ns;
    847 	const char *path;
    848 
    849 	na = find_adapter(adapters, adapter);
    850 	if (!na) {
    851 		na = create_adapter(adapter);
    852 		if (!na)
    853 			return -EINVAL;
    854 		adapters = g_slist_append(adapters, na);
    855 	}
    856 
    857 	ns = find_server(na->servers, id);
    858 	if (ns)
    859 		return 0;
    860 
    861 	ns = g_new0(struct network_server, 1);
    862 
    863 	switch (id) {
    864 	case BNEP_SVC_PANU:
    865 		ns->iface = g_strdup(NETWORK_PEER_INTERFACE);
    866 		ns->name = g_strdup("BlueZ PANU service");
    867 		break;
    868 	case BNEP_SVC_GN:
    869 		ns->iface = g_strdup(NETWORK_HUB_INTERFACE);
    870 		ns->name = g_strdup("BlueZ GN service");
    871 		break;
    872 	case BNEP_SVC_NAP:
    873 		ns->iface = g_strdup(NETWORK_ROUTER_INTERFACE);
    874 		ns->name = g_strdup("BlueZ NAP service");
    875 		break;
    876 	}
    877 
    878 	path = adapter_get_path(adapter);
    879 
    880 	if (!g_dbus_register_interface(connection, path, ns->iface,
    881 					server_methods, server_signals, NULL,
    882 					ns, path_unregister)) {
    883 		error("D-Bus failed to register %s interface",
    884 				ns->iface);
    885 		server_free(ns);
    886 		return -1;
    887 	}
    888 
    889 	adapter_get_address(adapter, &ns->src);
    890 	ns->id = id;
    891 	ns->na = na;
    892 	ns->record_id = register_server_record(ns);
    893 	ns->enable = TRUE;
    894 	na->servers = g_slist_append(na->servers, ns);
    895 
    896 	debug("Registered interface %s on path %s", ns->iface, path);
    897 
    898 	return 0;
    899 }
    900 
    901 int server_unregister(struct btd_adapter *adapter, uint16_t id)
    902 {
    903 	struct network_adapter *na;
    904 	struct network_server *ns;
    905 
    906 	na = find_adapter(adapters, adapter);
    907 	if (!na)
    908 		return -EINVAL;
    909 
    910 	ns = find_server(na->servers, id);
    911 	if (!ns)
    912 		return -EINVAL;
    913 
    914 	g_dbus_unregister_interface(connection, adapter_get_path(adapter),
    915 					ns->iface);
    916 
    917 	return 0;
    918 }
    919