summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--network/manager.c322
1 files changed, 251 insertions, 71 deletions
diff --git a/network/manager.c b/network/manager.c
index a8b9974f..58c335bb 100644
--- a/network/manager.c
+++ b/network/manager.c
@@ -51,40 +51,28 @@ struct manager {
GSList *connections; /* Network registered connections paths */
};
+struct pending_reply {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ struct manager *mgr;
+ uint16_t id;
+ char *addr;
+ char *path;
+ char *adapter_path;
+};
+
static DBusConnection *connection = NULL;
-static DBusHandlerResult list_paths(DBusConnection *conn, DBusMessage *msg,
- GSList *list)
+static void pending_reply_free(struct pending_reply *pr)
{
- DBusMessage *reply;
- DBusMessageIter iter;
- DBusMessageIter array_iter;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ if (pr->addr)
+ g_free(pr->addr);
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &array_iter);
+ if (pr->path)
+ g_free(pr->path);
- for (; list; list = list->next) {
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_STRING,
- &list->data);
- }
-
- dbus_message_iter_close_container(&iter, &array_iter);
-
- return send_message_and_unref(conn, reply);
-}
-
-static DBusHandlerResult list_servers(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct manager *mgr = data;
-
- return list_paths(conn, msg, mgr->servers);
+ if (pr->adapter_path)
+ g_free(pr->adapter_path);
}
static DBusHandlerResult create_path(DBusConnection *conn,
@@ -116,44 +104,29 @@ static DBusHandlerResult create_path(DBusConnection *conn,
return send_message_and_unref(conn, reply);
}
-static DBusHandlerResult create_server(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static DBusHandlerResult list_paths(DBusConnection *conn, DBusMessage *msg,
+ GSList *list)
{
- struct manager *mgr = data;
- DBusError derr;
- const char *str;
- char *path;
- uint16_t id;
-
- dbus_error_init(&derr);
- if (!dbus_message_get_args(msg, &derr,
- DBUS_TYPE_STRING, &str,
- DBUS_TYPE_INVALID)) {
- err_invalid_args(conn, msg, derr.message);
- dbus_error_free(&derr);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- id = bnep_service_id(str);
- if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))
- return err_invalid_args(conn, msg, "Not supported");
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
- path = g_new0(char, 32);
- snprintf(path, 32, NETWORK_PATH "/server/%s", bnep_name(id));
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
- /* Path already registered */
- if (g_slist_find_custom(mgr->servers, path, (GCompareFunc) strcmp))
- return create_path(conn, msg, path, NULL); /* Return already exist error */
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
- if (server_register(conn, path, id) < 0) {
- err_failed(conn, msg, "D-Bus path registration failed");
- g_free(path);
- return DBUS_HANDLER_RESULT_HANDLED;
+ for (; list; list = list->next) {
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING,
+ &list->data);
}
+ dbus_message_iter_close_container(&iter, &array_iter);
- mgr->servers = g_slist_append(mgr->servers, g_strdup(path));
-
- return create_path(conn, msg, path, "ServerCreated");
+ return send_message_and_unref(conn, reply);
}
static DBusHandlerResult remove_path(DBusConnection *conn,
@@ -200,6 +173,206 @@ static DBusHandlerResult remove_path(DBusConnection *conn,
return send_message_and_unref(conn, reply);
}
+static void pan_record_reply(DBusPendingCall *call, void *data)
+{
+ struct pending_reply *pr = data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ int len;
+ uint8_t *rec_bin;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed"))
+ err_connection_failed(pr->conn, pr->msg, derr.message);
+ else
+ err_not_supported(pr->conn, pr->msg);
+
+ error("GetRemoteServiceRecord failed: %s(%s)", derr.name,
+ derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("Invalid PAN service record length");
+ goto fail;
+ }
+
+
+ if (connection_register(pr->conn, pr->path, pr->addr, pr->id) == -1) {
+ err_failed(pr->conn, pr->msg, "D-Bus path registration failed");
+ goto fail;
+ }
+
+ pr->mgr->connections = g_slist_append(pr->mgr->connections,
+ g_strdup(pr->path));
+
+ create_path(pr->conn, pr->msg, g_strdup (pr->path), "ConnectionCreated");
+fail:
+ dbus_error_free(&derr);
+ pending_reply_free(pr);
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static int get_record(struct pending_reply *pr, uint32_t handle,
+ DBusPendingCallNotifyFunction cb)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+
+ msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
+ "org.bluez.Adapter", "GetRemoteServiceRecord");
+ if (!msg)
+ return -1;
+
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &pr->addr,
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
+ error("Can't send D-Bus message.");
+ return -1;
+ }
+
+ dbus_pending_call_set_notify(pending, cb, pr, NULL);
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static void pan_handle_reply(DBusPendingCall *call, void *data)
+{
+ struct pending_reply *pr = data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ uint32_t *phandle;
+ int len;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed"))
+ err_connection_failed(pr->conn, pr->msg, derr.message);
+ else
+ err_not_supported(pr->conn, pr->msg);
+
+ error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!len) {
+ err_not_supported(pr->conn, pr->msg);
+ goto fail;
+ }
+
+ if (get_record(pr, *phandle, pan_record_reply) < 0) {
+ err_not_supported(pr->conn, pr->msg);
+ goto fail;
+ }
+
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+ return;
+fail:
+ dbus_error_free(&derr);
+ pending_reply_free(pr);
+}
+
+static int get_handles(struct pending_reply *pr, DBusPendingCallNotifyFunction cb)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+ const char *uuid;
+
+ msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
+ "org.bluez.Adapter", "GetRemoteServiceHandles");
+ if (!msg)
+ return -1;
+
+ uuid = bnep_uuid(pr->id);
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &pr->addr,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
+ error("Can't send D-Bus message.");
+ return -1;
+ }
+
+ dbus_pending_call_set_notify(pending, cb, pr, NULL);
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static DBusHandlerResult list_servers(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct manager *mgr = data;
+
+ return list_paths(conn, msg, mgr->servers);
+}
+
+static DBusHandlerResult create_server(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct manager *mgr = data;
+ DBusError derr;
+ const char *str;
+ char *path;
+ int id;
+
+ dbus_error_init(&derr);
+ if (!dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID)) {
+ err_invalid_args(conn, msg, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ id = bnep_service_id(str);
+ if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))
+ return err_invalid_args(conn, msg, "Not supported");
+
+ path = g_new0(char, 32);
+ snprintf(path, 32, NETWORK_PATH "/server/%X", id);
+
+ /* Path already registered */
+ if (g_slist_find_custom(mgr->servers, path, (GCompareFunc) strcmp))
+ return create_path(conn, msg, path, NULL); /* Return already exist error */
+
+ /* FIXME: define which type should be used -- string/uuid str/uui128 */
+ if (server_register(conn, path, id) == -1) {
+ err_failed(conn, msg, "D-Bus path registration failed");
+ g_free(path);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ mgr->servers = g_slist_append(mgr->servers, g_strdup(path));
+
+ return create_path(conn, msg, path, "ServerCreated");
+}
+
static DBusHandlerResult remove_server(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -220,11 +393,12 @@ static DBusHandlerResult create_connection(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct manager *mgr = data;
+ struct pending_reply *pr;
static int uid = 0;
DBusError derr;
+ char src_addr[18];
const char *addr;
const char *str;
- char *path;
uint16_t id;
dbus_error_init(&derr);
@@ -241,18 +415,24 @@ static DBusHandlerResult create_connection(DBusConnection *conn,
if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))
return err_invalid_args(conn, msg, "Not supported");
- path = g_new0(char, 32);
- snprintf(path, 32, NETWORK_PATH "/connection%d", uid++);
-
- if (connection_register(conn, path, addr, id) == -1) {
+ pr = g_new(struct pending_reply, 1);
+ pr->conn = conn;
+ pr->msg = dbus_message_ref(msg);
+ pr->mgr = mgr;
+ pr->addr = g_strdup(addr);
+ pr->id = id;
+ pr->path = g_new0(char, 48);
+ snprintf(pr->path, 48, NETWORK_PATH "/connection%d", uid++);
+ ba2str(&mgr->src, src_addr);
+ pr->adapter_path = g_new0(char, 32);
+ snprintf(pr->adapter_path , 32, "/org/bluez/hci%d", hci_devid(src_addr));
+
+ if (get_handles(pr, pan_handle_reply) < 0) {
err_failed(conn, msg, "D-Bus path registration failed");
- g_free(path);
- return DBUS_HANDLER_RESULT_HANDLED;
+ pending_reply_free(pr);
}
- mgr->connections = g_slist_append(mgr->connections, g_strdup(path));
-
- return create_path(conn, msg, path, "ConnectionCreated");
+ return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult remove_connection(DBusConnection *conn,