diff options
-rw-r--r-- | network/connection.c | 280 | ||||
-rw-r--r-- | network/main.c | 1 | ||||
-rw-r--r-- | network/manager.c | 61 |
3 files changed, 181 insertions, 161 deletions
diff --git a/network/connection.c b/network/connection.c index 3e99a865..d0b60c82 100644 --- a/network/connection.c +++ b/network/connection.c @@ -52,9 +52,7 @@ #include "common.h" #include "connection.h" -#define NETWORK_PANU_INTERFACE "org.bluez.network.Peer" -#define NETWORK_GN_INTERFACE "org.bluez.network.Hub" -#define NETWORK_NAP_INTERFACE "org.bluez.network.Router" +#define NETWORK_PEER_INTERFACE "org.bluez.network.Peer" typedef enum { CONNECTED, @@ -62,15 +60,20 @@ typedef enum { DISCONNECTED } conn_state; -struct network_conn { - DBusMessage *msg; +struct network_peer { bdaddr_t src; bdaddr_t dst; char *path; /* D-Bus path */ + GSList *connections; +}; + +struct network_conn { + DBusMessage *msg; char dev[16]; /* Interface name */ uint16_t id; /* Role: Service Class Identifier */ conn_state state; int sk; + struct network_peer *peer; }; struct __service_16 { @@ -80,14 +83,34 @@ struct __service_16 { static DBusConnection *connection = NULL; static const char *prefix = NULL; -static GSList *connections = NULL; +static GSList *peers = NULL; + +static struct network_peer *find_peer(GSList *list, const char *path) +{ + GSList *l; + + for (l = list; l; l = l->next) { + struct network_peer *peer = l->data; + + if (!strcmp(peer->path, path)) + return peer; + } + + return NULL; +} -gint find_connection(gconstpointer a, gconstpointer b) +static struct network_conn *find_connection(GSList *list, uint16_t id) { - const struct network_conn *nc = a; - const char *path = b; + GSList *l; + + for (l = list; l; l = l->next) { + struct network_conn *nc = l->data; - return strcmp(nc->path, path); + if (nc->id == id) + return nc; + } + + return NULL; } static inline DBusMessage *not_supported(DBusMessage *msg) @@ -120,35 +143,17 @@ static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err) err ? strerror(err) : "Connection attempt failed"); } -static const char *id2iface(uint16_t id) -{ - switch (id) { - case BNEP_SVC_PANU: - return NETWORK_PANU_INTERFACE; - break; - case BNEP_SVC_GN: - return NETWORK_GN_INTERFACE; - break; - case BNEP_SVC_NAP: - return NETWORK_NAP_INTERFACE; - break; - default: - return NULL; - } -} - static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct network_conn *nc = data; if (connection != NULL) { - const char *interface = id2iface(nc->id); - - g_dbus_emit_signal(connection, nc->path, - interface, - "Disconnected", - DBUS_TYPE_INVALID); + const char *device = nc->dev; + g_dbus_emit_signal(connection, nc->peer->path, + NETWORK_PEER_INTERFACE, "Disconnected", + DBUS_TYPE_STRING, &device, + DBUS_TYPE_INVALID); } info("%s disconnected", nc->dev); @@ -171,7 +176,7 @@ static gboolean bnep_connect_cb(GIOChannel *chan, GIOCondition cond, gsize r; int sk; DBusMessage *reply; - const char *pdev; + const char *pdev, *uuid; if (cond & G_IO_NVAL) return FALSE; @@ -224,16 +229,18 @@ static gboolean bnep_connect_cb(GIOChannel *chan, GIOCondition cond, } bnep_if_up(nc->dev, nc->id); - g_dbus_emit_signal(connection, nc->path, - id2iface(nc->id), - "Connected", - DBUS_TYPE_INVALID); - pdev = nc->dev; + uuid = bnep_uuid(nc->id); - reply = g_dbus_create_reply(nc->msg, DBUS_TYPE_STRING, &pdev, - DBUS_TYPE_INVALID); - g_dbus_send_message(connection, reply); + g_dbus_send_reply(connection, nc->msg, + DBUS_TYPE_STRING, &pdev, + DBUS_TYPE_INVALID); + + g_dbus_emit_signal(connection, nc->peer->path, + NETWORK_PEER_INTERFACE, "Connected", + DBUS_TYPE_STRING, &pdev, + DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_INVALID); nc->state = CONNECTED; @@ -317,33 +324,32 @@ failed: g_dbus_send_message(connection, reply); } -static DBusMessage *get_interface(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct network_conn *nc = data; - const char *pdev = nc->dev; - - if (nc->state != CONNECTED) - return not_connected(msg); - - return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &pdev, - DBUS_TYPE_INVALID); -} - /* Connect and initiate BNEP session */ static DBusMessage *connection_connect(DBusConnection *conn, DBusMessage *msg, void *data) { - struct network_conn *nc = data; + struct network_peer *peer = data; + struct network_conn *nc; + const char *svc; + uint16_t id; int err; + if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc, + DBUS_TYPE_INVALID) == FALSE) + return NULL; + + id = bnep_service_id(svc); + nc = find_connection(peer->connections, id); + if (!nc) + return not_supported(msg); + if (nc->state != DISCONNECTED) return already_connected(msg); nc->state = CONNECTING; nc->msg = dbus_message_ref(msg); - err = bt_l2cap_connect(&nc->src, &nc->dst, BNEP_PSM, BNEP_MTU, + err = bt_l2cap_connect(&peer->src, &peer->dst, BNEP_PSM, BNEP_MTU, connect_cb, nc); if (err < 0) { error("Connect failed. %s(%d)", strerror(errno), errno); @@ -361,11 +367,11 @@ static DBusMessage *connection_cancel(DBusConnection *conn, { struct network_conn *nc = data; - if (nc->state != CONNECTING) - return no_pending_connect(msg); - - close(nc->sk); - nc->state = DISCONNECTED; + if (nc->state == CONNECTED) { + bnep_if_down(nc->dev); + bnep_kill_connection(&nc->peer->dst); + } else + close(nc->sk); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } @@ -373,22 +379,36 @@ static DBusMessage *connection_cancel(DBusConnection *conn, static DBusMessage *connection_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { - struct network_conn *nc = data; + struct network_peer *peer = data; + GSList *l; - if (nc->state != CONNECTED) - return not_connected(msg); + for (l = peer->connections; l; l = l->next) { + struct network_conn *nc = l->data; - bnep_if_down(nc->dev); - bnep_kill_connection(&nc->dst); + if (nc->state == DISCONNECTED) + continue; - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + return connection_cancel(conn, msg, nc); + } + + return not_connected(msg); } static DBusMessage *is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { - struct network_conn *nc = data; - gboolean up = (nc->state == CONNECTED); + struct network_peer *peer = data; + GSList *l; + dbus_bool_t up = FALSE; + + for (l = peer->connections; l; l = l->next) { + struct network_conn *nc = l->data; + + if (nc->state != CONNECTED) + continue; + + up = TRUE; + } return g_dbus_create_reply(msg, DBUS_TYPE_BOOLEAN, &up, DBUS_TYPE_INVALID); @@ -396,94 +416,126 @@ static DBusMessage *is_connected(DBusConnection *conn, static void connection_free(struct network_conn *nc) { - if (!nc) - return; - - if (nc->path) - g_free(nc->path); - if (nc->state == CONNECTED) { bnep_if_down(nc->dev); - bnep_kill_connection(&nc->dst); - } + bnep_kill_connection(&nc->peer->dst); + } else if (nc->state == CONNECTING) + close(nc->sk); g_free(nc); nc = NULL; } +static void peer_free(struct network_peer *peer) +{ + g_slist_foreach(peer->connections, (GFunc) connection_free, NULL); + g_slist_free(peer->connections); + g_free(peer->path); + g_free(peer); +} + static void path_unregister(void *data) { - struct network_conn *nc = data; - const char *interface = id2iface(nc->id); + struct network_peer *peer = data; - info("Unregistered interface %s on path %s", interface, nc->path); + info("Unregistered interface %s on path %s", + NETWORK_PEER_INTERFACE, peer->path); - connections = g_slist_remove(connections, nc); - connection_free(nc); + peers = g_slist_remove(peers, peer); + peer_free(peer); } static GDBusMethodTable connection_methods[] = { - { "GetInterface", "", "s", get_interface }, - { "Connect", "", "s", connection_connect, + { "Connect", "s", "s", connection_connect, G_DBUS_METHOD_FLAG_ASYNC }, - { "CancelConnect", "", "", connection_cancel }, { "Disconnect", "", "", connection_disconnect }, { "IsConnected", "", "b", is_connected }, { } }; static GDBusSignalTable connection_signals[] = { - { "Connected", "" }, - { "Disconnected", "" }, + { "Connected", "ss" }, + { "Disconnected", "s" }, { } }; void connection_unregister(const char *path, uint16_t id) { - const char *interface = id2iface(id); + struct network_peer *peer; + struct network_conn *nc; + + peer = find_peer(peers, path); + if (!peer) + return; + + nc = find_connection(peer->connections, id); + if (!nc) + return; + + peer->connections = g_slist_remove(peer->connections, nc); + connection_free(nc); + if (peer->connections) + return; + + g_dbus_unregister_interface(connection, path, NETWORK_PEER_INTERFACE); +} + +static struct network_peer *create_peer(const char *path, bdaddr_t *src, + bdaddr_t *dst) +{ + struct network_peer *peer; + + peer = g_new0(struct network_peer, 1); + peer->path = g_strdup(path); + bacpy(&peer->src, src); + bacpy(&peer->dst, dst); + + if (g_dbus_register_interface(connection, path, + NETWORK_PEER_INTERFACE, + connection_methods, + connection_signals, NULL, + peer, path_unregister) == FALSE) { + error("D-Bus failed to register %s interface", + NETWORK_PEER_INTERFACE); + g_free(peer); + return NULL; + } + + info("Registered interface %s on path %s", + NETWORK_PEER_INTERFACE, path); - g_dbus_unregister_interface(connection, path, interface); + return peer; } int connection_register(const char *path, bdaddr_t *src, bdaddr_t *dst, uint16_t id) { + struct network_peer *peer; struct network_conn *nc; - bdaddr_t default_src; - int dev_id; - const char *interface; if (!path) return -EINVAL; - bacpy(&default_src, BDADDR_ANY); - dev_id = hci_get_route(&default_src); - if (dev_id < 0 || hci_devba(dev_id, &default_src) < 0) - return -1; - - nc = g_new0(struct network_conn, 1); - interface = id2iface(id); - - if (g_dbus_register_interface(connection, path, - interface, - connection_methods, - connection_signals, NULL, - nc, path_unregister) == FALSE) { - error("D-Bus failed to register %s interface", interface); - return -1; + peer = find_peer(peers, path); + if (!peer) { + peer = create_peer(path, src, dst); + if (!peer) + return -1; + peers = g_slist_append(peers, peer); } - nc->path = g_strdup(path); - bacpy(&nc->src, src); - bacpy(&nc->dst, dst); + nc = find_connection(peer->connections, id); + if (nc) + return 0; + + nc = g_new0(struct network_conn, 1); nc->id = id; memset(nc->dev, 0, 16); strncpy(nc->dev, prefix, strlen(prefix)); nc->state = DISCONNECTED; + nc->peer = peer; - connections = g_slist_append(connections, nc); - - info("Registered interface %s on path %s", interface, path); + peer->connections = g_slist_append(peer->connections, nc); return 0; } diff --git a/network/main.c b/network/main.c index e4220928..414ff938 100644 --- a/network/main.c +++ b/network/main.c @@ -33,7 +33,6 @@ #include <gdbus.h> #include "plugin.h" -#include "device.h" #include "logging.h" #include "manager.h" diff --git a/network/manager.c b/network/manager.c index b3ba1cdb..22a6e70c 100644 --- a/network/manager.c +++ b/network/manager.c @@ -45,8 +45,8 @@ #include "textfile.h" #include "glib-helper.h" -#include "../hcid/adapter.h" -#include "../hcid/device.h" +#include "adapter.h" +#include "device.h" #include "error.h" #include "bridge.h" #include "manager.h" @@ -80,12 +80,14 @@ static void register_server(uint16_t id) server_store(path); } -static int network_probe(struct btd_device *device, uint16_t id) +static int network_probe(struct btd_device_driver *driver, + struct btd_device *device, GSList *records) { struct adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); const char *source, *destination; bdaddr_t src, dst; + uint16_t id; DBG("path %s", path); @@ -94,74 +96,41 @@ static int network_probe(struct btd_device *device, uint16_t id) str2ba(source, &src); str2ba(destination, &dst); + id = bnep_service_id(driver->uuids[0]); return connection_register(path, &src, &dst, id); } -static int panu_probe(struct btd_device_driver *driver, - struct btd_device *device, GSList *records) -{ - return network_probe(device, BNEP_SVC_PANU); -} - -static int gn_probe(struct btd_device_driver *driver, - struct btd_device *device, GSList *records) -{ - return network_probe(device, BNEP_SVC_GN); -} - -static int nap_probe(struct btd_device_driver *driver, - struct btd_device *device, GSList *records) -{ - return network_probe(device, BNEP_SVC_NAP); -} - -static void network_remove(struct btd_device *device, uint16_t id) +static void network_remove(struct btd_device_driver *driver, + struct btd_device *device) { const gchar *path = device_get_path(device); + uint16_t id = bnep_service_id(driver->uuids[0]); DBG("path %s", path); connection_unregister(path, id); } -static void panu_remove(struct btd_device_driver *driver, - struct btd_device *device) -{ - network_remove(device, BNEP_SVC_PANU); -} - -static void gn_remove(struct btd_device_driver *driver, - struct btd_device *device) -{ - network_remove(device, BNEP_SVC_GN); -} - -static void nap_remove(struct btd_device_driver *driver, - struct btd_device *device) -{ - network_remove(device, BNEP_SVC_NAP); -} - static struct btd_device_driver network_panu_driver = { .name = "network-panu", .uuids = BTD_UUIDS(PANU_UUID), - .probe = panu_probe, - .remove = panu_remove, + .probe = network_probe, + .remove = network_remove, }; static struct btd_device_driver network_gn_driver = { .name = "network-gn", .uuids = BTD_UUIDS(GN_UUID), - .probe = gn_probe, - .remove = gn_remove, + .probe = network_probe, + .remove = network_remove, }; static struct btd_device_driver network_nap_driver = { .name = "network-nap", .uuids = BTD_UUIDS(NAP_UUID), - .probe = nap_probe, - .remove = nap_remove, + .probe = network_probe, + .remove = network_remove, }; int network_manager_init(DBusConnection *conn, struct network_conf *service_conf) |