diff options
Diffstat (limited to 'hcid')
| -rw-r--r-- | hcid/dbus-adapter.c | 92 | ||||
| -rw-r--r-- | hcid/dbus-adapter.h | 12 | ||||
| -rw-r--r-- | hcid/dbus-api.txt | 19 | ||||
| -rw-r--r-- | hcid/dbus-error.c | 5 | ||||
| -rw-r--r-- | hcid/dbus-error.h | 1 | ||||
| -rw-r--r-- | hcid/dbus-hci.c | 22 | 
6 files changed, 128 insertions, 23 deletions
| diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index a36ab4fa..a4ca8712 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -1680,18 +1680,61 @@ static DBusHandlerResult adapter_last_used(DBusConnection *conn,  	return send_message_and_unref(conn, reply);  } -static DBusHandlerResult adapter_dc_remote_device(DBusConnection *conn, -						DBusMessage *msg, void *data) + +gboolean dc_pending_timeout_handler(void *data)  { +	int dd; +	struct adapter *adapter = data; +	struct pending_dc_info *pending_dc = adapter->pending_dc;  	DBusMessage *reply; +	dd = hci_open_dev(adapter->dev_id); + +	if (dd < 0) { + 		error_no_such_adapter(pending_dc->conn, +				      pending_dc->msg); +		dc_pending_timeout_cleanup(adapter); +		return FALSE; +	} + +	/* Send the HCI disconnect command */ +	if (hci_disconnect(dd, pending_dc->conn_handle, +				HCI_OE_USER_ENDED_CONNECTION, +			   	500) < 0) { +		int err = errno; +		error("Disconnect failed"); +		error_failed(pending_dc->conn, pending_dc->msg, err); +	} else { +		reply = dbus_message_new_method_return(pending_dc->msg); +		if (!reply) +			error("Failed to allocate disconnect reply"); +		else +			send_message_and_unref(pending_dc->conn, reply); +	} + +	hci_close_dev(dd); +	dc_pending_timeout_cleanup(adapter); + +	return FALSE; +} + +void dc_pending_timeout_cleanup(struct adapter *adapter) +{ +	dbus_connection_unref(adapter->pending_dc->conn); +	dbus_message_unref(adapter->pending_dc->msg); +	free(adapter->pending_dc); +	adapter->pending_dc = NULL; +} + +static DBusHandlerResult adapter_dc_remote_device(DBusConnection *conn, +						DBusMessage *msg, void *data) +{  	struct adapter *adapter = data;  	struct slist *l = adapter->active_conn;  	const char *peer_addr;  	bdaddr_t peer_bdaddr; -	int dd; -	struct active_conn_info *dev; +	DBusMessage *signal;  	if (!adapter->up)  		return error_not_ready(conn, msg); @@ -1710,29 +1753,38 @@ static DBusHandlerResult adapter_dc_remote_device(DBusConnection *conn,  	if (!l)  		return error_not_connected(conn, msg); -	dev = l->data; +	if(adapter->pending_dc) +		return error_disconnect_in_progress(conn, msg); -	dd = hci_open_dev(adapter->dev_id); -	if (dd < 0) -		return error_no_such_adapter(conn, msg); +	adapter->pending_dc = malloc(sizeof(*adapter->pending_dc)); +	if(!adapter->pending_dc) +		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	/* Send the HCI disconnect command */ -	if (hci_disconnect(dd, dev->handle, HCI_OE_USER_ENDED_CONNECTION, -				500) < 0) { -		int err = errno; -		error("Disconnect failed"); -		hci_close_dev(dd); -		return error_failed(conn, msg, err); +	/* Start waiting... */ +	adapter->pending_dc->timeout_id = +		g_timeout_add(DC_PENDING_TIMEOUT, +			      dc_pending_timeout_handler, +			      adapter); + +	if(!adapter->pending_dc->timeout_id) { +		free(adapter->pending_dc); +		adapter->pending_dc = NULL; +		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	} -	hci_close_dev(dd); +	adapter->pending_dc->conn = dbus_connection_ref(conn); +	adapter->pending_dc->msg = dbus_message_ref(msg); +	adapter->pending_dc->conn_handle = +		((struct active_conn_info *) l->data)->handle; -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return DBUS_HANDLER_RESULT_NEED_MEMORY; +	/* ...and send a signal */ +	signal = dev_signal_factory(adapter->dev_id, "RemoteDeviceDisconnectRequested", +						DBUS_TYPE_STRING, &peer_addr, +						DBUS_TYPE_INVALID); +	send_message_and_unref(conn, signal); -	return send_message_and_unref(conn, reply); +	return DBUS_HANDLER_RESULT_HANDLED;  }  static void reply_authentication_failure(struct bonding_request_info *bonding) diff --git a/hcid/dbus-adapter.h b/hcid/dbus-adapter.h index 3c21c179..288cc338 100644 --- a/hcid/dbus-adapter.h +++ b/hcid/dbus-adapter.h @@ -34,6 +34,8 @@  #define BONDING_TIMEOUT         45000 /* 45 sec */ +#define DC_PENDING_TIMEOUT      2000  /* 2 secs */ +  /* Discover types */  #define DISCOVER_TYPE_NONE	0x00  #define STD_INQUIRY		0x01 @@ -77,6 +79,13 @@ struct active_conn_info {  	uint16_t handle;  }; +struct pending_dc_info { +	DBusConnection *conn; +	DBusMessage *msg; +	uint16_t conn_handle; +	guint timeout_id; +}; +  struct adapter {  	uint16_t dev_id;  	int up; @@ -100,6 +109,7 @@ struct adapter {  	struct slist *active_conn;  	struct bonding_request_info *bonding;  	struct slist *pin_reqs; +	struct pending_dc_info *pending_dc;  };  DBusHandlerResult handle_adapter_method(DBusConnection *conn, DBusMessage *msg, void *data); @@ -112,4 +122,6 @@ struct slist *service_classes_str(uint32_t class);  int pending_remote_name_cancel(struct adapter *adapter); +void dc_pending_timeout_cleanup(struct adapter *adapter); +  #endif /* __ADAPTER_H */ diff --git a/hcid/dbus-api.txt b/hcid/dbus-api.txt index aa3a34fc..437f2baa 100644 --- a/hcid/dbus-api.txt +++ b/hcid/dbus-api.txt @@ -679,15 +679,22 @@ Methods		string GetAddress()  		void DisconnectRemoteDevice(string address)  			This method disconnects a specific remote device by -			terminating the low-level ACL connection. The use -			of this method should be restricted to administrator -			use only. +			terminating the low-level ACL connection. The use of +			this method should be restricted to administrator +			use. + +			A RemoteDeviceDisconnectRequested signal will be +			sent and the actual disconnection will only happen 2 +			seconds later.  This enables upper-level applications +			to terminate their connections gracefully before the +			ACL connection is terminated.  			Possible errors: org.bluez.Error.NotReady  					 org.bluez.Error.Failed  					 org.bluez.Error.NoSuchAdapter  					 org.bluez.Error.InvalidArguments  			                 org.bluez.Error.NotConnected +			                 org.bluez.Error.InProgress  		void CreateBonding(string address) @@ -1001,6 +1008,12 @@ Signals		void ModeChanged(string mode)  			This signal will be send if a low level connection  			between two devices has been created. +		void RemoteDeviceDisconnectRequested(string address) + +			This signal will be sent when a low level +			disconnection to a remote device has been requested. +			The actual disconnection will happen 2 seconds later. +  		void RemoteDeviceDisconnected(string address)  			This signal will be send if a low level connection diff --git a/hcid/dbus-error.c b/hcid/dbus-error.c index 8a87cff5..83b72ad7 100644 --- a/hcid/dbus-error.c +++ b/hcid/dbus-error.c @@ -278,6 +278,11 @@ DBusHandlerResult error_trusted_device_does_not_exists(DBusConnection *conn, DBu  	return error_does_not_exist(conn, msg, "Trusted device does not exist");  } +DBusHandlerResult error_disconnect_in_progress(DBusConnection *conn, DBusMessage *msg) +{ +	return error_in_progress(conn, msg, "Disconnection in progress"); +} +  static const char *strsdperror(int err)  { diff --git a/hcid/dbus-error.h b/hcid/dbus-error.h index c88ce815..801c122d 100644 --- a/hcid/dbus-error.h +++ b/hcid/dbus-error.h @@ -65,5 +65,6 @@ DBusHandlerResult error_sdp_failed(DBusConnection *conn, DBusMessage *msg, int e  DBusHandlerResult error_audit_already_exists(DBusConnection *conn, DBusMessage *msg);  DBusHandlerResult error_trusted_device_already_exists(DBusConnection *conn, DBusMessage *msg);  DBusHandlerResult error_trusted_device_does_not_exists(DBusConnection *conn, DBusMessage *msg); +DBusHandlerResult error_disconnect_in_progress(DBusConnection *conn, DBusMessage *msg);  #endif /* __BLUEZ_DBUS_ERROR_H */ diff --git a/hcid/dbus-hci.c b/hcid/dbus-hci.c index 51f3ca65..8fd443b6 100644 --- a/hcid/dbus-hci.c +++ b/hcid/dbus-hci.c @@ -473,6 +473,14 @@ int unregister_adapter_path(const char *path)  		adapter->active_conn = NULL;  	} +	/* Check if there is a pending RemoteDeviceDisconnect request */ +	if (adapter->pending_dc) { + 		error_no_such_adapter(adapter->pending_dc->conn, +				      adapter->pending_dc->msg); +		g_timeout_remove(adapter->pending_dc->timeout_id); +		dc_pending_timeout_cleanup(adapter); +	} +  	free (adapter);  unreg: @@ -1742,6 +1750,20 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status,  		adapter->bonding = NULL;  	} +	/* Check if there is a pending RemoteDeviceDisconnect request */ +	if (adapter->pending_dc) { +		DBusMessage *reply; + +		reply = dbus_message_new_method_return(adapter->pending_dc->msg); +		if (!reply) +			error("Failed to allocate disconnect reply"); +		else +			send_message_and_unref(adapter->pending_dc->conn, reply); + +		g_timeout_remove(adapter->pending_dc->timeout_id); +		dc_pending_timeout_cleanup(adapter); +	} +  	/* Send the remote device disconnected signal */  	message = dev_signal_factory(adapter->dev_id,  					"RemoteDeviceDisconnected", | 
