summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hcid/dbus-adapter.c90
-rw-r--r--hcid/dbus-common.c95
-rw-r--r--hcid/dbus-error.c8
-rw-r--r--hcid/dbus-test.c204
-rw-r--r--hcid/dbus.h5
5 files changed, 302 insertions, 100 deletions
diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c
index b499102b..ac5b07b1 100644
--- a/hcid/dbus-adapter.c
+++ b/hcid/dbus-adapter.c
@@ -27,7 +27,6 @@
#include <stdio.h>
#include <errno.h>
-#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/param.h>
@@ -166,44 +165,6 @@ static const char *toy_minor_cls[] = {
"game"
};
-static int check_address(const char *addr)
-{
- char tmp[18];
- char *ptr = tmp;
-
- if (!addr)
- return -1;
-
- if (strlen(addr) != 17)
- return -1;
-
- memcpy(tmp, addr, 18);
-
- while (*ptr) {
-
- *ptr = toupper(*ptr);
- if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
- return -1;
-
- ptr++;
- *ptr = toupper(*ptr);
- if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
- return -1;
-
- ptr++;
- *ptr = toupper(*ptr);
- if (*ptr == 0)
- break;
-
- if (*ptr != ':')
- return -1;
-
- ptr++;
- }
-
- return 0;
-}
-
int pending_remote_name_cancel(struct hci_dbus_data *pdata)
{
struct discovered_dev_info *dev, match;
@@ -1757,57 +1718,6 @@ static DBusHandlerResult handle_dev_disconnect_remote_device_req(DBusConnection
}
-static int l2raw_connect(const char *local, const bdaddr_t *remote)
-{
- struct sockaddr_l2 addr;
- long arg;
- int sk;
-
- sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
- if (sk < 0) {
- error("Can't create socket: %s (%d)", strerror(errno), errno);
- return sk;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- str2ba(local, &addr.l2_bdaddr);
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- error("Can't bind socket: %s (%d)", strerror(errno), errno);
- goto failed;
- }
-
- arg = fcntl(sk, F_GETFL);
- if (arg < 0) {
- error("Can't get file flags: %s (%d)", strerror(errno), errno);
- goto failed;
- }
-
- arg |= O_NONBLOCK;
- if (fcntl(sk, F_SETFL, arg) < 0) {
- error("Can't set file flags: %s (%d)", strerror(errno), errno);
- goto failed;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, remote);
-
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- if (errno == EAGAIN || errno == EINPROGRESS)
- return sk;
- error("Can't connect socket: %s (%d)", strerror(errno), errno);
- goto failed;
- }
-
- return sk;
-
-failed:
- close(sk);
- return -1;
-}
-
static void reply_authentication_failure(struct bonding_request_info *bonding)
{
DBusMessage *reply;
diff --git a/hcid/dbus-common.c b/hcid/dbus-common.c
index 62da70d6..e95b9401 100644
--- a/hcid/dbus-common.c
+++ b/hcid/dbus-common.c
@@ -30,9 +30,16 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <arpa/inet.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
@@ -374,4 +381,92 @@ int str2uuid(uuid_t *uuid, const char *string)
return -1;
}
+int l2raw_connect(const char *local, const bdaddr_t *remote)
+{
+ struct sockaddr_l2 addr;
+ long arg;
+ int sk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (sk < 0) {
+ error("Can't create socket: %s (%d)", strerror(errno), errno);
+ return sk;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba(local, &addr.l2_bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ error("Can't bind socket: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ arg = fcntl(sk, F_GETFL);
+ if (arg < 0) {
+ error("Can't get file flags: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ arg |= O_NONBLOCK;
+ if (fcntl(sk, F_SETFL, arg) < 0) {
+ error("Can't set file flags: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, remote);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (errno == EAGAIN || errno == EINPROGRESS)
+ return sk;
+ error("Can't connect socket: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ return sk;
+
+failed:
+ close(sk);
+ return -1;
+}
+
+int check_address(const char *addr)
+{
+ char tmp[18];
+ char *ptr = tmp;
+
+ if (!addr)
+ return -1;
+
+ if (strlen(addr) != 17)
+ return -1;
+
+ memcpy(tmp, addr, 18);
+
+ while (*ptr) {
+
+ *ptr = toupper(*ptr);
+ if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
+ return -1;
+
+ ptr++;
+ *ptr = toupper(*ptr);
+ if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
+ return -1;
+
+ ptr++;
+ *ptr = toupper(*ptr);
+ if (*ptr == 0)
+ break;
+
+ if (*ptr != ':')
+ return -1;
+
+ ptr++;
+ }
+
+ return 0;
+}
diff --git a/hcid/dbus-error.c b/hcid/dbus-error.c
index 82415cef..3944ffec 100644
--- a/hcid/dbus-error.c
+++ b/hcid/dbus-error.c
@@ -143,16 +143,16 @@ static DBusHandlerResult error_in_progress(DBusConnection *conn, DBusMessage *ms
dbus_message_new_error(msg, ERROR_INTERFACE ".InProgress", str));
}
-static DBusHandlerResult error_not_in_progress(DBusConnection *conn, DBusMessage *msg, const char *str)
+static DBusHandlerResult error_canceled(DBusConnection *conn, DBusMessage *msg, const char *str)
{
return send_reply_and_unref(conn,
- dbus_message_new_error(msg, ERROR_INTERFACE ".NotInProgress", str));
+ dbus_message_new_error(msg, ERROR_INTERFACE ".Canceled", str));
}
-static DBusHandlerResult error_canceled(DBusConnection *conn, DBusMessage *msg, const char *str)
+DBusHandlerResult error_not_in_progress(DBusConnection *conn, DBusMessage *msg, const char *str)
{
return send_reply_and_unref(conn,
- dbus_message_new_error(msg, ERROR_INTERFACE ".Canceled", str));
+ dbus_message_new_error(msg, ERROR_INTERFACE ".NotInProgress", str));
}
DBusHandlerResult error_connect_canceled(DBusConnection *conn, DBusMessage *msg)
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;
diff --git a/hcid/dbus.h b/hcid/dbus.h
index b32fec9f..16951e3b 100644
--- a/hcid/dbus.h
+++ b/hcid/dbus.h
@@ -175,6 +175,7 @@ DBusHandlerResult error_no_such_adapter(DBusConnection *conn, DBusMessage *msg);
DBusHandlerResult error_not_available(DBusConnection *conn, DBusMessage *msg);
DBusHandlerResult error_request_deferred(DBusConnection *conn, DBusMessage *msg);
DBusHandlerResult error_not_connected(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult error_not_in_progress(DBusConnection *conn, DBusMessage *msg, const char *str);
DBusHandlerResult error_unsupported_major_class(DBusConnection *conn, DBusMessage *msg);
DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn, DBusMessage *msg, int err);
DBusHandlerResult error_bonding_already_exists(DBusConnection *conn, DBusMessage *msg);
@@ -202,6 +203,10 @@ int name_listener_add(DBusConnection *connection, const char *name,
int name_listener_remove(DBusConnection *connection, const char *name,
name_cb_t func, void *user_data);
+int l2raw_connect(const char *local, const bdaddr_t *remote);
+
+int check_address(const char *addr);
+
DBusHandlerResult handle_test_method(DBusConnection *conn, DBusMessage *msg, void *data);
DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg, void *data);