summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/list.c13
-rw-r--r--common/list.h5
-rw-r--r--hcid/dbus-security.c221
-rw-r--r--hcid/dbus.c2
-rw-r--r--hcid/dbus.h6
5 files changed, 215 insertions, 32 deletions
diff --git a/common/list.c b/common/list.c
index bda2b564..c6d8cb98 100644
--- a/common/list.c
+++ b/common/list.c
@@ -86,6 +86,19 @@ struct slist *slist_remove(struct slist *list, void *data)
return list;
}
+struct slist *slist_find(struct slist *list, const void *data,
+ cmp_func_t cmp_func)
+{
+ struct slist *l;
+
+ for (l = list; l != NULL; l = l->next) {
+ if (!cmp_func(l->data, data))
+ return l;
+ }
+
+ return NULL;
+}
+
void slist_free(struct slist *list)
{
struct slist *l, *next;
diff --git a/common/list.h b/common/list.h
index b16bf946..1838370c 100644
--- a/common/list.h
+++ b/common/list.h
@@ -30,10 +30,15 @@ struct slist {
struct slist *next;
};
+typedef int (*cmp_func_t)(const void *a, const void *b);
+
struct slist *slist_append(struct slist *list, void *data);
struct slist *slist_remove(struct slist *list, void *data);
+struct slist *slist_find(struct slist *list, const void *data,
+ cmp_func_t cmp_func);
+
void slist_free(struct slist *list);
#endif /* __LIST_H */
diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c
index f3113d14..7fe9e313 100644
--- a/hcid/dbus-security.c
+++ b/hcid/dbus-security.c
@@ -65,6 +65,165 @@ static void default_agent_exited(const char *name, void *data)
default_agent = NULL;
}
+static void passkey_agent_free(struct passkey_agent *agent)
+{
+ if (!agent)
+ return;
+ if (agent->name)
+ free(agent->name);
+ if (agent->path)
+ free(agent->path);
+ if (agent->addr)
+ free(agent->addr);
+ free(agent);
+}
+
+static struct passkey_agent *passkey_agent_new(const char *name,
+ const char *path, const char *addr)
+{
+ struct passkey_agent *agent;
+
+ agent = malloc(sizeof(struct passkey_agent));
+ if (!agent)
+ return NULL;
+
+ memset(agent, 0, sizeof(struct passkey_agent));
+
+ agent->name = strdup(name);
+ if (!agent->name)
+ goto mem_fail;
+
+ agent->path = strdup(path);
+ if (!agent->path)
+ goto mem_fail;
+
+ if (addr) {
+ agent->addr = strdup(addr);
+ if (!agent->addr)
+ goto mem_fail;
+ }
+
+ return agent;
+
+mem_fail:
+ passkey_agent_free(agent);
+ return NULL;
+}
+
+static int agent_cmp(const struct passkey_agent *a, const struct passkey_agent *b)
+{
+ int ret;
+
+ if (b->name) {
+ if (!a->name)
+ return -1;
+ ret = strcmp(a->name, b->name);
+ if (ret)
+ return ret;
+ }
+
+ if (b->path) {
+ if (!a->path)
+ return -1;
+ ret = strcmp(a->path, b->path);
+ if (ret)
+ return ret;
+ }
+
+ if (b->addr) {
+ if (!a->addr)
+ return -1;
+ ret = strcmp(a->addr, b->addr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static DBusHandlerResult register_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ char *path, *addr;
+ struct passkey_agent *agent, ref;
+ struct hci_dbus_data *adapter;
+ DBusMessage *reply;
+
+ if (!data) {
+ error("register_agent called without any adapter info!");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ adapter = data;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ ref.name = (char *)dbus_message_get_sender(msg);
+ ref.addr = addr;
+ ref.path = path;
+
+ if (slist_find(adapter->passkey_agents, &ref, (cmp_func_t)agent_cmp))
+ return error_passkey_agent_already_exists(conn, msg);
+
+ agent = passkey_agent_new(ref.name, path, addr);
+ if (!agent)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ passkey_agent_free(agent);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ adapter->passkey_agents = slist_append(adapter->passkey_agents, agent);
+
+ return send_reply_and_unref(conn, reply);
+}
+
+static DBusHandlerResult unregister_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ char *path, *addr;
+ struct hci_dbus_data *adapter;
+ struct slist *match;
+ struct passkey_agent ref;
+ DBusMessage *reply;
+
+ if (!data) {
+ error("uregister_agent called without any adapter info!");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ adapter = data;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ ref.name = (char *)dbus_message_get_sender(msg);
+ ref.path = path;
+ ref.addr = addr;
+
+ match = slist_find(adapter->passkey_agents, &ref, (cmp_func_t)agent_cmp);
+ if (!match)
+ return error_passkey_agent_does_not_exist(conn, msg);
+
+ adapter->passkey_agents = slist_remove(adapter->passkey_agents, match->data);
+ passkey_agent_free(match->data);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ return send_reply_and_unref(conn, reply);
+}
+
static DBusHandlerResult register_default_agent(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -79,20 +238,10 @@ static DBusHandlerResult register_default_agent(DBusConnection *conn,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- default_agent = malloc(sizeof(struct passkey_agent));
+ default_agent = passkey_agent_new(dbus_message_get_sender(msg), path, NULL);
if (!default_agent)
goto need_memory;
- memset(default_agent, 0, sizeof(struct passkey_agent));
-
- default_agent->name = strdup(dbus_message_get_sender(msg));
- if (!default_agent->name)
- goto need_memory;
-
- default_agent->path = strdup(path);
- if (!default_agent->path)
- goto need_memory;
-
reply = dbus_message_new_method_return(msg);
if (!reply)
goto need_memory;
@@ -103,18 +252,11 @@ static DBusHandlerResult register_default_agent(DBusConnection *conn,
info("Default passkey agent (%s, %s) registered",
default_agent->name, default_agent->path);
- dbus_connection_send(conn, reply, NULL);
- dbus_message_unref(reply);
-
- return DBUS_HANDLER_RESULT_HANDLED;
+ return send_reply_and_unref(conn, reply);
need_memory:
if (default_agent) {
- if (default_agent->name)
- free(default_agent->name);
- if (default_agent->path)
- free(default_agent->path);
- free(default_agent);
+ passkey_agent_free(default_agent);
default_agent = NULL;
}
@@ -151,20 +293,17 @@ static DBusHandlerResult unregister_default_agent(DBusConnection *conn,
info("Default passkey agent (%s, %s) unregistered",
default_agent->name, default_agent->path);
- free(default_agent->path);
- free(default_agent->name);
- free(default_agent);
+ passkey_agent_free(default_agent);
default_agent = NULL;
- dbus_connection_send(conn, reply, NULL);
- dbus_message_unref(reply);
-
- return DBUS_HANDLER_RESULT_HANDLED;
+ return send_reply_and_unref(conn, reply);
}
static struct service_data sec_services[] = {
{ "RegisterDefaultPasskeyAgent", register_default_agent },
{ "UnregisterDefaultPasskeyAgent", unregister_default_agent },
+ { "RegisterPasskeyAgent", register_agent },
+ { "UnregisterPasskeyAgent", unregister_agent },
{ NULL, NULL }
};
@@ -299,7 +438,31 @@ DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg,
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
-int call_default_passkey_agent(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba)
+int handle_passkey_request(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba)
{
- return call_passkey_agent(default_agent, dev, path, sba, dba);
+ struct passkey_agent *agent = default_agent;
+ struct hci_dbus_data *adapter = NULL;
+ struct slist *l;
+ char addr[18];
+ void *data;
+
+ dbus_connection_get_object_path_data(get_dbus_connection(), path, &data);
+
+ if (!data)
+ goto done;
+
+ adapter = data;
+
+ ba2str(dba, addr);
+
+ for (l = adapter->passkey_agents; l != NULL; l = l->next) {
+ struct passkey_agent *a = l->data;
+ if (!strcmp(a->addr, addr)) {
+ agent = a;
+ break;
+ }
+ }
+
+done:
+ return call_passkey_agent(agent, dev, path, sba, dba);
}
diff --git a/hcid/dbus.c b/hcid/dbus.c
index 4efc7457..9341200e 100644
--- a/hcid/dbus.c
+++ b/hcid/dbus.c
@@ -433,7 +433,7 @@ void hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci)
snprintf(path, sizeof(path), "%s/hci%d", ADAPTER_PATH, hci_devid(addr));
- call_default_passkey_agent(dev, path, sba, &ci->bdaddr);
+ handle_passkey_request(dev, path, sba, &ci->bdaddr);
}
void hcid_dbus_bonding_created_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status)
diff --git a/hcid/dbus.h b/hcid/dbus.h
index 14011fa4..beb9accc 100644
--- a/hcid/dbus.h
+++ b/hcid/dbus.h
@@ -27,6 +27,7 @@
#include <stdint.h>
#include <dbus/dbus.h>
#include <bluetooth/bluetooth.h>
+#include "list.h"
#define BASE_PATH "/org/bluez"
#define BASE_INTERFACE "org.bluez"
@@ -76,9 +77,10 @@ struct hci_dbus_data {
uint32_t timeout_hits;
timeout_handler_func_t *timeout_handler;
uint8_t mode; /* scan mode */
- uint8_t resolve_name; /* send name on discover process */
+ int resolve_name; /* send name on discover process */
struct slist *discovered_devices;
char *requestor_name; /* requestor unique name */
+ struct slist *passkey_agents;
};
struct passkey_agent {
@@ -130,7 +132,7 @@ DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg,
service_handler_func_t find_service_handler(struct service_data *services, DBusMessage *msg);
-int call_default_passkey_agent(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba);
+int handle_passkey_request(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba);
static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusMessage *reply)
{