示例#1
0
int kdbus_msg_recv(struct kdbus_conn *conn,
		   struct kdbus_msg **msg_out,
		   uint64_t *offset)
{
	struct kdbus_cmd_recv recv = {};
	struct kdbus_msg *msg;
	int ret;

	ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv);
	if (ret < 0) {
		ret = -errno;
		return ret;
	}

	msg = (struct kdbus_msg *)(conn->buf + recv.offset);
	kdbus_msg_dump(conn, msg);

	if (msg_out) {
		*msg_out = msg;

		if (offset)
			*offset = recv.offset;
	} else {
		kdbus_msg_free(msg);

		ret = kdbus_free(conn, recv.offset);
		if (ret < 0)
			return ret;
	}

	return 0;
}
示例#2
0
int kdbus_name_list(struct kdbus_conn *conn, uint64_t flags)
{
	struct kdbus_cmd_name_list cmd_list;
	struct kdbus_name_list *list;
	struct kdbus_cmd_name *name;
	int ret;

	cmd_list.flags = flags;

	ret = ioctl(conn->fd, KDBUS_CMD_NAME_LIST, &cmd_list);
	if (ret < 0) {
		kdbus_printf("error listing names: %d (%m)\n", ret);
		return EXIT_FAILURE;
	}

	kdbus_printf("REGISTRY:\n");
	list = (struct kdbus_name_list *)(conn->buf + cmd_list.offset);
	KDBUS_ITEM_FOREACH(name, list, names)
		kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n",
		       name->owner_id,
		       name->flags, name->conn_flags,
		       name->size > sizeof(struct kdbus_cmd_name) ? name->name : "");
	kdbus_printf("\n");

	ret = kdbus_free(conn, cmd_list.offset);

	return ret;
}
示例#3
0
int timeout_msg_recv(struct kdbus_conn *conn)
{
	struct kdbus_cmd_recv recv = {};
	struct kdbus_msg *msg;
	int ret;

	ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv);
	if (ret < 0) {
		kdbus_printf("error receiving message: %d (%m)\n", ret);
		return -errno;
	}

	msg = (struct kdbus_msg *)(conn->buf + recv.offset);

	ASSERT_RETURN_VAL(msg->payload_type == KDBUS_PAYLOAD_KERNEL, -EINVAL);
	ASSERT_RETURN_VAL(msg->src_id == KDBUS_SRC_ID_KERNEL, -EINVAL);
	ASSERT_RETURN_VAL(msg->dst_id == conn->id, -EINVAL);

	expected &= ~(1ULL << msg->cookie_reply);
	kdbus_printf("Got message timeout for cookie %llu\n",
		     msg->cookie_reply);

	ret = kdbus_free(conn, recv.offset);
	if (ret < 0)
		return ret;

	return 0;
}
示例#4
0
int kdbus_test_message_basic(struct kdbus_test_env *env)
{
	struct kdbus_conn *conn;
	struct kdbus_conn *sender;
	struct kdbus_msg *msg;
	uint64_t cookie = 0x1234abcd5678eeff;
	uint64_t offset;
	int ret;

	sender = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(sender != NULL);

	/* create a 2nd connection */
	conn = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn != NULL);

	ret = kdbus_add_match_empty(conn);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_add_match_empty(sender);
	ASSERT_RETURN(ret == 0);

	/* send over 1st connection */
	ret = kdbus_msg_send(sender, NULL, cookie, 0, 0, 0,
			     KDBUS_DST_ID_BROADCAST);
	ASSERT_RETURN(ret == 0);

	/* Make sure that we do not get our own broadcasts */
	ret = kdbus_msg_recv(sender, NULL, NULL);
	ASSERT_RETURN(ret == -EAGAIN);

	/* ... and receive on the 2nd */
	ret = kdbus_msg_recv_poll(conn, 100, &msg, &offset);
	ASSERT_RETURN(ret == 0);
	ASSERT_RETURN(msg->cookie == cookie);

	kdbus_msg_free(msg);

	ret = kdbus_free(conn, offset);
	ASSERT_RETURN(ret == 0);

	kdbus_conn_free(sender);
	kdbus_conn_free(conn);

	return TEST_OK;
}
示例#5
0
int kdbus_test_byebye(struct kdbus_test_env *env)
{
	struct kdbus_conn *conn;
	struct kdbus_cmd_recv recv = {};
	int ret;

	/* create a 2nd connection */
	conn = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn != NULL);

	ret = kdbus_add_match_empty(conn);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_add_match_empty(env->conn);
	ASSERT_RETURN(ret == 0);

	/* send over 1st connection */
	ret = kdbus_msg_send(env->conn, NULL, 0, 0, 0, 0,
			     KDBUS_DST_ID_BROADCAST);
	ASSERT_RETURN(ret == 0);

	/* say byebye on the 2nd, which must fail */
	ret = ioctl(conn->fd, KDBUS_CMD_BYEBYE, 0);
	ASSERT_RETURN(ret == -1 && errno == EBUSY);

	/* receive the message */
	ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_free(conn, recv.offset);
	ASSERT_RETURN(ret == 0);

	/* and try again */
	ret = ioctl(conn->fd, KDBUS_CMD_BYEBYE, 0);
	ASSERT_RETURN(ret == 0);

	/* a 2nd try should result in -EALREADY */
	ret = ioctl(conn->fd, KDBUS_CMD_BYEBYE, 0);
	ASSERT_RETURN(ret == -1 && errno == EOPNOTSUPP);

	kdbus_conn_free(conn);

	return TEST_OK;
}
示例#6
0
static int kdbus_fork_test_by_id(const char *bus,
				 struct kdbus_conn **conn_db,
				 int parent_status, int child_status)
{
	int ret;
	pid_t pid;
	uint64_t cookie = 0x9876ecba;
	struct kdbus_msg *msg = NULL;
	uint64_t offset = 0;
	int status = 0;

	/*
	 * If the child_status is not EXIT_SUCCESS, then we expect
	 * that sending from the child will fail, thus receiving
	 * from parent must error with -ETIMEDOUT, and vice versa.
	 */
	bool parent_timedout = !!child_status;
	bool child_timedout = !!parent_status;

	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, pid);

	if (pid == 0) {
		struct kdbus_conn *conn_src;

		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
		ASSERT_EXIT(ret == 0);

		ret = drop_privileges(65534, 65534);
		ASSERT_EXIT(ret == 0);

		conn_src = kdbus_hello(bus, 0, NULL, 0);
		ASSERT_EXIT(conn_src);

		ret = kdbus_add_match_empty(conn_src);
		ASSERT_EXIT(ret == 0);

		/*
		 * child_status is always checked against send
		 * operations, in case it fails always return
		 * EXIT_FAILURE.
		 */
		ret = kdbus_msg_send(conn_src, NULL, cookie,
				     0, 0, 0, conn_db[0]->id);
		ASSERT_EXIT(ret == child_status);

		ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL);

		kdbus_conn_free(conn_src);

		/*
		 * Child kdbus_msg_recv_poll() should timeout since
		 * the parent_status was set to a non EXIT_SUCCESS
		 * value.
		 */
		if (child_timedout)
			_exit(ret == -ETIMEDOUT ? EXIT_SUCCESS : EXIT_FAILURE);

		_exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
	}

	ret = kdbus_msg_recv_poll(conn_db[0], 100, &msg, &offset);
	/*
	 * If parent_timedout is set then this should fail with
	 * -ETIMEDOUT since the child_status was set to a non
	 * EXIT_SUCCESS value. Otherwise, assume
	 * that kdbus_msg_recv_poll() has succeeded.
	 */
	if (parent_timedout) {
		ASSERT_RETURN_VAL(ret == -ETIMEDOUT, TEST_ERR);

		/* timedout no need to continue, we don't have the
		 * child connection ID, so just terminate. */
		goto out;
	} else {
		ASSERT_RETURN_VAL(ret == 0, ret);
	}

	ret = kdbus_msg_send(conn_db[0], NULL, ++cookie,
			     0, 0, 0, msg->src_id);
	/*
	 * parent_status is checked against send operations,
	 * on failures always return TEST_ERR.
	 */
	ASSERT_RETURN_VAL(ret == parent_status, TEST_ERR);

	kdbus_msg_free(msg);
	kdbus_free(conn_db[0], offset);

out:
	ret = waitpid(pid, &status, 0);
	ASSERT_RETURN_VAL(ret >= 0, ret);

	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
}
示例#7
0
int kdbus_msg_send(const struct kdbus_conn *conn,
		   const char *name,
		   uint64_t cookie,
		   uint64_t flags,
		   uint64_t timeout,
		   int64_t priority,
		   uint64_t dst_id)
{
	struct kdbus_msg *msg;
	const char ref1[1024 * 128 + 3] = "0123456789_0";
	const char ref2[] = "0123456789_1";
	struct kdbus_item *item;
	uint64_t size;
	int memfd = -1;
	int ret;

	size = sizeof(struct kdbus_msg);
	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));

	if (dst_id == KDBUS_DST_ID_BROADCAST)
		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64;
	else {
		memfd = sys_memfd_create("my-name-is-nice", 1024 * 1024);
		if (memfd < 0) {
			kdbus_printf("failed to create memfd: %m\n");
			return memfd;
		}

		if (write(memfd, "kdbus memfd 1234567", 19) != 19) {
			ret = -errno;
			kdbus_printf("writing to memfd failed: %m\n");
			return ret;
		}

		ret = sys_memfd_seal_set(memfd);
		if (ret < 0) {
			ret = -errno;
			kdbus_printf("memfd sealing failed: %m\n");
			return ret;
		}

		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
	}

	if (name)
		size += KDBUS_ITEM_SIZE(strlen(name) + 1);

	msg = malloc(size);
	if (!msg) {
		ret = -errno;
		kdbus_printf("unable to malloc()!?\n");
		return ret;
	}

	memset(msg, 0, size);
	msg->flags = flags;
	msg->timeout_ns = timeout;
	msg->priority = priority;
	msg->size = size;
	msg->src_id = conn->id;
	msg->dst_id = name ? 0 : dst_id;
	msg->cookie = cookie;
	msg->payload_type = KDBUS_PAYLOAD_DBUS;

	item = msg->items;

	if (name) {
		item->type = KDBUS_ITEM_DST_NAME;
		item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
		strcpy(item->str, name);
		item = KDBUS_ITEM_NEXT(item);
	}

	item->type = KDBUS_ITEM_PAYLOAD_VEC;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
	item->vec.address = (uintptr_t)&ref1;
	item->vec.size = sizeof(ref1);
	item = KDBUS_ITEM_NEXT(item);

	/* data padding for ref1 */
	item->type = KDBUS_ITEM_PAYLOAD_VEC;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
	item->vec.address = (uintptr_t)NULL;
	item->vec.size =  KDBUS_ALIGN8(sizeof(ref1)) - sizeof(ref1);
	item = KDBUS_ITEM_NEXT(item);

	item->type = KDBUS_ITEM_PAYLOAD_VEC;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
	item->vec.address = (uintptr_t)&ref2;
	item->vec.size = sizeof(ref2);
	item = KDBUS_ITEM_NEXT(item);

	if (dst_id == KDBUS_DST_ID_BROADCAST) {
		item->type = KDBUS_ITEM_BLOOM_FILTER;
		item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64;
		item->bloom_filter.generation = 0;
	} else {
		item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
		item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd);
		item->memfd.size = 16;
		item->memfd.fd = memfd;
	}
	item = KDBUS_ITEM_NEXT(item);

	ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error sending message: %d (%m)\n", ret);
		return ret;
	}

	if (memfd >= 0)
		close(memfd);

	if (flags & KDBUS_MSG_FLAGS_SYNC_REPLY) {
		struct kdbus_msg *reply;

		kdbus_printf("SYNC REPLY @offset %llu:\n", msg->offset_reply);
		reply = (struct kdbus_msg *)(conn->buf + msg->offset_reply);
		kdbus_msg_dump(conn, reply);

		ret = kdbus_free(conn, msg->offset_reply);
		if (ret < 0)
			return ret;
	}

	free(msg);

	return 0;
}
示例#8
0
static int msg_recv_prio(struct kdbus_conn *conn,
			 int64_t requested_prio,
			 int64_t expected_prio)
{
	struct kdbus_cmd_recv recv = {
		.size = sizeof(recv),
		.flags = KDBUS_RECV_USE_PRIORITY,
		.priority = requested_prio,
	};
	struct kdbus_msg *msg;
	int ret;

	ret = ioctl(conn->fd, KDBUS_CMD_RECV, &recv);
	if (ret < 0) {
		kdbus_printf("error receiving message: %d (%m)\n", -errno);
		return -errno;
	}

	msg = (struct kdbus_msg *)(conn->buf + recv.reply.offset);
	kdbus_msg_dump(conn, msg);

	if (msg->priority != expected_prio) {
		kdbus_printf("expected message prio %lld, got %lld\n",
			     (unsigned long long) expected_prio,
			     (unsigned long long) msg->priority);
		return -EINVAL;
	}

	kdbus_msg_free(msg);
	ret = kdbus_free(conn, recv.reply.offset);
	if (ret < 0)
		return ret;

	return 0;
}

int kdbus_test_message_prio(struct kdbus_test_env *env)
{
	struct kdbus_conn *a, *b;
	uint64_t cookie = 0;

	a = kdbus_hello(env->buspath, 0, NULL, 0);
	b = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(a && b);

	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   25, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -600, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   10, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,  -35, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -100, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   20, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,  -15, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -150, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   10, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,  -10, a->id) == 0);

	ASSERT_RETURN(msg_recv_prio(a, -200, -800) == 0);
	ASSERT_RETURN(msg_recv_prio(a, -100, -800) == 0);
	ASSERT_RETURN(msg_recv_prio(a, -400, -600) == 0);
	ASSERT_RETURN(msg_recv_prio(a, -400, -600) == -ENOMSG);
	ASSERT_RETURN(msg_recv_prio(a, 10, -150) == 0);
	ASSERT_RETURN(msg_recv_prio(a, 10, -100) == 0);

	kdbus_printf("--- get priority (all)\n");
	ASSERT_RETURN(kdbus_msg_recv(a, NULL, NULL) == 0);

	kdbus_conn_free(a);
	kdbus_conn_free(b);

	return TEST_OK;
}

static int kdbus_test_notify_kernel_quota(struct kdbus_test_env *env)
{
	int ret;
	unsigned int i;
	uint64_t offset;
	struct kdbus_conn *conn;
	struct kdbus_conn *reader;
	struct kdbus_msg *msg = NULL;

	reader = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(reader);

	conn = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn);

	/* Register for ID signals */
	ret = kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD,
				 KDBUS_MATCH_ID_ANY);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE,
				 KDBUS_MATCH_ID_ANY);
	ASSERT_RETURN(ret == 0);

	/* Each iteration two notifications: add and remove ID */
	for (i = 0; i < KDBUS_CONN_MAX_MSGS / 2; i++) {
		struct kdbus_conn *notifier;

		notifier = kdbus_hello(env->buspath, 0, NULL, 0);
		ASSERT_RETURN(notifier);

		kdbus_conn_free(notifier);

	}

	/*
	 * Now the reader queue is full, message will be lost
	 * but it will not be accounted in dropped msgs
	 */
	ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, 0, reader->id);
	ASSERT_RETURN(ret == -ENOBUFS);

	/* More ID kernel notifications that will be lost */
	kdbus_conn_free(conn);

	conn = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn);

	kdbus_conn_free(conn);

	ret = kdbus_msg_recv(reader, &msg, &offset);
	ASSERT_RETURN(ret == -EOVERFLOW);

	/*
	 * We lost only 3 packet since only broadcast mesg
	 * are accounted. The connection ID add/remove notification
	 */
	ASSERT_RETURN(offset == 3);

	kdbus_msg_free(msg);

	/* Read our queue */
	for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) {
		ret = kdbus_msg_recv_poll(reader, 100, &msg, NULL);
		ASSERT_RETURN(ret == 0);

		kdbus_msg_free(msg);
	}

	ret = kdbus_msg_recv(reader, NULL, NULL);
	ASSERT_RETURN(ret == -EAGAIN);

	kdbus_conn_free(reader);

	return 0;
}