From: Gowtham Anandha Babu Date: Wed, 24 May 2017 08:04:58 +0000 (+0530) Subject: [OTP] Add support for Object Transfer Channel X-Git-Tag: accepted/tizen/unified/20170613.194443~2^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2ef4759a7d0ad74c26b2526640fb52f85673cc58;p=platform%2Fupstream%2Fbluez.git [OTP] Add support for Object Transfer Channel Expose below DBus APIs: * ConnectOtc - bt_io_connect() * DisconnectOtc - shutdown() * ListenOtc - bt_io_listen() Change-Id: Ifa4379508e0d35500b141b597f30a9429d2e695a Signed-off-by: Gowtham Anandha Babu --- diff --git a/src/device.c b/src/device.c index 217e402..959fb22 100755 --- a/src/device.c +++ b/src/device.c @@ -356,6 +356,34 @@ typedef enum { #endif +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY +#define OTP_PSM 0x0025 + +/* OTP Client */ +#define BT_OTC_SERVICE_NAME "org.otp.client" +#define BT_OTC_OBJECT_PATH "/org/otp/client" +#define BT_OTC_INTERFACE_NAME "org.otp.otc_channel" + +/* OTP Server */ +#define BT_OTS_SERVICE_NAME "org.projectx.otp" +#define BT_OTS_OBJECT_PATH "/org/projectx/otp" +#define BT_OTS_INTERFACE_NAME "org.projectx.otp_service" + +typedef enum { + BT_OTP_CLIENT_ROLE = 0x00, + BT_OTP_SERVER_ROLE, +} bt_otp_role_e; + +struct otc_conn_info { + const char *dev_path; + bt_otp_role_e role; + GIOChannel *io; + bool otc_connected; +}; + +GSList *otc_connection_list = NULL; +#endif + static int device_browse_gatt(struct btd_device *device, DBusMessage *msg); static int device_browse_sdp(struct btd_device *device, DBusMessage *msg); @@ -3475,6 +3503,268 @@ static DBusMessage *disconnect_ipsp(DBusConnection *conn, DBusMessage *msg, return dbus_message_new_method_return(msg);; } +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY +static GSList *find_otc_conn_info(GSList *list, const char *path) +{ + GSList *l; + + for (l = list; l != NULL; l = g_slist_next(l)) { + struct otc_conn_info *info = l->data; + + if (g_strcmp0(info->dev_path, path) == 0) + return l; + } + + return NULL; +} + +static gboolean otc_disconnected_cb(GIOChannel *chan, GIOCondition cond, + gpointer user_data) +{ + struct otc_conn_info *conn_info; + const char *dev_path = (const char *) user_data; + GSList *l; + + DBG("OTC Disconnected"); + + l = find_otc_conn_info(otc_connection_list, dev_path); + if (!l) + return FALSE; + + conn_info = l->data; + conn_info->otc_connected = false; + + g_dbus_emit_signal(dbus_conn, dev_path, + DEVICE_INTERFACE, "OtcDisconnected", + DBUS_TYPE_INVALID); + + if (conn_info->io) { + g_io_channel_shutdown(conn_info->io, TRUE, NULL); + g_io_channel_unref(conn_info->io); + } + + otc_connection_list = g_slist_remove(otc_connection_list, conn_info); + g_free(conn_info); + + return FALSE; +} + +static void otc_connect_cb(GIOChannel *chan, GError *gerr, + gpointer user_data) +{ + const char *dev_path; + GSList *l; + struct otc_conn_info *conn_info = NULL; + DBusMessage *msg = NULL; + DBusMessageIter iter; + int fd; + + if (gerr) + return; + + dev_path = (const char *) user_data; + l = find_otc_conn_info(otc_connection_list, dev_path); + + if (!l) + return; + + conn_info = l->data; + conn_info->otc_connected = true; + + fd = g_io_channel_unix_get_fd(chan); + + DBG("OTC Connected fd [%d], role [%s]", + fd, conn_info->role ? "server" : "client"); + DBG("dev_path [%s]", dev_path); + + g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL, + otc_disconnected_cb, (gpointer) dev_path); + + if (conn_info->role == BT_OTP_CLIENT_ROLE) { + msg = dbus_message_new_method_call(BT_OTC_SERVICE_NAME, + BT_OTC_OBJECT_PATH, + BT_OTC_INTERFACE_NAME, + "NewConnection"); + } else if (conn_info->role == BT_OTP_SERVER_ROLE) { + msg = dbus_message_new_method_call(BT_OTS_SERVICE_NAME, + BT_OTS_OBJECT_PATH, + BT_OTS_INTERFACE_NAME, + "NewConnection"); + } + + if (!msg) { + error("Unable to create NewConnection call"); + return; + } + + dbus_message_iter_init_append(msg, &iter); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &dev_path); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd); + + if (!g_dbus_send_message(dbus_conn, msg)) { + error("sending NewConnection failed"); + dbus_message_unref(msg); + } +} + +int btd_adapter_connect_otc(struct btd_device *device) +{ + struct btd_adapter *adapter = device_get_adapter(device); + const bdaddr_t *src = btd_adapter_get_address(adapter); + uint8_t src_type = btd_adapter_get_le_address_type(adapter); + const bdaddr_t *dest = device_get_address(device); + uint8_t dest_type = device->bdaddr_type; + struct otc_conn_info *conn_info = NULL; + const char *dev_path = device_get_path(device); + GError *gerr = NULL; + + conn_info = g_malloc0(sizeof(struct otc_conn_info)); + + conn_info->io = bt_io_connect(otc_connect_cb, + (gpointer) dev_path, NULL, &gerr, + BT_IO_OPT_SOURCE_BDADDR, src, + BT_IO_OPT_SOURCE_TYPE, src_type, + BT_IO_OPT_DEST_BDADDR, dest, + BT_IO_OPT_DEST_TYPE, dest_type, + BT_IO_OPT_PSM, OTP_PSM, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, + BT_IO_OPT_INVALID); + + if (!conn_info->io) { + error("OTC Connect failed : %s", gerr->message); + g_error_free(gerr); + g_io_channel_unref(conn_info->io); + g_free(conn_info); + return -EIO; + } + + conn_info->dev_path = dev_path; + conn_info->role = BT_OTP_CLIENT_ROLE; + conn_info->otc_connected = false; + g_io_channel_set_close_on_unref(conn_info->io, FALSE); + + otc_connection_list = g_slist_append(otc_connection_list, conn_info); + return 0; +} + +static DBusMessage *connect_otc(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_device *device = user_data; + GSList *l; + + if (device == NULL) + return btd_error_invalid_args(msg); + + l = find_otc_conn_info(otc_connection_list, device_get_path(device)); + + if (l) { + struct otc_conn_info *info = l->data; + if (info->otc_connected) + return btd_error_already_connected(msg); + else + return btd_error_busy(msg); + } + + if (btd_adapter_connect_otc(device) != 0) + return btd_error_failed(msg, "ConnectFailed"); + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *disconnect_otc(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_device *device = user_data; + struct otc_conn_info *info = NULL; + GError *gerr = NULL; + GSList *l; + int sock; + + l = find_otc_conn_info(otc_connection_list, device_get_path(device)); + + if (!l) + return btd_error_does_not_exist(msg); + + info = l->data; + + if (!info->otc_connected) + return btd_error_not_connected(msg); + + sock = g_io_channel_unix_get_fd(info->io); + + shutdown(sock, SHUT_RDWR); + + g_io_channel_shutdown(info->io, FALSE, NULL); + + g_io_channel_unref(info->io); + info->io = NULL; + + return dbus_message_new_method_return(msg); +} + +int btd_adapter_listen_otc(struct btd_device *device) +{ + struct btd_adapter *adapter = device_get_adapter(device); + const bdaddr_t *src = btd_adapter_get_address(adapter); + uint8_t type = btd_adapter_get_le_address_type(adapter); + struct otc_conn_info *conn_info = NULL; + const char *dev_path = device_get_path(device); + GError *gerr = NULL; + + conn_info = g_malloc0(sizeof(struct otc_conn_info)); + + conn_info->io = bt_io_listen(otc_connect_cb, NULL, (gpointer) dev_path, + NULL, &gerr, + BT_IO_OPT_SOURCE_BDADDR, src, + BT_IO_OPT_SOURCE_TYPE, type, + BT_IO_OPT_PSM, OTP_PSM, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, + BT_IO_OPT_INVALID); + + if (!conn_info->io) { + error("OTC Listen failed : %s", gerr->message); + g_error_free(gerr); + return -EIO; + } + + conn_info->dev_path = dev_path; + conn_info->otc_connected = false; + conn_info->role = BT_OTP_SERVER_ROLE; + g_io_channel_set_close_on_unref(conn_info->io, FALSE); + + otc_connection_list = g_slist_append(otc_connection_list, conn_info); + return 0; +} + +static DBusMessage *listen_otc(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_device *device = user_data; + GSList *l; + + if (device == NULL) + return btd_error_invalid_args(msg); + + l = find_otc_conn_info(otc_connection_list, device_get_path(device)); + + if (l) { + struct otc_conn_info *info = l->data; + if (info->otc_connected) + return btd_error_already_connected(msg); + else + return btd_error_busy(msg); + } + + if (btd_adapter_listen_otc(device) != 0) + return btd_error_failed(msg, "ListenFailed"); + + return dbus_message_new_method_return(msg); +} +#endif + static DBusMessage *le_set_data_length( DBusConnection *conn, DBusMessage *msg, void *user_data) @@ -3856,6 +4146,11 @@ static const GDBusMethodTable device_methods[] = { { GDBUS_METHOD("CancelDiscovery", NULL, NULL, cancel_discover) }, { GDBUS_ASYNC_METHOD("ConnectIpsp", NULL, NULL, connect_ipsp) }, { GDBUS_ASYNC_METHOD("DisconnectIpsp", NULL, NULL, disconnect_ipsp) }, +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY + { GDBUS_METHOD("ConnectOtc", NULL, NULL, connect_otc) }, + { GDBUS_METHOD("DisconnectOtc", NULL, NULL, disconnect_otc) }, + { GDBUS_METHOD("ListenOtc", NULL, NULL, listen_otc) }, +#endif { GDBUS_ASYNC_METHOD("LESetDataLength", GDBUS_ARGS({"max_tx_octets", "q" }, { "max_tx_time", "q" }), NULL,