diff options
| -rw-r--r-- | audio/a2dp.c | 4 | ||||
| -rw-r--r-- | audio/avdtp.c | 89 | ||||
| -rw-r--r-- | audio/manager.c | 125 | ||||
| -rw-r--r-- | audio/manager.h | 7 | ||||
| -rw-r--r-- | audio/sink.c | 4 | ||||
| -rw-r--r-- | audio/unix.c | 5 | 
6 files changed, 170 insertions, 64 deletions
| diff --git a/audio/a2dp.c b/audio/a2dp.c index 1e22e7c8..febc112c 100644 --- a/audio/a2dp.c +++ b/audio/a2dp.c @@ -607,8 +607,8 @@ int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source  	if (enable_sink) {  		source.sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, -							AVDTP_MEDIA_TYPE_AUDIO, -							&ind, &cfm); +						AVDTP_MEDIA_TYPE_AUDIO, +						&ind, &cfm);  		if (source.sep == NULL)  			return -1; diff --git a/audio/avdtp.c b/audio/avdtp.c index 57de80b9..be2709da 100644 --- a/audio/avdtp.c +++ b/audio/avdtp.c @@ -36,10 +36,13 @@  #include <glib.h>  #include <bluetooth/bluetooth.h> +#include <bluetooth/sdp.h>  #include "dbus.h"  #include "logging.h" +#include "device.h" +#include "manager.h"  #include "avdtp.h"  #include <bluetooth/l2cap.h> @@ -274,6 +277,8 @@ struct avdtp {  	struct pending_req *req;  	guint dc_timer; + +	DBusPendingCall *pending_auth;  };  struct avdtp_error { @@ -1363,7 +1368,15 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,  	return TRUE;  failed: +	if (session->pending_auth) { +		manager_cancel_authorize(&session->dst, ADVANCED_AUDIO_UUID, +						session->pending_auth); +		dbus_pending_call_unref(session->pending_auth); +		session->pending_auth = NULL; +	} +  	connection_lost(session, -EIO); +  	return FALSE;  } @@ -2041,8 +2054,12 @@ static struct avdtp *avdtp_get_internal(bdaddr_t *src, bdaddr_t *dst)  	assert(dst != NULL);  	session = find_session(src, dst); -	if (session) -		return session; +	if (session) { +		if (session->pending_auth) +			return NULL; +		else +			return session; +	}  	session = g_new0(struct avdtp, 1); @@ -2063,6 +2080,9 @@ struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst)  	session = avdtp_get_internal(src, dst); +	if (!session) +		return NULL; +  	return avdtp_ref(session);  } @@ -2463,6 +2483,51 @@ int avdtp_unregister_sep(struct avdtp_local_sep *sep)  	return 0;  } +static void auth_cb(DBusPendingCall *call, void *data) +{ +	GIOChannel *io; +	struct avdtp *session = data; +	DBusMessage *reply = dbus_pending_call_steal_reply(call); +	DBusError err; + +	dbus_pending_call_unref(session->pending_auth); +	session->pending_auth = NULL; + +	dbus_error_init(&err); +	if (dbus_set_error_from_message(&err, reply)) { +		error("Access denied: %s", err.message); + +		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { +			debug("Canceling authorization request"); +			manager_cancel_authorize(&session->dst, +							ADVANCED_AUDIO_UUID, +							NULL); +		} + +		dbus_error_free(&err); + +		connection_lost(session, -EACCES); + +		dbus_message_unref(reply); + +		return; +	} + +	session->buf = g_malloc0(session->mtu); + +	set_disconnect_timer(session); + +	session->state = AVDTP_SESSION_STATE_CONNECTED; + +	g_source_remove(session->io); + +	io = g_io_channel_unix_new(session->sock); +	session->io = g_io_add_watch(io, +				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, +				(GIOFunc) session_cb, session); +	g_io_channel_unref(io); +} +  static gboolean avdtp_server_cb(GIOChannel *chan, GIOCondition cond, void *data)  {  	int srv_sk, cli_sk; @@ -2471,7 +2536,7 @@ static gboolean avdtp_server_cb(GIOChannel *chan, GIOCondition cond, void *data)  	struct l2cap_options l2o;  	bdaddr_t src, dst;  	struct avdtp *session; -	GIOChannel *cli_io; +	GIOChannel *io;  	char address[18];  	if (cond & G_IO_NVAL) @@ -2529,19 +2594,19 @@ static gboolean avdtp_server_cb(GIOChannel *chan, GIOCondition cond, void *data)  		return TRUE;  	} -	if (session->ref == 1) -		set_disconnect_timer(session); +	if (!manager_authorize(&dst, ADVANCED_AUDIO_UUID, auth_cb, session, +				&session->pending_auth)) { +		close(cli_sk); +		return TRUE; +	}  	session->mtu = l2o.imtu; -	session->buf = g_malloc0(session->mtu);  	session->sock = cli_sk; -	session->state = AVDTP_SESSION_STATE_CONNECTED; -	cli_io = g_io_channel_unix_new(session->sock); -	session->io = g_io_add_watch(cli_io, -				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, -				(GIOFunc) session_cb, session); -	g_io_channel_unref(cli_io); +	io = g_io_channel_unix_new(session->sock); +	session->io = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL, +					(GIOFunc) session_cb, session); +	g_io_channel_unref(io);  	return TRUE;  } diff --git a/audio/manager.c b/audio/manager.c index 6eebce94..4d8d424d 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -1383,10 +1383,11 @@ int remove_service_record(DBusConnection *conn, uint32_t rec_id)  	return 0;  } -static void send_cancel_auth(struct device *device) +static void auth_cb(DBusPendingCall *call, void *data)  { -	DBusMessage *cancel; -	char addr[18], *address = addr; +	struct device *device = data; +	DBusMessage *reply = dbus_pending_call_steal_reply(call); +	DBusError err;  	const char *uuid;  	if (headset_get_type(device) == SVC_HEADSET) @@ -1394,35 +1395,12 @@ static void send_cancel_auth(struct device *device)  	else  		uuid = HFP_AG_UUID; -	cancel = dbus_message_new_method_call("org.bluez", "/org/bluez", -						"org.bluez.Database", -						"CancelAuthorizationRequest"); -	if (!cancel) { -		error("Unable to allocate new method call"); -		return; -	} - -	ba2str(&device->dst, addr); - -	dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address, -						DBUS_TYPE_STRING, &uuid, -							DBUS_TYPE_INVALID); - -	send_message_and_unref(connection, cancel); -} - -static void auth_cb(DBusPendingCall *call, void *data) -{ -	struct device *device = data; -	DBusMessage *reply = dbus_pending_call_steal_reply(call); -	DBusError err; -  	dbus_error_init(&err);  	if (dbus_set_error_from_message(&err, reply)) {  		error("Access denied: %s", err.message);  		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {  			debug("Canceling authorization request"); -			send_cancel_auth(device); +			manager_cancel_authorize(&device->dst, uuid, NULL);  		}  		dbus_error_free(&err); @@ -1446,11 +1424,8 @@ static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data)  	int srv_sk, cli_sk;  	struct sockaddr_rc addr;  	socklen_t size; -	char hs_address[18], *address = hs_address;  	const char *uuid;  	struct device *device; -	DBusMessage *auth; -	DBusPendingCall *pending;  	headset_type_t type;  	if (cond & G_IO_NVAL) @@ -1500,28 +1475,9 @@ static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data)  	headset_set_type(device, type); -	auth = dbus_message_new_method_call("org.bluez", "/org/bluez", -						"org.bluez.Database", -						"RequestAuthorization"); -	if (!auth) { -		error("Unable to allocate RequestAuthorization method call"); +	if (!manager_authorize(&device->dst, uuid, auth_cb, device, NULL))  		goto failed; -	} -	ba2str(&device->dst, hs_address); - -	dbus_message_append_args(auth, DBUS_TYPE_STRING, &address, -						DBUS_TYPE_STRING, &uuid, -							DBUS_TYPE_INVALID); - -	if (!dbus_connection_send_with_reply(connection, auth, &pending, -1)) { -		error("Sending of authorization request failed"); -		goto failed; -	} - -	dbus_pending_call_set_notify(pending, auth_cb, device, NULL); -	dbus_pending_call_unref(pending); -	dbus_message_unref(auth);  	headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);  	return TRUE; @@ -1734,3 +1690,72 @@ struct device *manager_get_connected_device(void)  	return NULL;  } + +void manager_cancel_authorize(bdaddr_t *dba, const char *uuid, +				DBusPendingCall *pending) +{ +	DBusMessage *cancel; +	char addr[18], *address = addr; + +	if (pending) +		dbus_pending_call_cancel(pending); + +	cancel = dbus_message_new_method_call("org.bluez", "/org/bluez", +						"org.bluez.Database", +						"CancelAuthorizationRequest"); +	if (!cancel) { +		error("Unable to allocate new method call"); +		return; +	} + +	ba2str(dba, addr); + +	dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address, +					DBUS_TYPE_STRING, &uuid, +					DBUS_TYPE_INVALID); + +	send_message_and_unref(connection, cancel); +} + +gboolean manager_authorize(bdaddr_t *dba, const char *uuid, +				DBusPendingCallNotifyFunction cb, +				void *user_data, +				DBusPendingCall **pending) +{ +	DBusMessage *auth; +	char address[18], *addr_ptr = address; +	DBusPendingCall *p; + +	ba2str(dba, address); + +	debug("Requesting authorization for device %s, UUID %s", +			address, uuid); + +	auth = dbus_message_new_method_call("org.bluez", "/org/bluez", +						"org.bluez.Database", +						"RequestAuthorization"); +	if (!auth) { +		error("Unable to allocate RequestAuthorization method call"); +		return FALSE; +	} + +	dbus_message_append_args(auth, DBUS_TYPE_STRING, &addr_ptr, +					DBUS_TYPE_STRING, &uuid, +					DBUS_TYPE_INVALID); + +	if (!dbus_connection_send_with_reply(connection, auth, &p, -1)) { +		error("Sending of authorization request failed"); +		dbus_message_unref(auth); +		return FALSE; +	} + +	dbus_pending_call_set_notify(p, cb, user_data, NULL); +	if (pending) +		*pending = p; +	else +		dbus_pending_call_unref(p); + +	dbus_message_unref(auth); + +	return TRUE; +} diff --git a/audio/manager.h b/audio/manager.h index a18cf4fd..65992040 100644 --- a/audio/manager.h +++ b/audio/manager.h @@ -47,3 +47,10 @@ struct device *manager_device_connected(bdaddr_t *bda, const char *uuid);  struct device *manager_default_device();  struct device *manager_get_connected_device(void); + +gboolean manager_authorize(bdaddr_t *dba, const char *uuid, +				DBusPendingCallNotifyFunction cb, +				void *user_data, +				DBusPendingCall **pending); +void manager_cancel_authorize(bdaddr_t *dba, const char *uuid, +				DBusPendingCall *pending); diff --git a/audio/sink.c b/audio/sink.c index ab9f401b..c09c019f 100644 --- a/audio/sink.c +++ b/audio/sink.c @@ -160,6 +160,10 @@ static DBusHandlerResult sink_connect(DBusConnection *conn,  	if (!sink->session)  		sink->session = avdtp_get(&dev->src, &dev->dst); +	if (!sink->session) +		return err_connect_failed(conn, msg, +						"Unable to get a session"); +  	if (sink->connect || sink->disconnect)  		return err_connect_failed(conn, msg, "Connect in progress"); diff --git a/audio/unix.c b/audio/unix.c index 19a140c0..3488fd5f 100644 --- a/audio/unix.c +++ b/audio/unix.c @@ -317,6 +317,11 @@ proceed:  		if (!a2dp->session)  			a2dp->session = avdtp_get(&dev->src, &dev->dst); +		if (!a2dp->session) { +			error("Unable to get a session"); +			goto failed; +		}	 +  		id = a2dp_source_request_stream(a2dp->session, dev,  						TRUE, a2dp_setup_complete,  						client); | 
