summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2006-08-20 19:05:10 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2006-08-20 19:05:10 +0000
commitbe52c05a25c0cbadcd605b24d66d0c0b682aee18 (patch)
tree89abaf343d91156a88500480e75e9cdc3247198e
parentafa617e410dad21b496539c2c7e89124294f33ae (diff)
First round of Passkey Release method support
-rw-r--r--common/glib-ectomy.c18
-rw-r--r--common/list.c10
-rw-r--r--common/list.h2
-rw-r--r--hcid/dbus-security.c127
-rw-r--r--hcid/dbus.c12
-rw-r--r--hcid/dbus.h38
-rw-r--r--hcid/main.c4
7 files changed, 155 insertions, 56 deletions
diff --git a/common/glib-ectomy.c b/common/glib-ectomy.c
index fb737642..214ee571 100644
--- a/common/glib-ectomy.c
+++ b/common/glib-ectomy.c
@@ -161,14 +161,6 @@ guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,
func, user_data, NULL);
}
-static void timeout_free(void *data, void *user_data)
-{
- struct timeout *t = data;
-
- if (t)
- free (t);
-}
-
static GMainContext *g_main_context_default()
{
if (default_context)
@@ -342,16 +334,19 @@ void g_main_loop_run(GMainLoop *loop)
void g_main_loop_quit(GMainLoop *loop)
{
- struct watch *w;
+ struct watch *w, *next;
loop->bail = 1;
- for (w = watch_head.next; w; w = w->next) {
+ for (w = watch_head.next; w; w = next) {
+ next = w->next;
if (w->destroy)
w->destroy(w->user_data);
watch_head.next = w->next;
free(w);
}
+
+ watch_head.next = NULL;
}
void g_main_loop_unref(GMainLoop *loop)
@@ -359,9 +354,10 @@ void g_main_loop_unref(GMainLoop *loop)
if (!loop->context)
return;
- slist_foreach(loop->context->ltimeout, timeout_free, NULL);
+ slist_foreach(loop->context->ltimeout, (slist_func_t)free, NULL);
slist_free(loop->context->ltimeout);
free(loop->context);
+ loop->context = NULL;
}
guint g_timeout_add(guint interval, GSourceFunc function, gpointer data)
diff --git a/common/list.c b/common/list.c
index 31ae9d35..42d377b7 100644
--- a/common/list.c
+++ b/common/list.c
@@ -99,6 +99,16 @@ struct slist *slist_find(struct slist *list, const void *data,
return NULL;
}
+int slist_length(struct slist *list)
+{
+ int len;
+
+ for (len = 0; list != NULL; list = list->next)
+ len++;
+
+ return len;
+}
+
void slist_foreach(struct slist *list, slist_func_t func, void *user_data)
{
while (list) {
diff --git a/common/list.h b/common/list.h
index 026d470c..c43756a9 100644
--- a/common/list.h
+++ b/common/list.h
@@ -40,6 +40,8 @@ struct slist *slist_remove(struct slist *list, void *data);
struct slist *slist_find(struct slist *list, const void *data,
cmp_func_t cmp_func);
+int slist_length(struct slist *list);
+
void slist_foreach(struct slist *list, slist_func_t func, void *user_data);
void slist_free(struct slist *list);
diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c
index 1495e44a..91a03e5d 100644
--- a/hcid/dbus-security.c
+++ b/hcid/dbus-security.c
@@ -43,6 +43,8 @@
static struct passkey_agent *default_agent = NULL;
+static void release_agent(struct passkey_agent *agent);
+
static void passkey_agent_free(struct passkey_agent *agent)
{
struct slist *l;
@@ -50,13 +52,6 @@ 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);
-
for (l = agent->pending_requests; l != NULL; l = l->next) {
struct pending_agent_request *req = l->data;
@@ -66,10 +61,21 @@ static void passkey_agent_free(struct passkey_agent *agent)
free(req->path);
dbus_pending_call_cancel(req->call);
dbus_pending_call_unref(req->call);
- dbus_connection_unref(req->conn);
free(req);
}
+ if (!agent->exited)
+ release_agent(agent);
+
+ if (agent->name)
+ free(agent->name);
+ if (agent->path)
+ free(agent->path);
+ if (agent->addr)
+ free(agent->addr);
+ if (agent->conn)
+ dbus_connection_unref(agent->conn);
+
slist_free(agent->pending_requests);
free(agent);
@@ -85,12 +91,15 @@ static void default_agent_exited(const char *name, void *data)
return;
}
+ default_agent->exited = 1;
+
passkey_agent_free(default_agent);
default_agent = NULL;
}
-static struct passkey_agent *passkey_agent_new(const char *name,
- const char *path, const char *addr)
+static struct passkey_agent *passkey_agent_new(struct hci_dbus_data *pdata, DBusConnection *conn,
+ const char *name, const char *path,
+ const char *addr)
{
struct passkey_agent *agent;
@@ -100,6 +109,8 @@ static struct passkey_agent *passkey_agent_new(const char *name,
memset(agent, 0, sizeof(struct passkey_agent));
+ agent->pdata = pdata;
+
agent->name = strdup(name);
if (!agent->name)
goto mem_fail;
@@ -114,9 +125,13 @@ static struct passkey_agent *passkey_agent_new(const char *name,
goto mem_fail;
}
+ agent->conn = dbus_connection_ref(conn);
+
return agent;
mem_fail:
+ /* So passkey_agent_free doesn't try to call Relese */
+ agent->exited = 1;
passkey_agent_free(agent);
return NULL;
}
@@ -166,6 +181,8 @@ static void agent_exited(const char *name, struct hci_dbus_data *adapter)
if (strcmp(agent->name, name))
continue;
+ agent->exited = 1;
+
adapter->passkey_agents = slist_remove(adapter->passkey_agents, agent);
passkey_agent_free(agent);
}
@@ -199,12 +216,13 @@ static DBusHandlerResult register_agent(DBusConnection *conn,
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);
+ agent = passkey_agent_new(adapter, conn, ref.name, path, addr);
if (!agent)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
reply = dbus_message_new_method_return(msg);
if (!reply) {
+ agent->exited = 1;
passkey_agent_free(agent);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
@@ -252,6 +270,8 @@ static DBusHandlerResult unregister_agent(DBusConnection *conn,
agent = match->data;
+ agent->exited = 1;
+
adapter->passkey_agents = slist_remove(adapter->passkey_agents, agent);
passkey_agent_free(agent);
@@ -282,7 +302,7 @@ static DBusHandlerResult register_default_agent(DBusConnection *conn,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- default_agent = passkey_agent_new(dbus_message_get_sender(msg), path, NULL);
+ default_agent = passkey_agent_new(NULL, conn, dbus_message_get_sender(msg), path, NULL);
if (!default_agent)
goto need_memory;
@@ -354,6 +374,7 @@ static struct service_data sec_services[] = {
static void passkey_agent_reply(DBusPendingCall *call, void *user_data)
{
struct pending_agent_request *req = user_data;
+ struct passkey_agent *agent = req->agent;
pin_code_reply_cp pr;
DBusMessage *message;
DBusError err;
@@ -407,13 +428,17 @@ done:
if (message)
dbus_message_unref(message);
- req->agent->pending_requests = slist_remove(req->agent->pending_requests, req);
-
+ agent->pending_requests = slist_remove(agent->pending_requests, req);
dbus_pending_call_cancel(req->call);
dbus_pending_call_unref(req->call);
- dbus_connection_unref(req->conn);
free(req->path);
free(req);
+
+ if (agent != default_agent) {
+ agent->pdata->passkey_agents = slist_remove(agent->pdata->passkey_agents,
+ agent);
+ passkey_agent_free(agent);
+ }
}
static int call_passkey_agent(DBusConnection *conn,
@@ -451,7 +476,6 @@ static int call_passkey_agent(DBusConnection *conn,
bacpy(&req->sba, sba);
bacpy(&req->bda, dba);
req->agent = agent;
- req->conn = dbus_connection_ref(conn);
req->path = strdup(path);
if (!req->path)
goto failed;
@@ -480,7 +504,6 @@ failed:
dbus_message_unref(message);
if (req) {
- dbus_connection_unref(req->conn);
free(req->path);
free(req);
}
@@ -522,6 +545,8 @@ int handle_passkey_request(DBusConnection *conn, int dev, const char *path,
for (l = adapter->passkey_agents; l != NULL; l = l->next) {
struct passkey_agent *a = l->data;
+ if (a != default_agent && slist_length(a->pending_requests) >= 1)
+ continue;
if (!strcmp(a->addr, addr)) {
agent = a;
break;
@@ -532,12 +557,12 @@ done:
return call_passkey_agent(conn, agent, dev, path, sba, dba);
}
-static void send_cancel_request(struct passkey_agent *agent, struct pending_agent_request *req)
+static void send_cancel_request(struct pending_agent_request *req)
{
DBusMessage *message;
char address[18], *ptr = address;
- message = dbus_message_new_method_call(agent->name, agent->path,
+ message = dbus_message_new_method_call(req->agent->name, req->agent->path,
"org.bluez.PasskeyAgent", "Cancel");
if (message == NULL) {
error("Couldn't allocate D-Bus message");
@@ -553,18 +578,69 @@ static void send_cancel_request(struct passkey_agent *agent, struct pending_agen
dbus_message_set_no_reply(message, TRUE);
- send_reply_and_unref(req->conn, message);
+ send_reply_and_unref(req->agent->conn, message);
debug("PasskeyAgent.Request(%s, %s) was canceled", req->path, address);
dbus_pending_call_cancel(req->call);
dbus_pending_call_unref(req->call);
- dbus_connection_unref(req->conn);
free(req->path);
free(req);
}
-void cancel_passkey_agent_requests(struct slist *agents, const char *path, bdaddr_t *addr)
+static void release_agent(struct passkey_agent *agent)
+{
+ DBusMessage *message;
+
+ debug("Releasing agent %s, %s", agent->name, agent->path);
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.PasskeyAgent", "Cancel");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ send_reply_and_unref(agent->conn, message);
+}
+
+void release_default_agent(void)
+{
+ if (!default_agent)
+ return;
+
+ name_listener_remove(default_agent->conn, default_agent->name,
+ (name_cb_t)default_agent_exited, NULL);
+
+ passkey_agent_free(default_agent);
+ default_agent = NULL;
+}
+
+void release_passkey_agents(struct hci_dbus_data *pdata, bdaddr_t *bda)
+{
+ struct slist *l, *next;
+
+ for (l = pdata->passkey_agents; l != NULL; l = next) {
+ struct passkey_agent *agent = l->data;
+ next = l->next;
+
+ if (bda && agent->addr) {
+ bdaddr_t tmp;
+ str2ba(agent->addr, &tmp);
+ if (bacmp(&tmp, bda))
+ continue;
+ }
+
+ name_listener_remove(agent->conn, agent->name, (name_cb_t)agent_exited, pdata);
+ passkey_agent_free(agent);
+ pdata->passkey_agents = slist_remove(pdata->passkey_agents, agent);
+ }
+}
+
+void cancel_passkey_agent_requests(struct slist *agents, const char *path,
+ bdaddr_t *addr)
{
struct slist *l, *next;
@@ -573,20 +649,21 @@ void cancel_passkey_agent_requests(struct slist *agents, const char *path, bdadd
struct pending_agent_request *req = l->data;
next = l->next;
if (!strcmp(path, req->path) && (!addr || !bacmp(addr, &req->bda))) {
- send_cancel_request(default_agent, req);
+ send_cancel_request(req);
default_agent->pending_requests = slist_remove(default_agent->pending_requests,
req);
}
}
/* and then the adapter specific agents */
- for (;agents != NULL; agents = agents->next) {
+ for (; agents != NULL; agents = agents->next) {
struct passkey_agent *agent = agents->data;
+
for (l = agent->pending_requests; l != NULL; l = next) {
struct pending_agent_request *req = l->data;
next = l->next;
if (!strcmp(path, req->path) && (!addr || !bacmp(addr, &req->bda))) {
- send_cancel_request(agent, req);
+ send_cancel_request(req);
agent->pending_requests = slist_remove(agent->pending_requests, req);
}
}
diff --git a/hcid/dbus.c b/hcid/dbus.c
index ec79a932..269d255d 100644
--- a/hcid/dbus.c
+++ b/hcid/dbus.c
@@ -396,6 +396,8 @@ static int unregister_dbus_path(const char *path)
cancel_passkey_agent_requests(pdata->passkey_agents, path, NULL);
+ release_passkey_agents(pdata, NULL);
+
if (pdata->requestor_name) {
name_listener_remove(connection, pdata->requestor_name,
(name_cb_t)create_bond_req_exit, pdata);
@@ -614,7 +616,7 @@ failed:
int hcid_dbus_stop_device(uint16_t id)
{
char path[MAX_PATH_LENGTH];
- struct hci_dbus_data* pdata;
+ struct hci_dbus_data *pdata;
const char *scan_mode = MODE_OFF;
DBusMessage *message;
@@ -642,6 +644,8 @@ int hcid_dbus_stop_device(uint16_t id)
cancel_passkey_agent_requests(pdata->passkey_agents, path, NULL);
+ release_passkey_agents(pdata, NULL);
+
if (pdata->requestor_name) {
name_listener_remove(connection, pdata->requestor_name,
(name_cb_t)create_bond_req_exit, pdata);
@@ -774,6 +778,8 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u
}
}
+ release_passkey_agents(pdata, peer);
+
if (!pdata->bonding || bacmp(&pdata->bonding->bdaddr, peer))
goto failed; /* skip: no bonding req pending */
@@ -1412,6 +1418,7 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle
}
cancel_passkey_agent_requests(pdata->passkey_agents, path, &dev->bdaddr);
+ release_passkey_agents(pdata, &dev->bdaddr);
/* Sent the remote device disconnected signal */
message = dev_signal_factory(pdata->dev_id, "RemoteDeviceDisconnected",
@@ -1637,6 +1644,8 @@ void hcid_dbus_exit(void)
if (!dbus_connection_get_is_connected(connection))
return;
+ release_default_agent();
+
/* Unregister all paths in Adapter path hierarchy */
if (!dbus_connection_list_registered(connection, BASE_PATH, &children))
goto done;
@@ -1983,6 +1992,7 @@ void create_bond_req_exit(const char *name, struct hci_dbus_data *pdata)
debug("CreateConnection requestor at %s exited before bonding was completed", name);
cancel_passkey_agent_requests(pdata->passkey_agents, path, &pdata->bonding->bdaddr);
+ release_passkey_agents(pdata, &pdata->bonding->bdaddr);
if (pdata->bonding->disconnect) {
struct slist *l;
diff --git a/hcid/dbus.h b/hcid/dbus.h
index 1399bf92..4aae9164 100644
--- a/hcid/dbus.h
+++ b/hcid/dbus.h
@@ -95,23 +95,6 @@ struct active_conn_info {
uint16_t handle;
};
-struct passkey_agent {
- char *addr;
- char *name;
- char *path;
- struct slist *pending_requests;
-};
-
-struct pending_agent_request {
- struct passkey_agent *agent;
- int dev;
- bdaddr_t sba;
- bdaddr_t bda;
- char *path;
- DBusConnection *conn;
- DBusPendingCall *call;
-};
-
struct hci_dbus_data {
uint16_t dev_id;
int up;
@@ -129,6 +112,25 @@ struct hci_dbus_data {
struct slist *pending_bondings;
};
+struct passkey_agent {
+ struct hci_dbus_data *pdata;
+ DBusConnection *conn;
+ char *addr;
+ char *name;
+ char *path;
+ struct slist *pending_requests;
+ int exited;
+};
+
+struct pending_agent_request {
+ struct passkey_agent *agent;
+ int dev;
+ bdaddr_t sba;
+ bdaddr_t bda;
+ char *path;
+ DBusPendingCall *call;
+};
+
typedef int register_function_t(DBusConnection *conn, uint16_t id);
typedef int unregister_function_t(DBusConnection *conn, uint16_t id);
@@ -194,6 +196,8 @@ service_handler_func_t find_service_handler(struct service_data *services, DBusM
void create_bond_req_exit(const char *name, struct hci_dbus_data *pdata);
int handle_passkey_request(DBusConnection *conn, int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba);
+void release_default_agent(void);
+void release_passkey_agents(struct hci_dbus_data *pdata, bdaddr_t *bda);
void cancel_passkey_agent_requests(struct slist *agents, const char *path, bdaddr_t *dba);
static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusMessage *reply)
diff --git a/hcid/main.c b/hcid/main.c
index 3aea1a89..5aadca01 100644
--- a/hcid/main.c
+++ b/hcid/main.c
@@ -730,8 +730,6 @@ int main(int argc, char *argv[])
/* Start event processor */
g_main_run(event_loop);
- g_main_unref(event_loop);
-
if (sdp)
stop_sdp_server();
@@ -739,6 +737,8 @@ int main(int argc, char *argv[])
hcid_dbus_exit();
+ g_main_unref(event_loop);
+
info("Exit");
stop_logging();