3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
32 #include <netinet/in.h>
34 #include <bluetooth/bluetooth.h>
35 #include <bluetooth/bnep.h>
36 #include <bluetooth/sdp.h>
39 #include <gdbus/gdbus.h>
41 #include "btio/btio.h"
43 #include "src/dbus-common.h"
44 #include "src/adapter.h"
45 #include "src/device.h"
46 #include "src/profile.h"
47 #include "src/service.h"
48 #include "src/error.h"
51 #include "connection.h"
53 #define NETWORK_PEER_INTERFACE "org.bluez.Network1"
54 #define BNEP_INTERFACE "bnep%d"
63 struct btd_device *device;
68 struct btd_service *service;
69 char dev[16]; /* Interface name */
70 uint16_t id; /* Role: Service Class Identifier */
74 struct network_peer *peer;
79 static GSList *peers = NULL;
81 static uint16_t get_service_id(struct btd_service *service)
83 return bnep_service_id(btd_service_get_profile(service)->remote_uuid);
86 static struct network_peer *find_peer(GSList *list, struct btd_device *device)
88 for (; list; list = list->next) {
89 struct network_peer *peer = list->data;
91 if (peer->device == device)
98 static struct network_conn *find_connection_by_state(GSList *list,
101 for (; list; list = list->next) {
102 struct network_conn *nc = list->data;
104 if (nc->state == state)
111 static void bnep_disconn_cb(gpointer data)
113 struct network_conn *nc = data;
114 DBusConnection *conn = btd_get_dbus_connection();
115 const char *path = device_get_path(nc->peer->device);
117 #ifdef __TIZEN_PATCH__
118 nc->state = DISCONNECTED;
121 g_dbus_emit_property_changed(conn, path,
122 NETWORK_PEER_INTERFACE, "Connected");
123 g_dbus_emit_property_changed(conn, path,
124 NETWORK_PEER_INTERFACE, "Interface");
125 g_dbus_emit_property_changed(conn, path,
126 NETWORK_PEER_INTERFACE, "UUID");
127 device_remove_disconnect_watch(nc->peer->device, nc->dc_id);
130 btd_service_disconnecting_complete(nc->service, 0);
132 info("%s disconnected", nc->dev);
134 nc->state = DISCONNECTED;
135 memset(nc->dev, 0, sizeof(nc->dev));
136 strncpy(nc->dev, BNEP_INTERFACE, 16);
139 bnep_free(nc->session);
143 static void local_connect_cb(struct network_conn *nc, int err)
145 DBusConnection *conn = btd_get_dbus_connection();
146 const char *pdev = nc->dev;
149 DBusMessage *reply = btd_error_failed(nc->connect,
151 g_dbus_send_message(conn, reply);
153 g_dbus_send_reply(conn, nc->connect, DBUS_TYPE_STRING, &pdev,
157 dbus_message_unref(nc->connect);
161 static void cancel_connection(struct network_conn *nc, int err)
163 btd_service_connecting_complete(nc->service, err);
166 local_connect_cb(nc, err);
169 g_io_channel_shutdown(nc->io, FALSE, NULL);
170 g_io_channel_unref(nc->io);
174 if (nc->state == CONNECTED)
175 bnep_disconnect(nc->session);
177 #ifndef __TIZEN_PATCH__
178 bnep_free(nc->session);
181 nc->state = DISCONNECTED;
184 static void connection_destroy(DBusConnection *conn, void *user_data)
186 struct network_conn *nc = user_data;
188 cancel_connection(nc, -EIO);
191 static void disconnect_cb(struct btd_device *device, gboolean removal,
194 struct network_conn *nc = user_data;
196 info("Network: disconnect %s", device_get_path(nc->peer->device));
198 connection_destroy(NULL, user_data);
201 static void bnep_conn_cb(char *iface, int err, void *data)
203 struct network_conn *nc = data;
205 DBusConnection *conn;
210 error("connect failed %s", strerror(-err));
214 info("%s connected", nc->dev);
216 memcpy(nc->dev, iface, sizeof(nc->dev));
217 btd_service_connecting_complete(nc->service, 0);
220 local_connect_cb(nc, 0);
222 conn = btd_get_dbus_connection();
223 path = device_get_path(nc->peer->device);
225 g_dbus_emit_property_changed(conn, path,
226 NETWORK_PEER_INTERFACE, "Connected");
227 g_dbus_emit_property_changed(conn, path,
228 NETWORK_PEER_INTERFACE, "Interface");
229 g_dbus_emit_property_changed(conn, path,
230 NETWORK_PEER_INTERFACE, "UUID");
232 nc->state = CONNECTED;
233 nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb,
239 cancel_connection(nc, -EIO);
242 static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
244 struct network_conn *nc = data;
248 error("%s", err->message);
252 sk = g_io_channel_unix_get_fd(nc->io);
253 nc->session = bnep_new(sk, BNEP_SVC_PANU, nc->id, BNEP_INTERFACE);
257 perr = bnep_connect(nc->session, bnep_conn_cb, nc);
259 error("bnep connect(): %s (%d)", strerror(-perr), -perr);
263 bnep_set_disconnect(nc->session, bnep_disconn_cb, nc);
266 g_io_channel_unref(nc->io);
273 cancel_connection(nc, -EIO);
276 static DBusMessage *local_connect(DBusConnection *conn,
277 DBusMessage *msg, void *data)
279 struct network_peer *peer = data;
280 struct btd_service *service;
281 struct network_conn *nc;
287 if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc,
288 DBUS_TYPE_INVALID) == FALSE)
289 return btd_error_invalid_args(msg);
291 id = bnep_service_id(svc);
292 uuid = bnep_uuid(id);
295 return btd_error_invalid_args(msg);
297 service = btd_device_get_service(peer->device, uuid);
299 return btd_error_not_supported(msg);
301 nc = btd_service_get_user_data(service);
303 if (nc->connect != NULL)
304 return btd_error_busy(msg);
306 err = connection_connect(nc->service);
308 return btd_error_failed(msg, strerror(-err));
310 nc->connect = dbus_message_ref(msg);
315 /* Connect and initiate BNEP session */
316 int connection_connect(struct btd_service *service)
318 struct network_conn *nc = btd_service_get_user_data(service);
319 struct network_peer *peer = nc->peer;
320 uint16_t id = get_service_id(service);
327 if (nc->state != DISCONNECTED)
330 src = btd_adapter_get_address(device_get_adapter(peer->device));
331 dst = device_get_address(peer->device);
333 nc->io = bt_io_connect(connect_cb, nc,
335 BT_IO_OPT_SOURCE_BDADDR, src,
336 BT_IO_OPT_DEST_BDADDR, dst,
337 BT_IO_OPT_PSM, BNEP_PSM,
338 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
339 BT_IO_OPT_OMTU, BNEP_MTU,
340 BT_IO_OPT_IMTU, BNEP_MTU,
345 nc->state = CONNECTING;
350 int connection_disconnect(struct btd_service *service)
352 struct network_conn *nc = btd_service_get_user_data(service);
354 if (nc->state == DISCONNECTED)
357 connection_destroy(NULL, nc);
362 static DBusMessage *local_disconnect(DBusConnection *conn,
363 DBusMessage *msg, void *data)
365 struct network_peer *peer = data;
368 for (l = peer->connections; l; l = l->next) {
369 struct network_conn *nc = l->data;
372 if (nc->state == DISCONNECTED)
375 err = connection_disconnect(nc->service);
377 return btd_error_failed(msg, strerror(-err));
379 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
382 return btd_error_not_connected(msg);
386 network_property_get_connected(const GDBusPropertyTable *property,
387 DBusMessageIter *iter, void *data)
389 struct network_peer *peer = data;
390 struct network_conn *nc;
391 dbus_bool_t connected;
393 nc = find_connection_by_state(peer->connections, CONNECTED);
394 connected = nc != NULL ? TRUE : FALSE;
396 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &connected);
401 static gboolean network_property_exists(const GDBusPropertyTable *property,
404 struct network_peer *peer = data;
405 struct network_conn *nc;
407 nc = find_connection_by_state(peer->connections, CONNECTED);
415 network_property_get_interface(const GDBusPropertyTable *property,
416 DBusMessageIter *iter, void *data)
418 struct network_peer *peer = data;
419 struct network_conn *nc;
422 nc = find_connection_by_state(peer->connections, CONNECTED);
428 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &iface);
433 static gboolean network_property_get_uuid(const GDBusPropertyTable *property,
434 DBusMessageIter *iter, void *data)
436 struct network_peer *peer = data;
437 struct network_conn *nc;
440 nc = find_connection_by_state(peer->connections, CONNECTED);
444 uuid = bnep_uuid(nc->id);
446 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
451 static void connection_free(void *data)
453 struct network_conn *nc = data;
456 device_remove_disconnect_watch(nc->peer->device, nc->dc_id);
458 connection_destroy(NULL, nc);
461 dbus_message_unref(nc->connect);
463 btd_service_unref(nc->service);
467 static void peer_free(struct network_peer *peer)
469 g_slist_free_full(peer->connections, connection_free);
470 btd_device_unref(peer->device);
474 static void path_unregister(void *data)
476 struct network_peer *peer = data;
478 DBG("Unregistered interface %s on path %s",
479 NETWORK_PEER_INTERFACE, device_get_path(peer->device));
481 peers = g_slist_remove(peers, peer);
485 static const GDBusMethodTable connection_methods[] = {
486 { GDBUS_ASYNC_METHOD("Connect",
487 GDBUS_ARGS({"uuid", "s"}),
488 GDBUS_ARGS({"interface", "s"}),
490 { GDBUS_METHOD("Disconnect",
491 NULL, NULL, local_disconnect) },
495 static const GDBusPropertyTable connection_properties[] = {
496 { "Connected", "b", network_property_get_connected },
497 { "Interface", "s", network_property_get_interface, NULL,
498 network_property_exists },
499 { "UUID", "s", network_property_get_uuid, NULL,
500 network_property_exists },
504 void connection_unregister(struct btd_service *service)
506 struct btd_device *device = btd_service_get_device(service);
507 struct network_conn *conn = btd_service_get_user_data(service);
508 struct network_peer *peer = conn->peer;
509 uint16_t id = get_service_id(service);
511 DBG("%s id %u", device_get_path(device), id);
513 peer->connections = g_slist_remove(peer->connections, conn);
514 connection_free(conn);
516 if (peer->connections != NULL)
519 g_dbus_unregister_interface(btd_get_dbus_connection(),
520 device_get_path(device),
521 NETWORK_PEER_INTERFACE);
524 static struct network_peer *create_peer(struct btd_device *device)
526 struct network_peer *peer;
529 peer = g_new0(struct network_peer, 1);
530 peer->device = btd_device_ref(device);
532 path = device_get_path(device);
534 if (g_dbus_register_interface(btd_get_dbus_connection(), path,
535 NETWORK_PEER_INTERFACE,
537 NULL, connection_properties,
538 peer, path_unregister) == FALSE) {
539 error("D-Bus failed to register %s interface",
540 NETWORK_PEER_INTERFACE);
545 DBG("Registered interface %s on path %s",
546 NETWORK_PEER_INTERFACE, path);
551 int connection_register(struct btd_service *service)
553 struct btd_device *device = btd_service_get_device(service);
554 struct network_peer *peer;
555 struct network_conn *nc;
556 uint16_t id = get_service_id(service);
558 DBG("%s id %u", device_get_path(device), id);
560 peer = find_peer(peers, device);
562 peer = create_peer(device);
565 peers = g_slist_append(peers, peer);
568 nc = g_new0(struct network_conn, 1);
570 nc->service = btd_service_ref(service);
571 nc->state = DISCONNECTED;
574 btd_service_set_user_data(service, nc);
576 DBG("id %u registered", id);
578 peer->connections = g_slist_append(peer->connections, nc);