diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 0533b67..d14d0ca 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
Possible errors: None
+ object ConnectDevice(dict properties) [experimental]
+
+ This method connects to device without need of
+ performing General Discovery. Connection mechanism is
+ similar to Connect method from Device1 interface with
+ exception that this method returns success when physical
+ connection is established. After this method returns,
+ services discovery will continue and any supported
+ profile will be connected. There is no need for calling
+ Connect on Device1 after this call. If connection was
+ successful this method returns object path to created
+ device object.
+
+ Parameters that may be set in the filter dictionary
+ include the following:
+
+ string Address
+
+ The Bluetooth device address of the remote
+ device. This parameter is mandatory.
+
+ string AddressType
+
+ The Bluetooth device Address Type. This is
+ address type that should be used for initial
+ connection. If this parameter is not present
+ BR/EDR device is created.
+
+ Possible values:
+ "public" - Public address
+ "random" - Random address
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+ org.bluez.Error.NotSupported
+ org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+
Properties string Address [readonly]
The Bluetooth device address.
diff --git a/src/adapter.c b/src/adapter.c
index 8a99f52..0fc9f84 100644
--- a/src/adapter.c
+++ b/src/adapter.c
#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;
+}
+
static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_ASYNC_METHOD("StartDiscovery", NULL, NULL, start_discovery) },
{ GDBUS_METHOD("SetDiscoveryFilter",
{ GDBUS_METHOD("GetDiscoveryFilters", NULL,
GDBUS_ARGS({ "filters", "as" }),
get_discovery_filters) },
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ConnectDevice",
+ GDBUS_ARGS({ "properties", "a{sv}" }), NULL,
+ connect_device) },
{ }
};
diff --git a/src/device.c b/src/device.c
index 0da4184..1b84040 100644
--- a/src/device.c
+++ b/src/device.c
if (!dev->bredr_state.svc_resolved)
return -ENOENT;
- for (l = services; l; l = g_slist_next(l)) {
- struct btd_service *service = l->data;
+ if (services) {
+ for (l = services; l; l = g_slist_next(l)) {
+ struct btd_service *service = l->data;
- dev->pending = g_slist_append(dev->pending, service);
+ dev->pending = g_slist_append(dev->pending, service);
+ }
+ } else {
+ dev->pending = create_pending_list(dev, NULL);
}
return connect_next(dev);
dev->pending_paired = false;
}
+ if (!dev->temporary)
+ store_device_info(dev);
+
+ if (bdaddr_type != BDADDR_BREDR && err == 0)
+ store_services(dev);
+
+ if (req)
+ browse_request_complete(req, browse_type, bdaddr_type, err);
+
while (dev->svc_callbacks) {
struct svc_callback *cb = dev->svc_callbacks->data;
dev->svc_callbacks);
g_free(cb);
}
-
- if (!dev->temporary)
- store_device_info(dev);
-
- if (bdaddr_type != BDADDR_BREDR && err == 0)
- store_services(dev);
-
- if (!req)
- return;
-
- browse_request_complete(req, browse_type, bdaddr_type, err);
}
static struct bonding_req *bonding_request_new(DBusMessage *msg,