diff options
| -rw-r--r-- | hcid/agent.c | 159 | ||||
| -rw-r--r-- | hcid/agent.h | 10 | ||||
| -rw-r--r-- | hcid/dbus-hci.c | 126 | ||||
| -rw-r--r-- | hcid/dbus-hci.h | 2 | ||||
| -rw-r--r-- | hcid/security.c | 12 | 
5 files changed, 307 insertions, 2 deletions
diff --git a/hcid/agent.c b/hcid/agent.c index 5706ea94..c8236892 100644 --- a/hcid/agent.c +++ b/hcid/agent.c @@ -56,6 +56,7 @@  typedef enum {  	AGENT_REQUEST_PASSKEY, +	AGENT_REQUEST_CONFIRMATION,  	AGENT_REQUEST_PINCODE,  	AGENT_REQUEST_AUTHORIZE,  	AGENT_REQUEST_CONFIRM_MODE @@ -518,6 +519,164 @@ failed:  	return -1;  } +static DBusPendingCall *passkey_request_new(struct agent *agent, +						const char *device_path) +{ +	DBusMessage *message; +	DBusPendingCall *call; + +	message = dbus_message_new_method_call(agent->name, agent->path, +					"org.bluez.Agent", "RequestPasskey"); +	if (message == NULL) { +		error("Couldn't allocate D-Bus message"); +		return NULL; +	} + +	dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device_path, +					DBUS_TYPE_INVALID); + +	if (dbus_connection_send_with_reply(connection, message, +					&call, REQUEST_TIMEOUT) == FALSE) { +		error("D-Bus send failed"); +		dbus_message_unref(message); +		return NULL; +	} + +	dbus_message_unref(message); +	return call; +} + +static void passkey_reply(DBusPendingCall *call, void *user_data) +{ +	struct agent_request *req = user_data; +	struct agent *agent = req->agent; +	agent_passkey_cb cb = req->cb; +	DBusMessage *message; +	DBusError err; +	uint32_t passkey; + +	/* steal_reply will always return non-NULL since the callback +	 * is only called after a reply has been received */ +	message = dbus_pending_call_steal_reply(call); + +	dbus_error_init(&err); +	if (dbus_set_error_from_message(&err, message)) { +		error("Agent replied with an error: %s, %s", +				err.name, err.message); +		cb(agent, &err, 0, req->user_data); +		dbus_error_free(&err); +		goto done; +	} + +	dbus_error_init(&err); +	if (!dbus_message_get_args(message, &err, +				DBUS_TYPE_UINT32, &passkey, +				DBUS_TYPE_INVALID)) { +		error("Wrong passkey reply signature: %s", err.message); +		cb(agent, &err, 0, req->user_data); +		dbus_error_free(&err); +		goto done; +	} + +	cb(agent, NULL, passkey, req->user_data); + +done: +	if (message) +		dbus_message_unref(message); + +	dbus_pending_call_cancel(req->call); +	agent_request_free(req); +} + +int agent_request_passkey(struct agent *agent, struct device *device, +				agent_passkey_cb cb, void *user_data) +{ +	struct agent_request *req; + +	if (agent->request) +		return -EBUSY; + +	debug("Calling Agent.RequestPasskey: name=%s, path=%s", +			agent->name, agent->path); + +	req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb, user_data); + +	req->call = passkey_request_new(agent, device->path); +	if (!req->call) +		goto failed; + +	dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL); + +	agent->request = req; + +	return 0; + +failed: +	agent_request_free(req); +	return -1; +} + +static DBusPendingCall *confirmation_request_new(struct agent *agent, +						const char *device_path, +						uint32_t passkey) +{ +	DBusMessage *message; +	DBusPendingCall *call; + +	message = dbus_message_new_method_call(agent->name, agent->path, +				"org.bluez.Agent", "RequestConfirmation"); +	if (message == NULL) { +		error("Couldn't allocate D-Bus message"); +		return NULL; +	} + +	dbus_message_append_args(message, +				DBUS_TYPE_OBJECT_PATH, &device_path, +				DBUS_TYPE_UINT32, &passkey, +				DBUS_TYPE_INVALID); + +	if (dbus_connection_send_with_reply(connection, message, +					&call, REQUEST_TIMEOUT) == FALSE) { +		error("D-Bus send failed"); +		dbus_message_unref(message); +		return NULL; +	} + +	dbus_message_unref(message); + +	return call; +} + +int agent_request_confirmation(struct agent *agent, struct device *device, +				uint32_t passkey, agent_cb cb, +				void *user_data) +{ +	struct agent_request *req; + +	if (agent->request) +		return -EBUSY; + +	debug("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u", +			agent->name, agent->path, passkey); + +	req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb, +				user_data); + +	req->call = confirmation_request_new(agent, device->path, passkey); +	if (!req->call) +		goto failed; + +	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); + +	agent->request = req; + +	return 0; + +failed: +	agent_request_free(req); +	return -1; +} +  uint8_t agent_get_io_capability(struct agent *agent)  {  	return agent->capability; diff --git a/hcid/agent.h b/hcid/agent.h index 2bfe003e..552c91f2 100644 --- a/hcid/agent.h +++ b/hcid/agent.h @@ -30,6 +30,9 @@ typedef void (*agent_cb) (struct agent *agent, DBusError *err,  typedef void (*agent_pincode_cb) (struct agent *agent, DBusError *err,  					const char *pincode, void *user_data); +typedef void (*agent_passkey_cb) (struct agent *agent, DBusError *err, +					uint32_t passkey, void *user_data); +  typedef void (*agent_remove_cb) (struct agent *agent, void *user_data);  struct agent *agent_create(struct adapter *adapter, const char *name, @@ -47,6 +50,13 @@ int agent_request_pincode(struct agent *agent, struct device *device,  int agent_confirm_mode_change(struct agent *agent, const char *new_mode,  				agent_cb cb, void *user_data); +int agent_request_passkey(struct agent *agent, struct device *device, +				agent_passkey_cb cb, void *user_data); + +int agent_request_confirmation(struct agent *agent, struct device *device, +				uint32_t passkey, agent_cb cb, +				void *user_data); +  int agent_cancel(struct agent *agent);  uint8_t agent_get_io_capability(struct agent *agent); diff --git a/hcid/dbus-hci.c b/hcid/dbus-hci.c index 14261bfe..4822de9a 100644 --- a/hcid/dbus-hci.c +++ b/hcid/dbus-hci.c @@ -1032,6 +1032,132 @@ old_fallback:  						&ci->bdaddr);  } +static void confirm_cb(struct agent *agent, DBusError *err, void *user_data) +{ +	struct device *device = user_data; +	struct adapter *adapter = device->adapter; +	user_confirm_reply_cp cp; +	int dd; + +	dd = hci_open_dev(adapter->dev_id); +	if (dd < 0) { +		error("Unable to open hci%d", adapter->dev_id); +		return; +	} + +	memset(&cp, 0, sizeof(cp)); +	str2ba(device->address, &cp.bdaddr); + +	if (err) +		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, +				USER_CONFIRM_REPLY_CP_SIZE, &cp); +	else +		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY, +				USER_CONFIRM_REPLY_CP_SIZE, &cp); + +	hci_close_dev(dd); +} + +static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey, +			void *user_data) +{ +	struct device *device = user_data; +	struct adapter *adapter = device->adapter; +	user_passkey_reply_cp cp; +	bdaddr_t dba; +	int dd; + +	dd = hci_open_dev(adapter->dev_id); +	if (dd < 0) { +		error("Unable to open hci%d", adapter->dev_id); +		return; +	} + +	str2ba(device->address, &dba); + +	memset(&cp, 0, sizeof(cp)); +	bacpy(&cp.bdaddr, &dba); +	cp.passkey = passkey; + +	if (err) +		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, +				6, &dba); +	else +		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_REPLY, +				USER_PASSKEY_REPLY_CP_SIZE, &cp); + +	hci_close_dev(dd); +} + +int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey) +{ +	struct adapter *adapter; +	struct device *device; +	struct agent *agent; +	char addr[18]; + +	adapter = find_adapter(sba); +	if (!adapter) { +		error("No matching adapter found"); +		return -1; +	} + +	ba2str(dba, addr); + +	device = adapter_get_device(connection, adapter, addr); +	if (device && device->agent) +		agent = device->agent; +	else +		agent = adapter->agent; + +	if (!agent) { +		error("No agent available for user confirm request"); +		return -1; +	} + +	if (agent_request_confirmation(agent, device, passkey, +					confirm_cb, device) < 0) { +		error("Requesting passkey failed"); +		return -1; +	} + +	return 0; +} + +int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba) +{ +	struct adapter *adapter; +	struct device *device; +	struct agent *agent; +	char addr[18]; + +	adapter = find_adapter(sba); +	if (!adapter) { +		error("No matching adapter found"); +		return -1; +	} + +	ba2str(dba, addr); + +	device = adapter_get_device(connection, adapter, addr); +	if (device && device->agent) +		agent = device->agent; +	else +		agent = adapter->agent; + +	if (!agent) { +		error("No agent available for user confirm request"); +		return -1; +	} + +	if (agent_request_passkey(agent, device, passkey_cb, device) < 0) { +		error("Requesting passkey failed"); +		return -1; +	} + +	return 0; +} +  int hcid_dbus_confirm_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci, char *pin)  {  	struct adapter *adapter; diff --git a/hcid/dbus-hci.h b/hcid/dbus-hci.h index 671c5f1a..167780b4 100644 --- a/hcid/dbus-hci.h +++ b/hcid/dbus-hci.h @@ -49,6 +49,8 @@ void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local);  void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr);  int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote, uint8_t *cap,  				uint8_t *auth); +int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey); +int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba);  int unregister_adapter_path(const char *path); diff --git a/hcid/security.c b/hcid/security.c index 6f8151f8..0df255ab 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -360,12 +360,20 @@ static void return_link_keys(int dev, bdaddr_t *sba, void *ptr)  static void user_confirm_request(int dev, bdaddr_t *sba, void *ptr)  { -	hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, 6, ptr); +	evt_user_confirm_request *req = ptr; + +	if (hcid_dbus_user_confirm(sba, &req->bdaddr, req->passkey) < 0) +		hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, +				6, ptr);  }  static void user_passkey_request(int dev, bdaddr_t *sba, void *ptr)  { -	hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, 6, ptr); +	evt_user_passkey_request *req = ptr; + +	if (hcid_dbus_user_passkey(sba, &req->bdaddr) < 0) +		hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, +				6, ptr);  }  static void remote_oob_data_request(int dev, bdaddr_t *sba, void *ptr)  | 
