diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2006-10-03 19:19:58 +0000 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@nokia.com> | 2006-10-03 19:19:58 +0000 | 
| commit | 6af2f85288b058b3a575622b01af6869100a7398 (patch) | |
| tree | e50eed9b3937603279904b5c982ddb024d67c04e | |
| parent | 7880ff6d0f3b877d16f5d1119120ee73344dd402 (diff) | |
More AuditRemoteDevice implementation
| -rw-r--r-- | hcid/dbus-adapter.c | 90 | ||||
| -rw-r--r-- | hcid/dbus-common.c | 95 | ||||
| -rw-r--r-- | hcid/dbus-error.c | 8 | ||||
| -rw-r--r-- | hcid/dbus-test.c | 204 | ||||
| -rw-r--r-- | hcid/dbus.h | 5 | 
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); | 
