diff options
Diffstat (limited to 'hcid')
-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) |