diff options
| -rw-r--r-- | hcid/dbus-adapter.c | 23 | ||||
| -rw-r--r-- | hcid/dbus.c | 201 | ||||
| -rw-r--r-- | hcid/dbus.h | 8 | ||||
| -rw-r--r-- | hcid/hcid.h | 2 | ||||
| -rw-r--r-- | hcid/security.c | 8 | 
5 files changed, 203 insertions, 39 deletions
| diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index 36c47e0b..551586ed 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -1081,7 +1081,7 @@ static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBu  		return error_bonding_in_progress(conn, msg);  	ecode = get_device_address(dbus_data->dev_id, local_addr, sizeof(local_addr)); -	if (ecode < 0) /* FIXME: remove the peer bdaddr from the list */ +	if (ecode < 0)  		return error_failed(conn, msg, -ecode);  	/* check if a link key already exists */ @@ -1105,10 +1105,6 @@ static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBu  	if (dd < 0)  		return error_no_such_adapter(conn, msg); -	/* check if there is an active connection */ -	//dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &peer_bdaddr); -	handle = find_connection_handle(dd, &peer_bdaddr); -  	memset(&rq, 0, sizeof(rq));  	memset(&rp, 0, sizeof(rp)); @@ -1117,6 +1113,9 @@ static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBu  	rq.rparam = &rp;  	rq.rlen = EVT_CMD_STATUS_SIZE; +	/* check if there is an active connection */ +	handle = find_connection_handle(dd, &peer_bdaddr); +  	if (handle < 0 ) {  		create_conn_cp cp; @@ -1125,14 +1124,14 @@ static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBu  		bonding_state = CONNECTING;  		bacpy(&cp.bdaddr, &peer_bdaddr); -		cp.pkt_type = htobs(HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5); +		cp.pkt_type       = htobs(HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5);  		cp.pscan_rep_mode = 0x02; -		cp.clock_offset = htobs(0x0000); -		cp.role_switch = 0x01; +		cp.clock_offset	  = htobs(0x0000); +		cp.role_switch    = 0x01; -		rq.ocf = OCF_CREATE_CONN; +		rq.ocf    = OCF_CREATE_CONN;  		rq.cparam = &cp; -		rq.clen = CREATE_CONN_CP_SIZE; +		rq.clen   = CREATE_CONN_CP_SIZE;  	} else {  		/* connection found */  		auth_requested_cp cp; @@ -1526,7 +1525,7 @@ static DBusHandlerResult handle_dev_cancel_discovery_req(DBusConnection *conn, D  		break;  	} -	slist_foreach(dbus_data->discovered_devices, discovered_device_free, NULL); +	slist_foreach(dbus_data->discovered_devices, discovered_device_info_free, NULL);  	slist_free(dbus_data->discovered_devices);  	dbus_data->discovered_devices = NULL; @@ -1591,7 +1590,7 @@ static struct service_data dev_services[] = {  	{ "GetEncryptionKeySize",			handle_dev_get_encryption_key_size_req,	},  	{ "DiscoverDevices",				handle_dev_discover_devices_req,	}, -	{ "DiscoverDevicesWithoutNameResolving",	handle_dev_discover_devices_req	}, +	{ "DiscoverDevicesWithoutNameResolving",	handle_dev_discover_devices_req		},  	{ "CancelDiscovery",				handle_dev_cancel_discovery_req,	},  	{ NULL, NULL } diff --git a/hcid/dbus.c b/hcid/dbus.c index ac00e8d1..02d7f739 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -98,7 +98,7 @@ static const char *phone_minor_cls[] = {  }; -void discovered_device_free(void *data, void *user_data) +void discovered_device_info_free(void *data, void *user_data)  {  	struct discovered_dev_info *dev = data; @@ -108,6 +108,27 @@ void discovered_device_free(void *data, void *user_data)  	}  } +static void bonding_request_info_free(void *data, void *user_data) +{ +	struct bonding_request_info *dev = data; + +	if (dev) { +		free(dev->bdaddr); +		dbus_message_unref(dev->msg); +		free(dev); +	} +} + +static void active_conn_info_free(void *data, void *user_data) +{ +	struct active_conn_info *dev = data; + +	if (dev) { +		free(dev->bdaddr); +		free(dev); +	} +} +  int bonding_requests_find(const void *data, const void *user_data)  {  	const struct bonding_request_info *dev = data; @@ -187,6 +208,52 @@ static int remote_name_remove(struct slist **list, bdaddr_t *bdaddr)  	return ret_val;  } +static int active_conn_find_by_handle(const void *data, const void *user_data) +{ +	const struct active_conn_info *dev = data; +	const uint16_t *handle = user_data; + +	if (dev->handle == *handle) +		return 0; + +	return -1; +} + +static int active_conn_append(struct slist **list, bdaddr_t *bdaddr, uint16_t handle) +{ +	struct active_conn_info *dev = NULL; + +	dev = malloc(sizeof(*dev)); +	if (!dev) +		return -1; + +	dev->bdaddr = malloc(sizeof(*dev->bdaddr)); +	bacpy(dev->bdaddr, bdaddr); +	dev->handle = handle; + +	*list = slist_append(*list, dev); +	return 0; +} + +static int active_conn_remove(struct slist **list, uint16_t *handle) +{ +	struct active_conn_info *dev; +	struct slist *l; +	int ret_val = -1; + +	l = slist_find(*list, handle, active_conn_find_by_handle); + +	if (l) { +		dev = l->data; +		*list = slist_remove(*list, dev); +		free(dev->bdaddr); +		free(dev); +		ret_val = 0; +	} + +	return ret_val; +} +  static DBusMessage *dbus_msg_new_authentication_return(DBusMessage *msg, uint8_t status)  { @@ -356,14 +423,31 @@ failed:  static gboolean unregister_dbus_path(const char *path)  { -	struct hci_dbus_data *data; +	struct hci_dbus_data *pdata;  	info("Unregister path:%s", path); -	if (dbus_connection_get_object_path_data(connection, path, (void *) &data) && data) { -		if (data->requestor_name) -			free(data->requestor_name); -		free(data); +	if (dbus_connection_get_object_path_data(connection, path, (void *) &pdata) && pdata) { +		if (pdata->requestor_name) +			free(pdata->requestor_name); + +		if (pdata->discovered_devices) { +			slist_foreach(pdata->discovered_devices, discovered_device_info_free, NULL); +			slist_free(pdata->discovered_devices); +			pdata->discovered_devices = NULL; +		} + +		if (pdata->bonding_requests) { +			slist_foreach(pdata->bonding_requests, bonding_request_info_free, NULL); +			slist_free(pdata->bonding_requests); +			pdata->bonding_requests = NULL; +		} + +		if (pdata->active_conn) { +			slist_foreach(pdata->active_conn, active_conn_info_free, NULL); +			slist_free(pdata->active_conn); +			pdata->active_conn = NULL; +		}  	}  	if (!dbus_connection_unregister_object_path (connection, path)) { @@ -387,10 +471,12 @@ gboolean hcid_dbus_register_device(uint16_t id)  	char *pptr = path;  	gboolean ret;  	DBusMessage *message = NULL; -	int dd = -1; +	int i, dd = -1;  	read_scan_enable_rp rp;  	struct hci_request rq;  	struct hci_dbus_data* pdata; +	struct hci_conn_list_req *cl = NULL; +	struct hci_conn_info *ci = NULL;  	snprintf(path, sizeof(path), "%s/hci%d", ADAPTER_PATH, id);  	ret = register_dbus_path(path, ADAPTER_PATH_ID, id, &obj_dev_vtable, FALSE); @@ -447,6 +533,27 @@ gboolean hcid_dbus_register_device(uint16_t id)  	}  	dbus_connection_flush(connection); +	 +	/*  +	 * retrieve the active connections: address the scenario where +	 * the are active connections before the daemon've started +	 */ + +	cl = malloc(10 * sizeof(*ci) + sizeof(*cl)); +	if (!cl) +		goto failed; + +	cl->dev_id = id; +	cl->conn_num = 10; +	ci = cl->conn_info; + +	if (ioctl(dd, HCIGETCONNLIST, (void *) cl) < 0) { +		free(cl); +		goto failed; +	} + +	for (i = 0; i < cl->conn_num; i++, ci++) +		active_conn_append(&pdata->active_conn, &ci->bdaddr, ci->handle);  failed:  	if (message) @@ -458,6 +565,9 @@ failed:  	if (dd >= 0)  		close(dd); +	if (cl) +		free(cl); +  	return ret;  } @@ -752,7 +862,7 @@ void hcid_dbus_inquiry_complete(bdaddr_t *local)  		pdata->discover_state = DISCOVER_OFF;  		/* free discovered devices list */ -		slist_foreach(pdata->discovered_devices, discovered_device_free, NULL); +		slist_foreach(pdata->discovered_devices, discovered_device_info_free, NULL);  		slist_free(pdata->discovered_devices);  		pdata->discovered_devices = NULL; @@ -945,7 +1055,7 @@ void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char  		goto failed; /* skip if a new request has been sent */  	/* free discovered devices list */ -	slist_foreach(pdata->discovered_devices, discovered_device_free, NULL); +	slist_foreach(pdata->discovered_devices, discovered_device_info_free, NULL);  	slist_free(pdata->discovered_devices);  	pdata->discovered_devices = NULL; @@ -971,6 +1081,7 @@ failed:  void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, bdaddr_t *peer)  {  	char path[MAX_PATH_LENGTH]; +	DBusMessage *message = NULL;  	struct hci_request rq;  	evt_cmd_status rp;  	auth_requested_cp cp; @@ -992,28 +1103,37 @@ void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, b  	snprintf(path, sizeof(path), "%s/hci%d", ADAPTER_PATH, id); +	if (!status) { +		/* Sent the remote device connected signal */ +		message = dbus_message_new_signal(path, ADAPTER_INTERFACE, "RemoteDeviceConnected"); + +		dbus_message_append_args(message, +					 	DBUS_TYPE_STRING, &peer_addr, +						DBUS_TYPE_INVALID); + +		send_reply_and_unref(connection, message); +	} +  	if (!dbus_connection_get_object_path_data(connection, path, (void *) &pdata))  		goto failed; -	l = slist_find(pdata->bonding_requests, peer, bonding_requests_find); +	/* add in the active connetions list */ +	active_conn_append(&pdata->active_conn, peer, handle); -	/*  -	 * Connections can be requested by other applications,  profiles and bonding -	 * For now it's necessary check only if there a pending bonding request -	 */ +	/* check if this connection request was requested by a bonding procedure */ +	l = slist_find(pdata->bonding_requests, peer, bonding_requests_find);  	if (!l)   		goto failed;  	dev = l->data; -	/* connection failed */	  	if (status) {  		error_connection_attempt_failed(connection, dev->msg, status);  		goto failed;  	}  	if (dev->bonding_state != CONNECTING) -		goto failed; /* FIXME: is it possible? */ +		goto failed;  	dd = hci_open_dev(pdata->dev_id);  	if (dd < 0) { @@ -1032,7 +1152,6 @@ void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, b  	rq.event  = EVT_CMD_STATUS;  	rq.rparam = &rp;  	rq.rlen   = EVT_CMD_STATUS_SIZE; -  	rq.ocf    = OCF_AUTH_REQUESTED;  	rq.cparam = &cp;  	rq.clen   = AUTH_REQUESTED_CP_SIZE; @@ -1069,8 +1188,54 @@ failed:  	bt_free(peer_addr);  } -void hcid_dbus_disconn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t reason) +void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, uint8_t reason)  { +	char path[MAX_PATH_LENGTH]; +	struct hci_dbus_data *pdata = NULL; +	struct active_conn_info *dev; +	DBusMessage *message; +	struct slist *l; +	char *local_addr, *peer_addr = NULL; +	bdaddr_t tmp; +	int id; + +	baswap(&tmp, local); local_addr = batostr(&tmp); + +	id = hci_devid(local_addr); +	if (id < 0) { +		error("No matching device id for %s", local_addr); +		goto failed; +	} + +	snprintf(path, sizeof(path), "%s/hci%d", ADAPTER_PATH, id); + +	if (!dbus_connection_get_object_path_data(connection, path, (void *) &pdata)) +		goto failed; + +	l = slist_find(pdata->active_conn, &handle, active_conn_find_by_handle); + +	if (!l) +		goto failed; + +	dev = l->data; +	/* add in the active connetions list */ +	baswap(&tmp, dev->bdaddr); peer_addr = batostr(&tmp); + +	/* Sent the remote device disconnected signal */ +	message = dbus_message_new_signal(path, ADAPTER_INTERFACE, "RemoteDeviceDisconnected"); + +	dbus_message_append_args(message, +					DBUS_TYPE_STRING, &peer_addr, +					DBUS_TYPE_INVALID); + +	send_reply_and_unref(connection, message); +	active_conn_remove(&pdata->active_conn, &handle); + +failed: +	if (peer_addr) +		free(peer_addr); + +	free(local_addr);  }  /***************************************************************** diff --git a/hcid/dbus.h b/hcid/dbus.h index 8eba6a95..ae247fc0 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -100,6 +100,11 @@ struct bonding_request_info {  	bonding_state_t bonding_state;  }; +struct active_conn_info { +	bdaddr_t *bdaddr; +	uint16_t handle; +}; +  struct hci_dbus_data {  	uint16_t dev_id;  	uint16_t path_id; @@ -112,6 +117,7 @@ struct hci_dbus_data {  	char *requestor_name;	/* requestor unique name */  	struct slist *passkey_agents;  	struct slist *bonding_requests; +	struct slist *active_conn;  };  struct passkey_agent { @@ -184,7 +190,7 @@ static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusM  	return DBUS_HANDLER_RESULT_HANDLED;  } -void discovered_device_free(void *data, void *user_data); +void discovered_device_info_free(void *data, void *user_data);  int bonding_requests_find(const void *data, const void *user_data);  int remote_name_find_by_bdaddr(const void *data, const void *user_data);  int remote_name_append(struct slist **list, bdaddr_t *bdaddr, name_status_t name_status); diff --git a/hcid/hcid.h b/hcid/hcid.h index db2133c3..71389a62 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -117,7 +117,7 @@ void hcid_dbus_inquiry_complete(bdaddr_t *local);  void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, int8_t rssi);  void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name);  void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, bdaddr_t *peer); -void hcid_dbus_disconn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t reason); +void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, uint8_t reason);  void hcid_dbus_bonding_created_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status);  void hcid_dbus_setname_complete(bdaddr_t *local);  void hcid_dbus_setscan_enable_complete(bdaddr_t *local); diff --git a/hcid/security.c b/hcid/security.c index f42738a5..ba1fb0a1 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -478,14 +478,8 @@ static inline void conn_complete(int dev, bdaddr_t *sba, void *ptr)  static inline void disconn_complete(int dev, bdaddr_t *sba, void *ptr)  {  	evt_disconn_complete *evt = ptr; -	bdaddr_t dba; - -	if (evt->status) -		return; - -	bacpy(&dba, BDADDR_ANY); -	hcid_dbus_disconn_complete(sba, &dba, evt->reason); +	hcid_dbus_disconn_complete(sba, evt->status, evt->handle, evt->reason);  }  static inline void auth_complete(int dev, bdaddr_t *sba, void *ptr) | 
