summaryrefslogtreecommitdiffstats
path: root/hcid/dbus-test.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2006-10-03 19:19:58 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2006-10-03 19:19:58 +0000
commit6af2f85288b058b3a575622b01af6869100a7398 (patch)
treee50eed9b3937603279904b5c982ddb024d67c04e /hcid/dbus-test.c
parent7880ff6d0f3b877d16f5d1119120ee73344dd402 (diff)
More AuditRemoteDevice implementation
Diffstat (limited to 'hcid/dbus-test.c')
-rw-r--r--hcid/dbus-test.c204
1 files changed, 198 insertions, 6 deletions
diff --git a/hcid/dbus-test.c b/hcid/dbus-test.c
index d29012fe..a8f2fd7b 100644
--- a/hcid/dbus-test.c
+++ b/hcid/dbus-test.c
@@ -33,21 +33,182 @@
#include "hcid.h"
#include "dbus.h"
+struct audit {
+ bdaddr_t addr;
+
+ /* We need to store the path instead of a pointer to the data
+ * because by the time the audit is processed the adapter
+ * might have gotten removed. Storing only the path allows us to
+ * detect this scenario */
+ char adapter_path[PATH_MAX];
+
+ char *requestor;
+ DBusConnection *conn;
+
+ GIOChannel *io;
+ guint io_id;
+};
+
+struct slist *audits;
+
+static struct audit *audit_new(DBusConnection *conn, DBusMessage *msg, bdaddr_t *addr)
+{
+ struct audit *audit;
+ const char *path;
+ const char *requestor;
+
+ path = dbus_message_get_path(msg);
+ requestor = dbus_message_get_sender(msg);
+
+ audit = malloc(sizeof(struct audit));
+ if (!audit)
+ return NULL;
+ memset(audit, 0, sizeof(struct audit));
+
+ audit->requestor = strdup(requestor);
+ if (!audit->requestor) {
+ free(audit);
+ return NULL;
+ }
+
+ bacpy(&audit->addr, addr);
+ strncpy(audit->adapter_path, path, sizeof(audit->adapter_path) - 1);
+ audit->conn = dbus_connection_ref(conn);
+
+ return audit;
+}
+
+static void audit_free(struct audit *audit)
+{
+ free(audit->requestor);
+ dbus_connection_unref(audit->conn);
+ free(audit);
+}
+
+static void audit_requestor_exited(const char *name, struct audit *audit)
+{
+ debug("AuditRemoteDevice requestor %s exited", name);
+ audits = slist_remove(audits, audit);
+ if (audit->io)
+ g_io_channel_close(audit->io);
+ audit_free(audit);
+}
+
+int audit_addr_cmp(const void *a, const void *b)
+{
+ const struct audit *audit = a;
+ const bdaddr_t *addr = b;
+
+ return bacmp(&audit->addr, addr);
+}
+
+static gboolean audit_in_progress(void)
+{
+ struct slist *l;
+
+ for (l = audits; l != NULL; l = l->next) {
+ struct audit *audit = l->data;
+ if (audit->io)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean l2raw_connect_complete(GIOChannel *io, GIOCondition cond, struct audit *audit)
+{
+ if (cond & G_IO_NVAL) {
+ g_io_channel_unref(io);
+ return FALSE;
+ }
+
+ if (cond & (G_IO_ERR | G_IO_HUP)) {
+ error("Error on raw l2cap socket");
+ g_io_channel_close(io);
+ return FALSE;
+ }
+
+ debug("AuditRemoteDevice: connected");
+
+ /* FIXME: Instead of closing and unrefing we should proceed with the audit */
+ g_io_channel_close(io);
+ g_io_channel_unref(io);
+ audits = slist_remove(audits, audit);
+ name_listener_remove(audit->conn, audit->requestor,
+ (name_cb_t) audit_requestor_exited, audit);
+ audit_free(audit);
+
+ return FALSE;
+}
+
static DBusHandlerResult audit_remote_device(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
+ DBusError err;
+ bdaddr_t dba;
const char *address;
+ struct audit *audit;
+ struct hci_dbus_data *dbus_data = data;
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID))
+ dbus_error_init(&err);
+ dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&err)) {
+ error("Can't extract message arguments:%s", err.message);
+ dbus_error_free(&err);
return error_invalid_arguments(conn, msg);
+ }
+
+ if (check_address(address) < 0)
+ return error_invalid_arguments(conn, msg);
+
+ str2ba(address, &dba);
+
+ /* check if there is a pending discover: requested by D-Bus/non clients */
+ if (dbus_data->disc_active || (dbus_data->pdisc_active && !dbus_data->pinq_idle))
+ return error_discover_in_progress(conn, msg);
+
+ pending_remote_name_cancel(dbus_data);
+
+ if (dbus_data->bonding)
+ return error_bonding_in_progress(conn, msg);
+
+ if (slist_find(dbus_data->pin_reqs, &dba, pin_req_cmp))
+ return error_bonding_in_progress(conn, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ audit = audit_new(conn, msg, &dba);
+ if (!audit) {
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ if (!audit_in_progress()) {
+ int sk;
+
+ sk = l2raw_connect(dbus_data->address, &dba);
+ if (sk < 0) {
+ audit_free(audit);
+ dbus_message_unref(reply);
+ return error_connection_attempt_failed(conn, msg, 0);
+ }
+
+ audit->io = g_io_channel_unix_new(sk);
+ audit->io_id = g_io_add_watch(audit->io,
+ G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ (GIOFunc) l2raw_connect_complete, audit);
+ }
+
+ name_listener_add(conn, dbus_message_get_sender(msg),
+ (name_cb_t) audit_requestor_exited, audit);
+
+ audits = slist_append(audits, audit);
+
return send_reply_and_unref(conn, reply);
}
@@ -55,13 +216,44 @@ static DBusHandlerResult cancel_audit_remote_device(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
+ DBusError err;
const char *address;
+ bdaddr_t dba;
+ struct slist *l;
+ struct audit *audit;
+
+ dbus_error_init(&err);
+ dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&err)) {
+ error("Can't extract message arguments:%s", err.message);
+ dbus_error_free(&err);
+ return error_invalid_arguments(conn, msg);
+ }
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID))
+ if (check_address(address) < 0)
return error_invalid_arguments(conn, msg);
+ str2ba(address, &dba);
+
+ l = slist_find(audits, &dba, audit_addr_cmp);
+ if (!l)
+ return error_not_in_progress(conn, msg, "Audit not in progress");
+
+ audit = l->data;
+
+ if (strcmp(audit->requestor, dbus_message_get_sender(msg)))
+ return error_not_authorized(conn, msg);
+
+ if (audit->io)
+ g_io_channel_close(audit->io);
+
+ audits = slist_remove(audits, audit);
+ name_listener_remove(audit->conn, audit->requestor,
+ (name_cb_t) audit_requestor_exited, audit);
+ audit_free(audit);
+
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;