summaryrefslogtreecommitdiffstats
path: root/hcid
diff options
context:
space:
mode:
Diffstat (limited to 'hcid')
-rw-r--r--hcid/dbus-adapter.c23
-rw-r--r--hcid/dbus.c201
-rw-r--r--hcid/dbus.h8
-rw-r--r--hcid/hcid.h2
-rw-r--r--hcid/security.c8
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)