#include "src/shared/att.h"
#include "src/shared/gatt-db.h"
+#include "btio/btio.h"
#include "hcid.h"
#include "sdpd.h"
#include "adapter.h"
return reply;
}
+struct device_connect_data {
+ struct btd_adapter *adapter;
+ bdaddr_t dst;
+ uint8_t dst_type;
+ DBusMessage *msg;
+};
+
+static void device_browse_cb(struct btd_device *dev, int err, void *user_data)
+{
+ DBG("err %d (%s)", err, strerror(-err));
+
+ if (!err)
+ btd_device_connect_services(dev, NULL);
+}
+
+static void device_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
+{
+ struct device_connect_data *data = user_data;
+ struct btd_adapter *adapter = data->adapter;
+ struct btd_device *device;
+ const char *path;
+
+ DBG("%s", gerr ? gerr->message : "");
+
+ if (gerr)
+ goto failed;
+
+ /* object might already exist due to mgmt socket event */
+ device = btd_adapter_get_device(adapter, &data->dst, data->dst_type);
+ if (!device)
+ goto failed;
+
+ path = device_get_path(device);
+
+ g_dbus_send_reply(dbus_conn, data->msg, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ /* continue with service discovery and connection */
+ btd_device_set_temporary(device, false);
+ device_update_last_seen(device, data->dst_type);
+
+ if (data->dst_type != BDADDR_BREDR){
+ g_io_channel_set_close_on_unref(io, FALSE);
+ device_attach_att(device, io);
+ }
+
+ device_discover_services(device);
+ device_wait_for_svc_complete(device, device_browse_cb, NULL);
+
+ g_io_channel_unref(io);
+ dbus_message_unref(data->msg);
+ free(data);
+ return;
+
+failed:
+ g_dbus_send_error(dbus_conn, data->msg, "org.bluez.Failed", NULL);
+ g_io_channel_unref(io);
+ dbus_message_unref(data->msg);
+ free(data);
+}
+
+static void device_connect(struct btd_adapter *adapter, const bdaddr_t *dst,
+ uint8_t dst_type, DBusMessage *msg)
+{
+ struct device_connect_data *data;
+ GIOChannel *io;
+
+ data = new0(struct device_connect_data, 1);
+ data->adapter = adapter;
+ bacpy(&data->dst, dst);
+ data->dst_type = dst_type;
+ data->msg = dbus_message_ref(msg);
+
+ if (dst_type == BDADDR_BREDR)
+ io = bt_io_connect(device_connect_cb, data, NULL, NULL,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter->bdaddr,
+ BT_IO_OPT_SOURCE_TYPE, BDADDR_BREDR,
+ BT_IO_OPT_DEST_BDADDR, dst,
+ BT_IO_OPT_DEST_TYPE, BDADDR_BREDR,
+ BT_IO_OPT_PSM, SDP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_INVALID);
+ else
+ io = bt_io_connect(device_connect_cb, data, NULL, NULL,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter->bdaddr,
+ BT_IO_OPT_SOURCE_TYPE, adapter->bdaddr_type,
+ BT_IO_OPT_DEST_BDADDR, dst,
+ BT_IO_OPT_DEST_TYPE, dst_type,
+ BT_IO_OPT_CID, ATT_CID,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_INVALID);
+
+ if (!io) {
+ g_dbus_send_message(dbus_conn,
+ btd_error_failed(msg, "Connect failed"));
+ dbus_message_unref(data->msg);
+ free(data);
+ }
+}
+
+static DBusMessage *connect_device(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ DBusMessageIter iter, subiter, dictiter, value;
+ uint8_t addr_type = BDADDR_BREDR;
+ bdaddr_t addr = *BDADDR_ANY;
+
+ DBG("sender %s", dbus_message_get_sender(msg));
+
+ if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+ return btd_error_not_ready(msg);
+
+ dbus_message_iter_init(msg, &iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &subiter);
+ while (true) {
+ int type = dbus_message_iter_get_arg_type(&subiter);
+ char *key;
+ char *str;
+
+ if (type == DBUS_TYPE_INVALID)
+ break;
+
+ dbus_message_iter_recurse(&subiter, &dictiter);
+
+ dbus_message_iter_get_basic(&dictiter, &key);
+ if (!dbus_message_iter_next(&dictiter))
+ return btd_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&dictiter) !=
+ DBUS_TYPE_VARIANT)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&dictiter, &value);
+
+ if (!strcmp(key, "Address")) {
+ if (dbus_message_iter_get_arg_type(&value) !=
+ DBUS_TYPE_STRING)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&value, &str);
+
+ if (str2ba(str, &addr) < 0 )
+ return btd_error_invalid_args(msg);
+ } else if (!strcmp(key, "AddressType")) {
+ if (dbus_message_iter_get_arg_type(&value) !=
+ DBUS_TYPE_STRING)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&value, &str);
+
+
+ if (!strcmp(str, "public"))
+ addr_type = BDADDR_LE_PUBLIC;
+ else if (!strcmp(str, "random"))
+ addr_type = BDADDR_LE_RANDOM;
+ else
+ return btd_error_invalid_args(msg);
+ } else {
+ return btd_error_invalid_args(msg);
+ }
+
+ dbus_message_iter_next(&subiter);
+ }
+
+ if (!bacmp(&addr, BDADDR_ANY))
+ return btd_error_invalid_args(msg);
+
+ if (btd_adapter_find_device(adapter, &addr, addr_type))
+ return btd_error_already_exists(msg);
+
+ device_connect(adapter, &addr, addr_type, msg);
+ return NULL;
+}
+
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
static DBusMessage *adapter_unpair_device(DBusConnection *conn,
{ GDBUS_METHOD("GetDiscoveryFilters", NULL,
GDBUS_ARGS({ "filters", "as" }),
get_discovery_filters) },
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ConnectDevice",
+ GDBUS_ARGS({ "properties", "a{sv}" }), NULL,
+ connect_device) },
{ }
};