Example #1
0
File: sink.c Project: Thread974/bz
static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
					struct avdtp_stream *stream,
					struct avdtp_error *err, void *user_data)
{
	struct sink *sink = user_data;

	sink->connect_id = 0;

	if (stream) {
		DBG("Stream successfully created");
		btd_service_connecting_complete(sink->service, 0);
		return;
	}

	avdtp_unref(sink->session);
	sink->session = NULL;
	if (avdtp_error_category(err) == AVDTP_ERRNO
			&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
		DBG("connect:connect XCASE detected");
		sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
							stream_setup_retry,
							sink);
	} else {
		DBG("Stream setup failed : %s", avdtp_strerror(err));
		btd_service_connecting_complete(sink->service, -EIO);
	}
}
Example #2
0
int btd_service_connect(struct btd_service *service)
{
	struct btd_profile *profile = service->profile;
	char addr[18];
	int err;

	if (!profile->connect)
		return -ENOTSUP;

	switch (service->state) {
	case BTD_SERVICE_STATE_UNAVAILABLE:
		return -EINVAL;
	case BTD_SERVICE_STATE_DISCONNECTED:
		break;
	case BTD_SERVICE_STATE_CONNECTING:
	case BTD_SERVICE_STATE_CONNECTED:
		return -EALREADY;
	case BTD_SERVICE_STATE_DISCONNECTING:
		return -EBUSY;
	}

	change_state(service, BTD_SERVICE_STATE_CONNECTING, 0);

	err = profile->connect(service);
	if (err == 0)
		return 0;

	ba2str(device_get_address(service->device), addr);
	error("%s profile connect failed for %s: %s", profile->name, addr,
								strerror(-err));

	btd_service_connecting_complete(service, err);

	return err;
}
Example #3
0
static void source_free(struct btd_service *service)
{
	struct source *source = btd_service_get_user_data(service);

	if (source->cb_id)
		avdtp_stream_remove_cb(source->session, source->stream,
					source->cb_id);

	if (source->session)
		avdtp_unref(source->session);

	if (source->connect_id > 0) {
		btd_service_connecting_complete(source->service, -ECANCELED);
		a2dp_cancel(source->connect_id);
		source->connect_id = 0;
	}

	if (source->disconnect_id > 0) {
		btd_service_disconnecting_complete(source->service, -ECANCELED);
		a2dp_cancel(source->disconnect_id);
		source->disconnect_id = 0;
	}

	avdtp_remove_state_cb(source->avdtp_callback_id);
	btd_service_unref(source->service);

	g_free(source);
}
Example #4
0
static int gap_accept(struct btd_service *service)
{
	struct btd_device *device = btd_service_get_device(service);
	struct gatt_db *db = btd_device_get_gatt_db(device);
	struct bt_gatt_client *client = btd_device_get_gatt_client(device);
	struct gas *gas = btd_service_get_user_data(service);
	char addr[18];
	bt_uuid_t gap_uuid;

	ba2str(device_get_address(device), addr);
	DBG("GAP profile accept (%s)", addr);

	if (!gas) {
		error("GAP service not handled by profile");
		return -1;
	}

	gas->db = gatt_db_ref(db);
	gas->client = bt_gatt_client_ref(client);

	/* Handle the GAP services */
	bt_uuid16_create(&gap_uuid, GAP_UUID16);
	gatt_db_foreach_service(db, &gap_uuid, foreach_gap_service, gas);

	if (!gas->attr) {
		error("GAP attribute not found");
		gas_reset(gas);
		return -1;
	}

	btd_service_connecting_complete(service, 0);

	return 0;
}
Example #5
0
File: sink.c Project: Thread974/bz
int sink_disconnect(struct audio_device *dev, gboolean shutdown)
{
	struct sink *sink = dev->sink;

	if (!sink->session)
		return -ENOTCONN;

	if (shutdown)
		avdtp_set_device_disconnect(sink->session, TRUE);

	/* cancel pending connect */
	if (sink->connect_id > 0) {
		a2dp_cancel(dev, sink->connect_id);
		sink->connect_id = 0;
		btd_service_connecting_complete(sink->service, -ECANCELED);

		avdtp_unref(sink->session);
		sink->session = NULL;

		return 0;
	}

	/* disconnect already ongoing */
	if (sink->disconnect_id > 0)
		return -EBUSY;

	if (!sink->stream)
		return -ENOTCONN;

	return avdtp_close(sink->session, sink->stream, FALSE);
}
Example #6
0
File: sink.c Project: Thread974/bz
static void sink_free(struct audio_device *dev)
{
	struct sink *sink = dev->sink;

	if (sink->cb_id)
		avdtp_stream_remove_cb(sink->session, sink->stream,
					sink->cb_id);

	if (sink->session)
		avdtp_unref(sink->session);

	if (sink->connect_id > 0) {
		btd_service_connecting_complete(sink->service, -ECANCELED);
		a2dp_cancel(dev, sink->connect_id);
		sink->connect_id = 0;
	}

	if (sink->disconnect_id > 0) {
		btd_service_disconnecting_complete(sink->service, -ECANCELED);
		a2dp_cancel(dev, sink->disconnect_id);
		sink->disconnect_id = 0;
	}

	if (sink->retry_id)
		g_source_remove(sink->retry_id);

	avdtp_remove_state_cb(sink->avdtp_callback_id);
	btd_service_unref(sink->service);

	g_free(sink);
	dev->sink = NULL;
}
Example #7
0
int source_disconnect(struct btd_service *service)
{
	struct source *source = btd_service_get_user_data(service);

	if (!source->session)
		return -ENOTCONN;

	/* cancel pending connect */
	if (source->connect_id > 0) {
		a2dp_cancel(source->connect_id);
		source->connect_id = 0;
		btd_service_connecting_complete(source->service, -ECANCELED);

		avdtp_unref(source->session);
		source->session = NULL;

		return 0;
	}

	/* disconnect already ongoing */
	if (source->disconnect_id > 0)
		return -EBUSY;

	if (!source->stream)
		return -ENOTCONN;

	return avdtp_close(source->session, source->stream, FALSE);
}
Example #8
0
static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
					struct avdtp_stream *stream,
					struct avdtp_error *err, void *user_data)
{
	struct source *source = user_data;

	source->connect_id = 0;

	if (stream)
		return;

	avdtp_unref(source->session);
	source->session = NULL;
	if (avdtp_error_category(err) == AVDTP_ERRNO
				&& avdtp_error_posix_errno(err) != EHOSTDOWN)
		btd_service_connecting_complete(source->service, -EAGAIN);
	else
		btd_service_connecting_complete(source->service, -EIO);
}
Example #9
0
static void cancel_connection(struct network_conn *nc, int err)
{
	btd_service_connecting_complete(nc->service, err);
	if (nc->connect)
		local_connect_cb(nc, err);

	g_io_channel_shutdown(nc->io, TRUE, NULL);
	g_io_channel_unref(nc->io);
	nc->io = NULL;

	nc->state = DISCONNECTED;
}
Example #10
0
static int input_device_connected(struct input_device *idev)
{
	int err;

	if (idev->intr_io == NULL || idev->ctrl_io == NULL)
		return -ENOTCONN;

	err = hidp_add_connection(idev);
	if (err < 0)
		return err;

	btd_service_connecting_complete(idev->service, 0);

	return 0;
}
Example #11
0
static void stream_state_changed(struct avdtp_stream *stream,
					avdtp_state_t old_state,
					avdtp_state_t new_state,
					struct avdtp_error *err,
					void *user_data)
{
	struct btd_service *service = user_data;
	struct source *source = btd_service_get_user_data(service);

	if (err)
		return;

	switch (new_state) {
	case AVDTP_STATE_IDLE:
		btd_service_disconnecting_complete(source->service, 0);

		if (source->disconnect_id > 0) {
			a2dp_cancel(source->disconnect_id);
			source->disconnect_id = 0;
		}

		if (source->session) {
			avdtp_unref(source->session);
			source->session = NULL;
		}
		source->stream = NULL;
		source->cb_id = 0;
		break;
	case AVDTP_STATE_OPEN:
		btd_service_connecting_complete(source->service, 0);
		source_set_state(source, SOURCE_STATE_CONNECTED);
		break;
	case AVDTP_STATE_STREAMING:
		source_set_state(source, SOURCE_STATE_PLAYING);
		break;
	case AVDTP_STATE_CONFIGURED:
	case AVDTP_STATE_CLOSING:
	case AVDTP_STATE_ABORTING:
	default:
		break;
	}

	source->stream_state = new_state;
}
Example #12
0
static void bnep_conn_cb(GIOChannel *chan, char *iface, int err, void *data)
{
	struct network_conn *nc = data;
	const char *path;
	DBusConnection *conn;

	DBG("");

	if (err < 0) {
		error("connect failed %s", strerror(-err));
		goto failed;
	}

	info("%s connected", nc->dev);

	memcpy(nc->dev, iface, sizeof(nc->dev));
	btd_service_connecting_complete(nc->service, 0);

	if (nc->connect)
		local_connect_cb(nc, 0);

	conn = btd_get_dbus_connection();
	path = device_get_path(nc->peer->device);

	g_dbus_emit_property_changed(conn, path,
					NETWORK_PEER_INTERFACE, "Connected");
	g_dbus_emit_property_changed(conn, path,
					NETWORK_PEER_INTERFACE, "Interface");
	g_dbus_emit_property_changed(conn, path,
					NETWORK_PEER_INTERFACE, "UUID");

	nc->state = CONNECTED;
	nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb,
								nc, NULL);
	g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
							bnep_watchdog_cb, nc);
	g_io_channel_unref(nc->io);
	nc->io = NULL;

	return;

failed:
	cancel_connection(nc, -EIO);
}
Example #13
0
static int deviceinfo_accept(struct btd_service *service)
{
	struct btd_device *device = btd_service_get_device(service);
	struct gatt_db *db = btd_device_get_gatt_db(device);
	char addr[18];
	bt_uuid_t deviceinfo_uuid;

	ba2str(device_get_address(device), addr);
	DBG("deviceinfo profile accept (%s)", addr);

	/* Handle the device info service */
	bt_string_to_uuid(&deviceinfo_uuid, DEVICE_INFORMATION_UUID);
	gatt_db_foreach_service(db, &deviceinfo_uuid,
					foreach_deviceinfo_service, device);

	btd_service_connecting_complete(service, 0);

	return 0;
}
Example #14
0
static void control_connect_cb(GIOChannel *chan, GError *conn_err,
							gpointer user_data)
{
	struct input_device *idev = user_data;
	GIOCondition cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
	GIOChannel *io;
	GError *err = NULL;

	if (conn_err) {
		error("%s", conn_err->message);
		goto failed;
	}

	/* Connect to the HID interrupt channel */
	io = bt_io_connect(interrupt_connect_cb, idev,
				NULL, &err,
				BT_IO_OPT_SOURCE_BDADDR, &idev->src,
				BT_IO_OPT_DEST_BDADDR, &idev->dst,
				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
				BT_IO_OPT_INVALID);
	if (!io) {
		error("%s", err->message);
		g_error_free(err);
		goto failed;
	}

	idev->intr_io = io;

	if (idev->uhid)
		cond |= G_IO_IN;

	idev->ctrl_watch = g_io_add_watch(idev->ctrl_io, cond, ctrl_watch_cb,
									idev);

	return;

failed:
	btd_service_connecting_complete(idev->service, -EIO);
	g_io_channel_unref(idev->ctrl_io);
	idev->ctrl_io = NULL;
}
Example #15
0
static void interrupt_connect_cb(GIOChannel *chan, GError *conn_err,
							gpointer user_data)
{
	struct input_device *idev = user_data;
	GIOCondition cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
	int err;

	if (conn_err) {
		err = -EIO;
		goto failed;
	}

	err = input_device_connected(idev);
	if (err < 0)
		goto failed;

	if (idev->uhid)
		cond |= G_IO_IN;

	idev->intr_watch = g_io_add_watch(idev->intr_io, cond, intr_watch_cb,
									idev);

	return;

failed:
	btd_service_connecting_complete(idev->service, err);

	/* So we guarantee the interrupt channel is closed before the
	 * control channel (if we only do unref GLib will close it only
	 * after returning control to the mainloop */
	if (!conn_err)
		g_io_channel_shutdown(idev->intr_io, FALSE, NULL);

	g_io_channel_unref(idev->intr_io);
	idev->intr_io = NULL;

	if (idev->ctrl_io) {
		g_io_channel_unref(idev->ctrl_io);
		idev->ctrl_io = NULL;
	}
}
Example #16
0
static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
			GSList *caps, void *user_data)
{
	struct sink *sink = user_data;
	int id;

	sink->connect_id = 0;

	id = a2dp_config(session, sep, stream_setup_complete, caps, sink);
	if (id == 0)
		goto failed;

	sink->connect_id = id;
	return;

failed:
	btd_service_connecting_complete(sink->service, -EIO);

	avdtp_unref(sink->session);
	sink->session = NULL;
}
Example #17
0
static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
				void *user_data)
{
	struct source *source = user_data;
	int id, perr;

	if (err) {
		avdtp_unref(source->session);
		source->session = NULL;

		perr = -avdtp_error_posix_errno(err);
		if (perr != -EHOSTDOWN) {
			if (avdtp_error_category(err) == AVDTP_ERRNO)
				perr = -EAGAIN;
			else
				perr = -EIO;
		}
		goto failed;
	}

	DBG("Discovery complete");

	id = a2dp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL,
						select_complete, source);
	if (id == 0) {
		perr = -EIO;
		goto failed;
	}

	source->connect_id = id;
	return;

failed:
	btd_service_connecting_complete(source->service, perr);
	avdtp_unref(source->session);
	source->session = NULL;
}
Example #18
0
File: sink.c Project: Thread974/bz
static gboolean stream_setup_retry(gpointer user_data)
{
	struct sink *sink = user_data;
	int err;

	sink->retry_id = 0;

	if (sink->stream_state >= AVDTP_STATE_OPEN) {
		DBG("Stream successfully created, after XCASE connect:connect");
		err = 0;
	} else {
		DBG("Stream setup failed, after XCASE connect:connect");
		err = -EIO;
	}

	btd_service_connecting_complete(sink->service, err);

	if (sink->connect_id > 0) {
		a2dp_cancel(sink->dev, sink->connect_id);
		sink->connect_id = 0;
	}

	return FALSE;
}
Example #19
0
File: sink.c Project: Thread974/bz
static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
				void *user_data)
{
	struct sink *sink = user_data;
	int id;

	if (err) {
		avdtp_unref(sink->session);
		sink->session = NULL;
		if (avdtp_error_category(err) == AVDTP_ERRNO
				&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
			DBG("connect:connect XCASE detected");
			sink->retry_id =
				g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
							stream_setup_retry,
							sink);
		} else
			goto failed;
		return;
	}

	DBG("Discovery complete");

	id = a2dp_select_capabilities(sink->session, AVDTP_SEP_TYPE_SINK, NULL,
						select_complete, sink);
	if (id == 0)
		goto failed;

	sink->connect_id = id;
	return;

failed:
	btd_service_connecting_complete(sink->service, -EIO);
	avdtp_unref(sink->session);
	sink->session = NULL;
}
Example #20
0
static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
							gpointer data)
{
	struct network_conn *nc = data;
	struct bnep_control_rsp *rsp;
	struct timeval timeo;
	char pkt[BNEP_MTU];
	ssize_t r;
	int sk;
	const char *path;
	DBusConnection *conn;

	DBG("cond %u", cond);

	if (cond & G_IO_NVAL)
		return FALSE;

	if (nc->timeout_source > 0) {
		g_source_remove(nc->timeout_source);
		nc->timeout_source = 0;
	}

	if (cond & (G_IO_HUP | G_IO_ERR)) {
		error("Hangup or error on l2cap server socket");
		goto failed;
	}

	sk = g_io_channel_unix_get_fd(chan);

	memset(pkt, 0, BNEP_MTU);
	r = read(sk, pkt, sizeof(pkt) -1);
	if (r < 0) {
		error("IO Channel read error");
		goto failed;
	}

	if (r == 0) {
		error("No packet received on l2cap socket");
		goto failed;
	}

	errno = EPROTO;

	if ((size_t) r < sizeof(*rsp)) {
		error("Packet received is not bnep type");
		goto failed;
	}

	rsp = (void *) pkt;
	if (rsp->type != BNEP_CONTROL) {
		error("Packet received is not bnep type");
		goto failed;
	}

	if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
		return TRUE;

	r = ntohs(rsp->resp);

	if (r != BNEP_SUCCESS) {
		error("bnep failed");
		goto failed;
	}

	memset(&timeo, 0, sizeof(timeo));
	timeo.tv_sec = 0;

	setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));

	if (bnep_connadd(sk, BNEP_SVC_PANU, nc->dev)) {
		error("%s could not be added", nc->dev);
		goto failed;
	}

	bnep_if_up(nc->dev);

	btd_service_connecting_complete(nc->service, 0);
	if (nc->connect)
		local_connect_cb(nc, 0);

	conn = btd_get_dbus_connection();
	path = device_get_path(nc->peer->device);

	g_dbus_emit_property_changed(conn, path,
					NETWORK_PEER_INTERFACE, "Connected");
	g_dbus_emit_property_changed(conn, path,
					NETWORK_PEER_INTERFACE, "Interface");
	g_dbus_emit_property_changed(conn, path,
					NETWORK_PEER_INTERFACE, "UUID");

	nc->state = CONNECTED;
	nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb,
						nc, NULL);

	info("%s connected", nc->dev);
	/* Start watchdog */
	g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
			(GIOFunc) bnep_watchdog_cb, nc);
	g_io_channel_unref(nc->io);
	nc->io = NULL;

	return FALSE;

failed:
	cancel_connection(nc, -EIO);

	return FALSE;
}