public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Mike Pagano" <mpagano@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/linux-patches:4.2 commit in: /
Date: Wed, 19 Aug 2015 14:58:14 +0000 (UTC)	[thread overview]
Message-ID: <1439996286.1e94ed6b2554ee5b2a7770481aa5d64ad6a2332b.mpagano@gentoo> (raw)

commit:     1e94ed6b2554ee5b2a7770481aa5d64ad6a2332b
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Wed Aug 19 14:58:06 2015 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Wed Aug 19 14:58:06 2015 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=1e94ed6b

Patch to enable link security restrictions by default. Patch to disable Windows 8 compatibility for some Lenovo ThinkPads.  Patch to ensure that /dev/root doesn't appear in /proc/mounts when bootint without an initramfs.  Path to not not lock when UMH is waiting on current thread spawned by linuxrc. (bug #481344) fbcondecor bootsplash patch. Kernel patch that enables gcc < v4.9 optimizations for additional CPUs. Add patch to support namespace user.pax.* on tmpfs, bug #470644.

 0000_README                                        |    36 +
 1500_XATTR_USER_PREFIX.patch                       |    54 +
 ...ble-link-security-restrictions-by-default.patch |    22 +
 2700_ThinkPad-30-brightness-control-fix.patch      |    67 +
 2900_dev-root-proc-mount-fix.patch                 |    38 +
 2905_2disk-resume-image-fix.patch                  |    24 +
 4200_fbcondecor-3.19.patch                         |  2119 ++
 4567_distro-Gentoo-Kconfig.patch                   |    39 +-
 ...able-additional-cpu-optimizations-for-gcc.patch |   327 +
 ...-additional-cpu-optimizations-for-gcc-4.9.patch |   402 +
 5015_kdbus-8-12-2015.patch                         | 34349 +++++++++++++++++++
 11 files changed, 37446 insertions(+), 31 deletions(-)

diff --git a/0000_README b/0000_README
index 9018993..9022e99 100644
--- a/0000_README
+++ b/0000_README
@@ -43,6 +43,42 @@ EXPERIMENTAL
 Individual Patch Descriptions:
 --------------------------------------------------------------------------
 
+Patch:  1500_XATTR_USER_PREFIX.patch
+From:   https://bugs.gentoo.org/show_bug.cgi?id=470644
+Desc:   Support for namespace user.pax.* on tmpfs.
+
+Patch:  1510_fs-enable-link-security-restrictions-by-default.patch
+From:   http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/
+Desc:   Enable link security restrictions by default.
+
+Patch:  2700_ThinkPad-30-brightness-control-fix.patch
+From:   Seth Forshee <seth.forshee@canonical.com>
+Desc:   ACPI: Disable Windows 8 compatibility for some Lenovo ThinkPads.
+
+Patch:  2900_dev-root-proc-mount-fix.patch
+From:   https://bugs.gentoo.org/show_bug.cgi?id=438380
+Desc:   Ensure that /dev/root doesn't appear in /proc/mounts when bootint without an initramfs.
+
+Patch:  2905_s2disk-resume-image-fix.patch
+From:   Al Viro <viro <at> ZenIV.linux.org.uk>
+Desc:   Do not lock when UMH is waiting on current thread spawned by linuxrc. (bug #481344)
+
+Patch:  4200_fbcondecor-3.19.patch
+From:   http://www.mepiscommunity.org/fbcondecor
+Desc:   Bootsplash ported by Marco. (Bug #539616)
+
 Patch:  4567_distro-Gentoo-Kconfig.patch
 From:   Tom Wijsman <TomWij@gentoo.org>
 Desc:   Add Gentoo Linux support config settings and defaults.
+
+Patch:  5000_enable-additional-cpu-optimizations-for-gcc.patch
+From:   https://github.com/graysky2/kernel_gcc_patch/
+Desc:   Kernel patch enables gcc < v4.9 optimizations for additional CPUs.
+
+Patch:  5010_enable-additional-cpu-optimizations-for-gcc-4.9.patch
+From:   https://github.com/graysky2/kernel_gcc_patch/
+Desc:   Kernel patch enables gcc >= v4.9 optimizations for additional CPUs.
+
+Patch:  5015_kdbus-8-12-2015.patch
+From:   https://lkml.org
+Desc:   Kernel-level IPC implementation

diff --git a/1500_XATTR_USER_PREFIX.patch b/1500_XATTR_USER_PREFIX.patch
new file mode 100644
index 0000000..cc15cd5
--- /dev/null
+++ b/1500_XATTR_USER_PREFIX.patch
@@ -0,0 +1,54 @@
+From: Anthony G. Basile <blueness@gentoo.org>
+
+This patch adds support for a restricted user-controlled namespace on
+tmpfs filesystem used to house PaX flags.  The namespace must be of the
+form user.pax.* and its value cannot exceed a size of 8 bytes.
+
+This is needed even on all Gentoo systems so that XATTR_PAX flags
+are preserved for users who might build packages using portage on
+a tmpfs system with a non-hardened kernel and then switch to a
+hardened kernel with XATTR_PAX enabled.
+
+The namespace is added to any user with Extended Attribute support
+enabled for tmpfs.  Users who do not enable xattrs will not have
+the XATTR_PAX flags preserved.
+
+diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
+index e4629b9..6958086 100644
+--- a/include/uapi/linux/xattr.h
++++ b/include/uapi/linux/xattr.h
+@@ -63,5 +63,9 @@
+ #define XATTR_POSIX_ACL_DEFAULT  "posix_acl_default"
+ #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
+ 
++/* User namespace */
++#define XATTR_PAX_PREFIX XATTR_USER_PREFIX "pax."
++#define XATTR_PAX_FLAGS_SUFFIX "flags"
++#define XATTR_NAME_PAX_FLAGS XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX
+ 
+ #endif /* _UAPI_LINUX_XATTR_H */
+diff --git a/mm/shmem.c b/mm/shmem.c
+index 1c44af7..f23bb1b 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -2201,6 +2201,7 @@ static const struct xattr_handler *shmem_xattr_handlers[] = {
+ static int shmem_xattr_validate(const char *name)
+ {
+ 	struct { const char *prefix; size_t len; } arr[] = {
++		{ XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN},
+ 		{ XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
+ 		{ XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
+ 	};
+@@ -2256,6 +2257,12 @@ static int shmem_setxattr(struct dentry *dentry, const char *name,
+ 	if (err)
+ 		return err;
+ 
++	if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
++		if (strcmp(name, XATTR_NAME_PAX_FLAGS))
++			return -EOPNOTSUPP;
++		if (size > 8)
++			return -EINVAL;
++	}
+ 	return simple_xattr_set(&info->xattrs, name, value, size, flags);
+ }
+ 

diff --git a/1510_fs-enable-link-security-restrictions-by-default.patch b/1510_fs-enable-link-security-restrictions-by-default.patch
new file mode 100644
index 0000000..639fb3c
--- /dev/null
+++ b/1510_fs-enable-link-security-restrictions-by-default.patch
@@ -0,0 +1,22 @@
+From: Ben Hutchings <ben@decadent.org.uk>
+Subject: fs: Enable link security restrictions by default
+Date: Fri, 02 Nov 2012 05:32:06 +0000
+Bug-Debian: https://bugs.debian.org/609455
+Forwarded: not-needed
+
+This reverts commit 561ec64ae67ef25cac8d72bb9c4bfc955edfd415
+('VFS: don't do protected {sym,hard}links by default').
+
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -651,8 +651,8 @@ static inline void put_link(struct namei
+ 	path_put(link);
+ }
+ 
+-int sysctl_protected_symlinks __read_mostly = 0;
+-int sysctl_protected_hardlinks __read_mostly = 0;
++int sysctl_protected_symlinks __read_mostly = 1;
++int sysctl_protected_hardlinks __read_mostly = 1;
+ 
+ /**
+  * may_follow_link - Check symlink following for unsafe situations

diff --git a/2700_ThinkPad-30-brightness-control-fix.patch b/2700_ThinkPad-30-brightness-control-fix.patch
new file mode 100644
index 0000000..b548c6d
--- /dev/null
+++ b/2700_ThinkPad-30-brightness-control-fix.patch
@@ -0,0 +1,67 @@
+diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
+index cb96296..6c242ed 100644
+--- a/drivers/acpi/blacklist.c
++++ b/drivers/acpi/blacklist.c
+@@ -269,6 +276,61 @@  static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
+ 	},
+ 
+ 	/*
++	 * The following Lenovo models have a broken workaround in the
++	 * acpi_video backlight implementation to meet the Windows 8
++	 * requirement of 101 backlight levels. Reverting to pre-Win8
++	 * behavior fixes the problem.
++	 */
++	{
++	.callback = dmi_disable_osi_win8,
++	.ident = "Lenovo ThinkPad L430",
++	.matches = {
++		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L430"),
++		},
++	},
++	{
++	.callback = dmi_disable_osi_win8,
++	.ident = "Lenovo ThinkPad T430s",
++	.matches = {
++		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"),
++		},
++	},
++	{
++	.callback = dmi_disable_osi_win8,
++	.ident = "Lenovo ThinkPad T530",
++	.matches = {
++		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T530"),
++		},
++	},
++	{
++	.callback = dmi_disable_osi_win8,
++	.ident = "Lenovo ThinkPad W530",
++	.matches = {
++		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"),
++		},
++	},
++	{
++	.callback = dmi_disable_osi_win8,
++	.ident = "Lenovo ThinkPad X1 Carbon",
++	.matches = {
++		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"),
++		},
++	},
++	{
++	.callback = dmi_disable_osi_win8,
++	.ident = "Lenovo ThinkPad X230",
++	.matches = {
++		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"),
++		},
++	},
++
++	/*
+ 	 * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
+ 	 * Linux ignores it, except for the machines enumerated below.
+ 	 */
+

diff --git a/2900_dev-root-proc-mount-fix.patch b/2900_dev-root-proc-mount-fix.patch
new file mode 100644
index 0000000..60af1eb
--- /dev/null
+++ b/2900_dev-root-proc-mount-fix.patch
@@ -0,0 +1,38 @@
+--- a/init/do_mounts.c	2015-08-19 10:27:16.753852576 -0400
++++ b/init/do_mounts.c	2015-08-19 10:34:25.473850353 -0400
+@@ -490,7 +490,11 @@ void __init change_floppy(char *fmt, ...
+ 	va_start(args, fmt);
+ 	vsprintf(buf, fmt, args);
+ 	va_end(args);
+-	fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0);
++	if (saved_root_name[0])
++		fd = sys_open(saved_root_name, O_RDWR | O_NDELAY, 0);
++	else
++		fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0);
++
+ 	if (fd >= 0) {
+ 		sys_ioctl(fd, FDEJECT, 0);
+ 		sys_close(fd);
+@@ -534,11 +538,17 @@ void __init mount_root(void)
+ #endif
+ #ifdef CONFIG_BLOCK
+ 	{
+-		int err = create_dev("/dev/root", ROOT_DEV);
+-
+-		if (err < 0)
+-			pr_emerg("Failed to create /dev/root: %d\n", err);
+-		mount_block_root("/dev/root", root_mountflags);
++		if (saved_root_name[0] == '/') {
++	       	int err = create_dev(saved_root_name, ROOT_DEV);
++			if (err < 0)
++				pr_emerg("Failed to create %s: %d\n", saved_root_name, err);
++			mount_block_root(saved_root_name, root_mountflags);
++		} else {
++			int err = create_dev("/dev/root", ROOT_DEV);
++			if (err < 0)
++				pr_emerg("Failed to create /dev/root: %d\n", err);
++			mount_block_root("/dev/root", root_mountflags);
++		}
+ 	}
+ #endif
+ }

diff --git a/2905_2disk-resume-image-fix.patch b/2905_2disk-resume-image-fix.patch
new file mode 100644
index 0000000..7e95d29
--- /dev/null
+++ b/2905_2disk-resume-image-fix.patch
@@ -0,0 +1,24 @@
+diff --git a/kernel/kmod.c b/kernel/kmod.c
+index fb32636..d968882 100644
+--- a/kernel/kmod.c
++++ b/kernel/kmod.c
+@@ -575,7 +575,8 @@
+ 		call_usermodehelper_freeinfo(sub_info);
+ 		return -EINVAL;
+ 	}
+-	helper_lock();
++	if (!(current->flags & PF_FREEZER_SKIP))
++		helper_lock();
+ 	if (!khelper_wq || usermodehelper_disabled) {
+ 		retval = -EBUSY;
+ 		goto out;
+@@ -611,7 +612,8 @@ wait_done:
+ out:
+ 	call_usermodehelper_freeinfo(sub_info);
+ unlock:
+-	helper_unlock();
++	if (!(current->flags & PF_FREEZER_SKIP))
++		helper_unlock();
+ 	return retval;
+ }
+ EXPORT_SYMBOL(call_usermodehelper_exec);

diff --git a/4200_fbcondecor-3.19.patch b/4200_fbcondecor-3.19.patch
new file mode 100644
index 0000000..29c379f
--- /dev/null
+++ b/4200_fbcondecor-3.19.patch
@@ -0,0 +1,2119 @@
+diff --git a/Documentation/fb/00-INDEX b/Documentation/fb/00-INDEX
+index fe85e7c..2230930 100644
+--- a/Documentation/fb/00-INDEX
++++ b/Documentation/fb/00-INDEX
+@@ -23,6 +23,8 @@ ep93xx-fb.txt
+ 	- info on the driver for EP93xx LCD controller.
+ fbcon.txt
+ 	- intro to and usage guide for the framebuffer console (fbcon).
++fbcondecor.txt
++	- info on the Framebuffer Console Decoration
+ framebuffer.txt
+ 	- introduction to frame buffer devices.
+ gxfb.txt
+diff --git a/Documentation/fb/fbcondecor.txt b/Documentation/fb/fbcondecor.txt
+new file mode 100644
+index 0000000..3388c61
+--- /dev/null
++++ b/Documentation/fb/fbcondecor.txt
+@@ -0,0 +1,207 @@
++What is it?
++-----------
++
++The framebuffer decorations are a kernel feature which allows displaying a 
++background picture on selected consoles.
++
++What do I need to get it to work?
++---------------------------------
++
++To get fbcondecor up-and-running you will have to:
++ 1) get a copy of splashutils [1] or a similar program
++ 2) get some fbcondecor themes
++ 3) build the kernel helper program
++ 4) build your kernel with the FB_CON_DECOR option enabled.
++
++To get fbcondecor operational right after fbcon initialization is finished, you
++will have to include a theme and the kernel helper into your initramfs image.
++Please refer to splashutils documentation for instructions on how to do that.
++
++[1] The splashutils package can be downloaded from:
++    http://github.com/alanhaggai/fbsplash
++
++The userspace helper
++--------------------
++
++The userspace fbcondecor helper (by default: /sbin/fbcondecor_helper) is called by the
++kernel whenever an important event occurs and the kernel needs some kind of
++job to be carried out. Important events include console switches and video
++mode switches (the kernel requests background images and configuration
++parameters for the current console). The fbcondecor helper must be accessible at
++all times. If it's not, fbcondecor will be switched off automatically.
++
++It's possible to set path to the fbcondecor helper by writing it to
++/proc/sys/kernel/fbcondecor.
++
++*****************************************************************************
++
++The information below is mostly technical stuff. There's probably no need to
++read it unless you plan to develop a userspace helper.
++
++The fbcondecor protocol
++-----------------------
++
++The fbcondecor protocol defines a communication interface between the kernel and
++the userspace fbcondecor helper.
++
++The kernel side is responsible for:
++
++ * rendering console text, using an image as a background (instead of a
++   standard solid color fbcon uses),
++ * accepting commands from the user via ioctls on the fbcondecor device,
++ * calling the userspace helper to set things up as soon as the fb subsystem 
++   is initialized.
++
++The userspace helper is responsible for everything else, including parsing
++configuration files, decompressing the image files whenever the kernel needs
++it, and communicating with the kernel if necessary.
++
++The fbcondecor protocol specifies how communication is done in both ways:
++kernel->userspace and userspace->helper.
++  
++Kernel -> Userspace
++-------------------
++
++The kernel communicates with the userspace helper by calling it and specifying
++the task to be done in a series of arguments.
++
++The arguments follow the pattern:
++<fbcondecor protocol version> <command> <parameters>
++
++All commands defined in fbcondecor protocol v2 have the following parameters:
++ virtual console
++ framebuffer number
++ theme
++
++Fbcondecor protocol v1 specified an additional 'fbcondecor mode' after the
++framebuffer number. Fbcondecor protocol v1 is deprecated and should not be used.
++
++Fbcondecor protocol v2 specifies the following commands:
++
++getpic
++------
++ The kernel issues this command to request image data. It's up to the 
++ userspace  helper to find a background image appropriate for the specified 
++ theme and the current resolution. The userspace helper should respond by 
++ issuing the FBIOCONDECOR_SETPIC ioctl.
++
++init
++----
++ The kernel issues this command after the fbcondecor device is created and
++ the fbcondecor interface is initialized. Upon receiving 'init', the userspace
++ helper should parse the kernel command line (/proc/cmdline) or otherwise
++ decide whether fbcondecor is to be activated.
++
++ To activate fbcondecor on the first console the helper should issue the
++ FBIOCONDECOR_SETCFG, FBIOCONDECOR_SETPIC and FBIOCONDECOR_SETSTATE commands,
++ in the above-mentioned order.
++
++ When the userspace helper is called in an early phase of the boot process
++ (right after the initialization of fbcon), no filesystems will be mounted.
++ The helper program should mount sysfs and then create the appropriate
++ framebuffer, fbcondecor and tty0 devices (if they don't already exist) to get
++ current display settings and to be able to communicate with the kernel side.
++ It should probably also mount the procfs to be able to parse the kernel
++ command line parameters.
++
++ Note that the console sem is not held when the kernel calls fbcondecor_helper
++ with the 'init' command. The fbcondecor helper should perform all ioctls with
++ origin set to FBCON_DECOR_IO_ORIG_USER.
++
++modechange
++----------
++ The kernel issues this command on a mode change. The helper's response should
++ be similar to the response to the 'init' command. Note that this time the
++ console sem is held and all ioctls must be performed with origin set to
++ FBCON_DECOR_IO_ORIG_KERNEL.
++
++
++Userspace -> Kernel
++-------------------
++
++Userspace programs can communicate with fbcondecor via ioctls on the
++fbcondecor device. These ioctls are to be used by both the userspace helper
++(called only by the kernel) and userspace configuration tools (run by the users).
++
++The fbcondecor helper should set the origin field to FBCON_DECOR_IO_ORIG_KERNEL
++when doing the appropriate ioctls. All userspace configuration tools should
++use FBCON_DECOR_IO_ORIG_USER. Failure to set the appropriate value in the origin
++field when performing ioctls from the kernel helper will most likely result
++in a console deadlock.
++
++FBCON_DECOR_IO_ORIG_KERNEL instructs fbcondecor not to try to acquire the console
++semaphore. Not surprisingly, FBCON_DECOR_IO_ORIG_USER instructs it to acquire
++the console sem.
++
++The framebuffer console decoration provides the following ioctls (all defined in 
++linux/fb.h):
++
++FBIOCONDECOR_SETPIC
++description: loads a background picture for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: struct fb_image*
++notes: 
++If called for consoles other than the current foreground one, the picture data
++will be ignored.
++
++If the current virtual console is running in a 8-bpp mode, the cmap substruct
++of fb_image has to be filled appropriately: start should be set to 16 (first
++16 colors are reserved for fbcon), len to a value <= 240 and red, green and
++blue should point to valid cmap data. The transp field is ingored. The fields
++dx, dy, bg_color, fg_color in fb_image are ignored as well.
++
++FBIOCONDECOR_SETCFG
++description: sets the fbcondecor config for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: struct vc_decor*
++notes: The structure has to be filled with valid data.
++
++FBIOCONDECOR_GETCFG
++description: gets the fbcondecor config for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: struct vc_decor*
++
++FBIOCONDECOR_SETSTATE
++description: sets the fbcondecor state for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: unsigned int*
++          values: 0 = disabled, 1 = enabled.
++
++FBIOCONDECOR_GETSTATE
++description: gets the fbcondecor state for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: unsigned int*
++          values: as in FBIOCONDECOR_SETSTATE
++
++Info on used structures:
++
++Definition of struct vc_decor can be found in linux/console_decor.h. It's
++heavily commented. Note that the 'theme' field should point to a string
++no longer than FBCON_DECOR_THEME_LEN. When FBIOCONDECOR_GETCFG call is
++performed, the theme field should point to a char buffer of length
++FBCON_DECOR_THEME_LEN.
++
++Definition of struct fbcon_decor_iowrapper can be found in linux/fb.h.
++The fields in this struct have the following meaning:
++
++vc: 
++Virtual console number.
++
++origin: 
++Specifies if the ioctl is performed as a response to a kernel request. The
++fbcondecor helper should set this field to FBCON_DECOR_IO_ORIG_KERNEL, userspace
++programs should set it to FBCON_DECOR_IO_ORIG_USER. This field is necessary to
++avoid console semaphore deadlocks.
++
++data: 
++Pointer to a data structure appropriate for the performed ioctl. Type of
++the data struct is specified in the ioctls description.
++
++*****************************************************************************
++
++Credit
++------
++
++Original 'bootsplash' project & implementation by:
++  Volker Poplawski <volker@poplawski.de>, Stefan Reinauer <stepan@suse.de>,
++  Steffen Winterfeldt <snwint@suse.de>, Michael Schroeder <mls@suse.de>,
++  Ken Wimer <wimer@suse.de>.
++
++Fbcondecor, fbcondecor protocol design, current implementation & docs by:
++  Michal Januszewski <michalj+fbcondecor@gmail.com>
++
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 7183b6a..d576148 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -17,6 +17,10 @@ obj-y				+= pwm/
+ obj-$(CONFIG_PCI)		+= pci/
+ obj-$(CONFIG_PARISC)		+= parisc/
+ obj-$(CONFIG_RAPIDIO)		+= rapidio/
++# tty/ comes before char/ so that the VT console is the boot-time
++# default.
++obj-y				+= tty/
++obj-y				+= char/
+ obj-y				+= video/
+ obj-y				+= idle/
+ 
+@@ -42,11 +46,6 @@ obj-$(CONFIG_REGULATOR)		+= regulator/
+ # reset controllers early, since gpu drivers might rely on them to initialize
+ obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
+ 
+-# tty/ comes before char/ so that the VT console is the boot-time
+-# default.
+-obj-y				+= tty/
+-obj-y				+= char/
+-
+ # iommu/ comes before gpu as gpu are using iommu controllers
+ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
+
+diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
+index fe1cd01..6d2e87a 100644
+--- a/drivers/video/console/Kconfig
++++ b/drivers/video/console/Kconfig
+@@ -126,6 +126,19 @@ config FRAMEBUFFER_CONSOLE_ROTATION
+          such that other users of the framebuffer will remain normally
+          oriented.
+ 
++config FB_CON_DECOR
++	bool "Support for the Framebuffer Console Decorations"
++	depends on FRAMEBUFFER_CONSOLE=y && !FB_TILEBLITTING
++	default n
++	---help---
++	  This option enables support for framebuffer console decorations which
++	  makes it possible to display images in the background of the system
++	  consoles.  Note that userspace utilities are necessary in order to take 
++	  advantage of these features. Refer to Documentation/fb/fbcondecor.txt 
++	  for more information.
++
++	  If unsure, say N.
++
+ config STI_CONSOLE
+         bool "STI text console"
+         depends on PARISC
+diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
+index 43bfa48..cc104b6f 100644
+--- a/drivers/video/console/Makefile
++++ b/drivers/video/console/Makefile
+@@ -16,4 +16,5 @@ obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
+                                          fbcon_ccw.o
+ endif
+ 
++obj-$(CONFIG_FB_CON_DECOR)     	  += fbcondecor.o cfbcondecor.o
+ obj-$(CONFIG_FB_STI)              += sticore.o
+diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
+index 61b182b..984384b 100644
+--- a/drivers/video/console/bitblit.c
++++ b/drivers/video/console/bitblit.c
+@@ -18,6 +18,7 @@
+ #include <linux/console.h>
+ #include <asm/types.h>
+ #include "fbcon.h"
++#include "fbcondecor.h"
+ 
+ /*
+  * Accelerated handlers.
+@@ -55,6 +56,13 @@ static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ 	area.height = height * vc->vc_font.height;
+ 	area.width = width * vc->vc_font.width;
+ 
++	if (fbcon_decor_active(info, vc)) {
++ 		area.sx += vc->vc_decor.tx;
++ 		area.sy += vc->vc_decor.ty;
++ 		area.dx += vc->vc_decor.tx;
++ 		area.dy += vc->vc_decor.ty;
++ 	}
++
+ 	info->fbops->fb_copyarea(info, &area);
+ }
+ 
+@@ -380,11 +388,15 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 	cursor.image.depth = 1;
+ 	cursor.rop = ROP_XOR;
+ 
+-	if (info->fbops->fb_cursor)
+-		err = info->fbops->fb_cursor(info, &cursor);
++	if (fbcon_decor_active(info, vc)) {
++		fbcon_decor_cursor(info, &cursor);
++	} else {
++		if (info->fbops->fb_cursor)
++			err = info->fbops->fb_cursor(info, &cursor);
+ 
+-	if (err)
+-		soft_cursor(info, &cursor);
++		if (err)
++			soft_cursor(info, &cursor);
++	}
+ 
+ 	ops->cursor_reset = 0;
+ }
+diff --git a/drivers/video/console/cfbcondecor.c b/drivers/video/console/cfbcondecor.c
+new file mode 100644
+index 0000000..a2b4497
+--- /dev/null
++++ b/drivers/video/console/cfbcondecor.c
+@@ -0,0 +1,471 @@
++/*
++ *  linux/drivers/video/cfbcon_decor.c -- Framebuffer decor render functions
++ *
++ *  Copyright (C) 2004 Michal Januszewski <michalj+fbcondecor@gmail.com>
++ *
++ *  Code based upon "Bootdecor" (C) 2001-2003
++ *       Volker Poplawski <volker@poplawski.de>,
++ *       Stefan Reinauer <stepan@suse.de>,
++ *       Steffen Winterfeldt <snwint@suse.de>,
++ *       Michael Schroeder <mls@suse.de>,
++ *       Ken Wimer <wimer@suse.de>.
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/selection.h>
++#include <linux/slab.h>
++#include <linux/vt_kern.h>
++#include <asm/irq.h>
++
++#include "fbcon.h"
++#include "fbcondecor.h"
++
++#define parse_pixel(shift,bpp,type)						\
++	do {									\
++		if (d & (0x80 >> (shift)))					\
++			dd2[(shift)] = fgx;					\
++		else								\
++			dd2[(shift)] = transparent ? *(type *)decor_src : bgx;	\
++		decor_src += (bpp);						\
++	} while (0)								\
++
++extern int get_color(struct vc_data *vc, struct fb_info *info,
++		     u16 c, int is_fg);
++
++void fbcon_decor_fix_pseudo_pal(struct fb_info *info, struct vc_data *vc)
++{
++	int i, j, k;
++	int minlen = min(min(info->var.red.length, info->var.green.length),
++			     info->var.blue.length);
++	u32 col;
++
++	for (j = i = 0; i < 16; i++) {
++		k = color_table[i];
++
++		col = ((vc->vc_palette[j++]  >> (8-minlen))
++			<< info->var.red.offset);
++		col |= ((vc->vc_palette[j++] >> (8-minlen))
++			<< info->var.green.offset);
++		col |= ((vc->vc_palette[j++] >> (8-minlen))
++			<< info->var.blue.offset);
++			((u32 *)info->pseudo_palette)[k] = col;
++	}
++}
++
++void fbcon_decor_renderc(struct fb_info *info, int ypos, int xpos, int height,
++		      int width, u8* src, u32 fgx, u32 bgx, u8 transparent)
++{
++	unsigned int x, y;
++	u32 dd;
++	int bytespp = ((info->var.bits_per_pixel + 7) >> 3);
++	unsigned int d = ypos * info->fix.line_length + xpos * bytespp;
++	unsigned int ds = (ypos * info->var.xres + xpos) * bytespp;
++	u16 dd2[4];
++
++	u8* decor_src = (u8 *)(info->bgdecor.data + ds);
++	u8* dst = (u8 *)(info->screen_base + d);
++
++	if ((ypos + height) > info->var.yres || (xpos + width) > info->var.xres)
++		return;
++
++	for (y = 0; y < height; y++) {
++		switch (info->var.bits_per_pixel) {
++
++		case 32:
++			for (x = 0; x < width; x++) {
++
++				if ((x & 7) == 0)
++					d = *src++;
++				if (d & 0x80)
++					dd = fgx;
++				else
++					dd = transparent ?
++					     *(u32 *)decor_src : bgx;
++
++				d <<= 1;
++				decor_src += 4;
++				fb_writel(dd, dst);
++				dst += 4;
++			}
++			break;
++		case 24:
++			for (x = 0; x < width; x++) {
++
++				if ((x & 7) == 0)
++					d = *src++;
++				if (d & 0x80)
++					dd = fgx;
++				else
++					dd = transparent ?
++					     (*(u32 *)decor_src & 0xffffff) : bgx;
++
++				d <<= 1;
++				decor_src += 3;
++#ifdef __LITTLE_ENDIAN
++				fb_writew(dd & 0xffff, dst);
++				dst += 2;
++				fb_writeb((dd >> 16), dst);
++#else
++				fb_writew(dd >> 8, dst);
++				dst += 2;
++				fb_writeb(dd & 0xff, dst);
++#endif
++				dst++;
++			}
++			break;
++		case 16:
++			for (x = 0; x < width; x += 2) {
++				if ((x & 7) == 0)
++					d = *src++;
++
++				parse_pixel(0, 2, u16);
++				parse_pixel(1, 2, u16);
++#ifdef __LITTLE_ENDIAN
++				dd = dd2[0] | (dd2[1] << 16);
++#else
++				dd = dd2[1] | (dd2[0] << 16);
++#endif
++				d <<= 2;
++				fb_writel(dd, dst);
++				dst += 4;
++			}
++			break;
++
++		case 8:
++			for (x = 0; x < width; x += 4) {
++				if ((x & 7) == 0)
++					d = *src++;
++
++				parse_pixel(0, 1, u8);
++				parse_pixel(1, 1, u8);
++				parse_pixel(2, 1, u8);
++				parse_pixel(3, 1, u8);
++
++#ifdef __LITTLE_ENDIAN
++				dd = dd2[0] | (dd2[1] << 8) | (dd2[2] << 16) | (dd2[3] << 24);
++#else
++				dd = dd2[3] | (dd2[2] << 8) | (dd2[1] << 16) | (dd2[0] << 24);
++#endif
++				d <<= 4;
++				fb_writel(dd, dst);
++				dst += 4;
++			}
++		}
++
++		dst += info->fix.line_length - width * bytespp;
++		decor_src += (info->var.xres - width) * bytespp;
++	}
++}
++
++#define cc2cx(a) 						\
++	((info->fix.visual == FB_VISUAL_TRUECOLOR || 		\
++	  info->fix.visual == FB_VISUAL_DIRECTCOLOR) ? 		\
++	 ((u32*)info->pseudo_palette)[a] : a)
++
++void fbcon_decor_putcs(struct vc_data *vc, struct fb_info *info,
++		   const unsigned short *s, int count, int yy, int xx)
++{
++	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
++	struct fbcon_ops *ops = info->fbcon_par;
++	int fg_color, bg_color, transparent;
++	u8 *src;
++	u32 bgx, fgx;
++	u16 c = scr_readw(s);
++
++	fg_color = get_color(vc, info, c, 1);
++        bg_color = get_color(vc, info, c, 0);
++
++	/* Don't paint the background image if console is blanked */
++	transparent = ops->blank_state ? 0 :
++		(vc->vc_decor.bg_color == bg_color);
++
++	xx = xx * vc->vc_font.width + vc->vc_decor.tx;
++	yy = yy * vc->vc_font.height + vc->vc_decor.ty;
++
++	fgx = cc2cx(fg_color);
++	bgx = cc2cx(bg_color);
++
++	while (count--) {
++		c = scr_readw(s++);
++		src = vc->vc_font.data + (c & charmask) * vc->vc_font.height *
++		      ((vc->vc_font.width + 7) >> 3);
++
++		fbcon_decor_renderc(info, yy, xx, vc->vc_font.height,
++			       vc->vc_font.width, src, fgx, bgx, transparent);
++		xx += vc->vc_font.width;
++	}
++}
++
++void fbcon_decor_cursor(struct fb_info *info, struct fb_cursor *cursor)
++{
++	int i;
++	unsigned int dsize, s_pitch;
++	struct fbcon_ops *ops = info->fbcon_par;
++	struct vc_data* vc;
++	u8 *src;
++
++	/* we really don't need any cursors while the console is blanked */
++	if (info->state != FBINFO_STATE_RUNNING || ops->blank_state)
++		return;
++
++	vc = vc_cons[ops->currcon].d;
++
++	src = kmalloc(64 + sizeof(struct fb_image), GFP_ATOMIC);
++	if (!src)
++		return;
++
++	s_pitch = (cursor->image.width + 7) >> 3;
++	dsize = s_pitch * cursor->image.height;
++	if (cursor->enable) {
++		switch (cursor->rop) {
++		case ROP_XOR:
++			for (i = 0; i < dsize; i++)
++				src[i] = cursor->image.data[i] ^ cursor->mask[i];
++                        break;
++		case ROP_COPY:
++		default:
++			for (i = 0; i < dsize; i++)
++				src[i] = cursor->image.data[i] & cursor->mask[i];
++			break;
++		}
++	} else
++		memcpy(src, cursor->image.data, dsize);
++
++	fbcon_decor_renderc(info,
++			cursor->image.dy + vc->vc_decor.ty,
++			cursor->image.dx + vc->vc_decor.tx,
++			cursor->image.height,
++			cursor->image.width,
++			(u8*)src,
++			cc2cx(cursor->image.fg_color),
++			cc2cx(cursor->image.bg_color),
++			cursor->image.bg_color == vc->vc_decor.bg_color);
++
++	kfree(src);
++}
++
++static void decorset(u8 *dst, int height, int width, int dstbytes,
++		        u32 bgx, int bpp)
++{
++	int i;
++
++	if (bpp == 8)
++		bgx |= bgx << 8;
++	if (bpp == 16 || bpp == 8)
++		bgx |= bgx << 16;
++
++	while (height-- > 0) {
++		u8 *p = dst;
++
++		switch (bpp) {
++
++		case 32:
++			for (i=0; i < width; i++) {
++				fb_writel(bgx, p); p += 4;
++			}
++			break;
++		case 24:
++			for (i=0; i < width; i++) {
++#ifdef __LITTLE_ENDIAN
++				fb_writew((bgx & 0xffff),(u16*)p); p += 2;
++				fb_writeb((bgx >> 16),p++);
++#else
++				fb_writew((bgx >> 8),(u16*)p); p += 2;
++				fb_writeb((bgx & 0xff),p++);
++#endif
++			}
++		case 16:
++			for (i=0; i < width/4; i++) {
++				fb_writel(bgx,p); p += 4;
++				fb_writel(bgx,p); p += 4;
++			}
++			if (width & 2) {
++				fb_writel(bgx,p); p += 4;
++			}
++			if (width & 1)
++				fb_writew(bgx,(u16*)p);
++			break;
++		case 8:
++			for (i=0; i < width/4; i++) {
++				fb_writel(bgx,p); p += 4;
++			}
++
++			if (width & 2) {
++				fb_writew(bgx,p); p += 2;
++			}
++			if (width & 1)
++				fb_writeb(bgx,(u8*)p);
++			break;
++
++		}
++		dst += dstbytes;
++	}
++}
++
++void fbcon_decor_copy(u8 *dst, u8 *src, int height, int width, int linebytes,
++		   int srclinebytes, int bpp)
++{
++	int i;
++
++	while (height-- > 0) {
++		u32 *p = (u32 *)dst;
++		u32 *q = (u32 *)src;
++
++		switch (bpp) {
++
++		case 32:
++			for (i=0; i < width; i++)
++				fb_writel(*q++, p++);
++			break;
++		case 24:
++			for (i=0; i < (width*3/4); i++)
++				fb_writel(*q++, p++);
++			if ((width*3) % 4) {
++				if (width & 2) {
++					fb_writeb(*(u8*)q, (u8*)p);
++				} else if (width & 1) {
++					fb_writew(*(u16*)q, (u16*)p);
++					fb_writeb(*(u8*)((u16*)q+1),(u8*)((u16*)p+2));
++				}
++			}
++			break;
++		case 16:
++			for (i=0; i < width/4; i++) {
++				fb_writel(*q++, p++);
++				fb_writel(*q++, p++);
++			}
++			if (width & 2)
++				fb_writel(*q++, p++);
++			if (width & 1)
++				fb_writew(*(u16*)q, (u16*)p);
++			break;
++		case 8:
++			for (i=0; i < width/4; i++)
++				fb_writel(*q++, p++);
++
++			if (width & 2) {
++				fb_writew(*(u16*)q, (u16*)p);
++				q = (u32*) ((u16*)q + 1);
++				p = (u32*) ((u16*)p + 1);
++			}
++			if (width & 1)
++				fb_writeb(*(u8*)q, (u8*)p);
++			break;
++		}
++
++		dst += linebytes;
++		src += srclinebytes;
++	}
++}
++
++static void decorfill(struct fb_info *info, int sy, int sx, int height,
++		       int width)
++{
++	int bytespp = ((info->var.bits_per_pixel + 7) >> 3);
++	int d  = sy * info->fix.line_length + sx * bytespp;
++	int ds = (sy * info->var.xres + sx) * bytespp;
++
++	fbcon_decor_copy((u8 *)(info->screen_base + d), (u8 *)(info->bgdecor.data + ds),
++		    height, width, info->fix.line_length, info->var.xres * bytespp,
++		    info->var.bits_per_pixel);
++}
++
++void fbcon_decor_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx,
++		    int height, int width)
++{
++	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
++	struct fbcon_ops *ops = info->fbcon_par;
++	u8 *dst;
++	int transparent, bg_color = attr_bgcol_ec(bgshift, vc, info);
++
++	transparent = (vc->vc_decor.bg_color == bg_color);
++	sy = sy * vc->vc_font.height + vc->vc_decor.ty;
++	sx = sx * vc->vc_font.width + vc->vc_decor.tx;
++	height *= vc->vc_font.height;
++	width *= vc->vc_font.width;
++
++	/* Don't paint the background image if console is blanked */
++	if (transparent && !ops->blank_state) {
++		decorfill(info, sy, sx, height, width);
++	} else {
++		dst = (u8 *)(info->screen_base + sy * info->fix.line_length +
++			     sx * ((info->var.bits_per_pixel + 7) >> 3));
++		decorset(dst, height, width, info->fix.line_length, cc2cx(bg_color),
++			  info->var.bits_per_pixel);
++	}
++}
++
++void fbcon_decor_clear_margins(struct vc_data *vc, struct fb_info *info,
++			    int bottom_only)
++{
++	unsigned int tw = vc->vc_cols*vc->vc_font.width;
++	unsigned int th = vc->vc_rows*vc->vc_font.height;
++
++	if (!bottom_only) {
++		/* top margin */
++		decorfill(info, 0, 0, vc->vc_decor.ty, info->var.xres);
++		/* left margin */
++		decorfill(info, vc->vc_decor.ty, 0, th, vc->vc_decor.tx);
++		/* right margin */
++		decorfill(info, vc->vc_decor.ty, vc->vc_decor.tx + tw, th, 
++			   info->var.xres - vc->vc_decor.tx - tw);
++	}
++	decorfill(info, vc->vc_decor.ty + th, 0, 
++		   info->var.yres - vc->vc_decor.ty - th, info->var.xres);
++}
++
++void fbcon_decor_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, 
++			   int sx, int dx, int width)
++{
++	u16 *d = (u16 *) (vc->vc_origin + vc->vc_size_row * y + dx * 2);
++	u16 *s = d + (dx - sx);
++	u16 *start = d;
++	u16 *ls = d;
++	u16 *le = d + width;
++	u16 c;
++	int x = dx;
++	u16 attr = 1;
++
++	do {
++		c = scr_readw(d);
++		if (attr != (c & 0xff00)) {
++			attr = c & 0xff00;
++			if (d > start) {
++				fbcon_decor_putcs(vc, info, start, d - start, y, x);
++				x += d - start;
++				start = d;
++			}
++		}
++		if (s >= ls && s < le && c == scr_readw(s)) {
++			if (d > start) {
++				fbcon_decor_putcs(vc, info, start, d - start, y, x);
++				x += d - start + 1;
++				start = d + 1;
++			} else {
++				x++;
++				start++;
++			}
++		}
++		s++;
++		d++;
++	} while (d < le);
++	if (d > start)
++		fbcon_decor_putcs(vc, info, start, d - start, y, x);
++}
++
++void fbcon_decor_blank(struct vc_data *vc, struct fb_info *info, int blank)
++{
++	if (blank) {
++		decorset((u8 *)info->screen_base, info->var.yres, info->var.xres,
++			  info->fix.line_length, 0, info->var.bits_per_pixel);
++	} else {
++		update_screen(vc);
++		fbcon_decor_clear_margins(vc, info, 0);
++	}
++}
++
+diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
+index f447734..da50d61 100644
+--- a/drivers/video/console/fbcon.c
++++ b/drivers/video/console/fbcon.c
+@@ -79,6 +79,7 @@
+ #include <asm/irq.h>
+ 
+ #include "fbcon.h"
++#include "../console/fbcondecor.h"
+ 
+ #ifdef FBCONDEBUG
+ #  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
+@@ -94,7 +95,7 @@ enum {
+ 
+ static struct display fb_display[MAX_NR_CONSOLES];
+ 
+-static signed char con2fb_map[MAX_NR_CONSOLES];
++signed char con2fb_map[MAX_NR_CONSOLES];
+ static signed char con2fb_map_boot[MAX_NR_CONSOLES];
+ 
+ static int logo_lines;
+@@ -286,7 +287,7 @@ static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
+ 		!vt_force_oops_output(vc);
+ }
+ 
+-static int get_color(struct vc_data *vc, struct fb_info *info,
++int get_color(struct vc_data *vc, struct fb_info *info,
+ 	      u16 c, int is_fg)
+ {
+ 	int depth = fb_get_color_depth(&info->var, &info->fix);
+@@ -551,6 +552,9 @@ static int do_fbcon_takeover(int show_logo)
+ 		info_idx = -1;
+ 	} else {
+ 		fbcon_has_console_bind = 1;
++#ifdef CONFIG_FB_CON_DECOR
++		fbcon_decor_init();
++#endif
+ 	}
+ 
+ 	return err;
+@@ -1007,6 +1011,12 @@ static const char *fbcon_startup(void)
+ 	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ 	cols /= vc->vc_font.width;
+ 	rows /= vc->vc_font.height;
++
++	if (fbcon_decor_active(info, vc)) {
++		cols = vc->vc_decor.twidth / vc->vc_font.width;
++		rows = vc->vc_decor.theight / vc->vc_font.height;
++	}
++
+ 	vc_resize(vc, cols, rows);
+ 
+ 	DPRINTK("mode:   %s\n", info->fix.id);
+@@ -1036,7 +1046,7 @@ static void fbcon_init(struct vc_data *vc, int init)
+ 	cap = info->flags;
+ 
+ 	if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
+-	    (info->fix.type == FB_TYPE_TEXT))
++	    (info->fix.type == FB_TYPE_TEXT) || fbcon_decor_active(info, vc))
+ 		logo = 0;
+ 
+ 	if (var_to_display(p, &info->var, info))
+@@ -1260,6 +1270,11 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
+ 		fbcon_clear_margins(vc, 0);
+ 	}
+ 
++ 	if (fbcon_decor_active(info, vc)) {
++ 		fbcon_decor_clear(vc, info, sy, sx, height, width);
++ 		return;
++ 	}
++
+ 	/* Split blits that cross physical y_wrap boundary */
+ 
+ 	y_break = p->vrows - p->yscroll;
+@@ -1279,10 +1294,15 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
+ 	struct display *p = &fb_display[vc->vc_num];
+ 	struct fbcon_ops *ops = info->fbcon_par;
+ 
+-	if (!fbcon_is_inactive(vc, info))
+-		ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
+-			   get_color(vc, info, scr_readw(s), 1),
+-			   get_color(vc, info, scr_readw(s), 0));
++	if (!fbcon_is_inactive(vc, info)) {
++
++		if (fbcon_decor_active(info, vc))
++			fbcon_decor_putcs(vc, info, s, count, ypos, xpos);
++		else
++			ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
++				   get_color(vc, info, scr_readw(s), 1),
++				   get_color(vc, info, scr_readw(s), 0));
++	}
+ }
+ 
+ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
+@@ -1298,8 +1318,13 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
+ 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ 	struct fbcon_ops *ops = info->fbcon_par;
+ 
+-	if (!fbcon_is_inactive(vc, info))
+-		ops->clear_margins(vc, info, bottom_only);
++	if (!fbcon_is_inactive(vc, info)) {
++	 	if (fbcon_decor_active(info, vc)) {
++	 		fbcon_decor_clear_margins(vc, info, bottom_only);
++ 		} else {
++			ops->clear_margins(vc, info, bottom_only);
++		}
++	}
+ }
+ 
+ static void fbcon_cursor(struct vc_data *vc, int mode)
+@@ -1819,7 +1844,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
+ 			count = vc->vc_rows;
+ 		if (softback_top)
+ 			fbcon_softback_note(vc, t, count);
+-		if (logo_shown >= 0)
++		if (logo_shown >= 0 || fbcon_decor_active(info, vc))
+ 			goto redraw_up;
+ 		switch (p->scrollmode) {
+ 		case SCROLL_MOVE:
+@@ -1912,6 +1937,8 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
+ 			count = vc->vc_rows;
+ 		if (logo_shown >= 0)
+ 			goto redraw_down;
++		if (fbcon_decor_active(info, vc))
++			goto redraw_down;
+ 		switch (p->scrollmode) {
+ 		case SCROLL_MOVE:
+ 			fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
+@@ -2060,6 +2087,13 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s
+ 		}
+ 		return;
+ 	}
++
++	if (fbcon_decor_active(info, vc) && sy == dy && height == 1) {
++ 		/* must use slower redraw bmove to keep background pic intact */
++ 		fbcon_decor_bmove_redraw(vc, info, sy, sx, dx, width);
++ 		return;
++ 	}
++
+ 	ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+ 		   height, width);
+ }
+@@ -2130,8 +2164,8 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
+ 	var.yres = virt_h * virt_fh;
+ 	x_diff = info->var.xres - var.xres;
+ 	y_diff = info->var.yres - var.yres;
+-	if (x_diff < 0 || x_diff > virt_fw ||
+-	    y_diff < 0 || y_diff > virt_fh) {
++	if ((x_diff < 0 || x_diff > virt_fw ||
++		y_diff < 0 || y_diff > virt_fh) && !vc->vc_decor.state) {
+ 		const struct fb_videomode *mode;
+ 
+ 		DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
+@@ -2167,6 +2201,21 @@ static int fbcon_switch(struct vc_data *vc)
+ 
+ 	info = registered_fb[con2fb_map[vc->vc_num]];
+ 	ops = info->fbcon_par;
++	prev_console = ops->currcon;
++	if (prev_console != -1)
++		old_info = registered_fb[con2fb_map[prev_console]];
++
++#ifdef CONFIG_FB_CON_DECOR
++	if (!fbcon_decor_active_vc(vc) && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
++		struct vc_data *vc_curr = vc_cons[prev_console].d;
++		if (vc_curr && fbcon_decor_active_vc(vc_curr)) {
++			/* Clear the screen to avoid displaying funky colors during
++			 * palette updates. */
++			memset((u8*)info->screen_base + info->fix.line_length * info->var.yoffset,
++			       0, info->var.yres * info->fix.line_length);
++		}
++	}
++#endif
+ 
+ 	if (softback_top) {
+ 		if (softback_lines)
+@@ -2185,9 +2234,6 @@ static int fbcon_switch(struct vc_data *vc)
+ 		logo_shown = FBCON_LOGO_CANSHOW;
+ 	}
+ 
+-	prev_console = ops->currcon;
+-	if (prev_console != -1)
+-		old_info = registered_fb[con2fb_map[prev_console]];
+ 	/*
+ 	 * FIXME: If we have multiple fbdev's loaded, we need to
+ 	 * update all info->currcon.  Perhaps, we can place this
+@@ -2231,6 +2277,18 @@ static int fbcon_switch(struct vc_data *vc)
+ 			fbcon_del_cursor_timer(old_info);
+ 	}
+ 
++	if (fbcon_decor_active_vc(vc)) {
++		struct vc_data *vc_curr = vc_cons[prev_console].d;
++
++		if (!vc_curr->vc_decor.theme ||
++			strcmp(vc->vc_decor.theme, vc_curr->vc_decor.theme) ||
++			(fbcon_decor_active_nores(info, vc_curr) &&
++			 !fbcon_decor_active(info, vc_curr))) {
++			fbcon_decor_disable(vc, 0);
++			fbcon_decor_call_helper("modechange", vc->vc_num);
++		}
++	}
++
+ 	if (fbcon_is_inactive(vc, info) ||
+ 	    ops->blank_state != FB_BLANK_UNBLANK)
+ 		fbcon_del_cursor_timer(info);
+@@ -2339,15 +2397,20 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+ 		}
+ 	}
+ 
+- 	if (!fbcon_is_inactive(vc, info)) {
++	if (!fbcon_is_inactive(vc, info)) {
+ 		if (ops->blank_state != blank) {
+ 			ops->blank_state = blank;
+ 			fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
+ 			ops->cursor_flash = (!blank);
+ 
+-			if (!(info->flags & FBINFO_MISC_USEREVENT))
+-				if (fb_blank(info, blank))
+-					fbcon_generic_blank(vc, info, blank);
++			if (!(info->flags & FBINFO_MISC_USEREVENT)) {
++				if (fb_blank(info, blank)) {
++					if (fbcon_decor_active(info, vc))
++						fbcon_decor_blank(vc, info, blank);
++					else
++						fbcon_generic_blank(vc, info, blank);
++				}
++			}
+ 		}
+ 
+ 		if (!blank)
+@@ -2522,13 +2585,22 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
+ 	}
+ 
+ 	if (resize) {
++		/* reset wrap/pan */
+ 		int cols, rows;
+ 
+ 		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ 		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++
++		if (fbcon_decor_active(info, vc)) {
++			info->var.xoffset = info->var.yoffset = p->yscroll = 0;
++			cols = vc->vc_decor.twidth;
++			rows = vc->vc_decor.theight;
++		}
+ 		cols /= w;
+ 		rows /= h;
++
+ 		vc_resize(vc, cols, rows);
++
+ 		if (CON_IS_VISIBLE(vc) && softback_buf)
+ 			fbcon_update_softback(vc);
+ 	} else if (CON_IS_VISIBLE(vc)
+@@ -2657,7 +2729,11 @@ static int fbcon_set_palette(struct vc_data *vc, unsigned char *table)
+ 	int i, j, k, depth;
+ 	u8 val;
+ 
+-	if (fbcon_is_inactive(vc, info))
++	if (fbcon_is_inactive(vc, info)
++#ifdef CONFIG_FB_CON_DECOR
++			|| vc->vc_num != fg_console
++#endif
++		)
+ 		return -EINVAL;
+ 
+ 	if (!CON_IS_VISIBLE(vc))
+@@ -2683,14 +2759,56 @@ static int fbcon_set_palette(struct vc_data *vc, unsigned char *table)
+ 	} else
+ 		fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap);
+ 
+-	return fb_set_cmap(&palette_cmap, info);
++	if (fbcon_decor_active(info, vc_cons[fg_console].d) &&
++	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
++
++		u16 *red, *green, *blue;
++		int minlen = min(min(info->var.red.length, info->var.green.length),
++				     info->var.blue.length);
++		int h;
++
++		struct fb_cmap cmap = {
++			.start = 0,
++			.len = (1 << minlen),
++			.red = NULL,
++			.green = NULL,
++			.blue = NULL,
++			.transp = NULL
++		};
++
++		red = kmalloc(256 * sizeof(u16) * 3, GFP_KERNEL);
++
++		if (!red)
++			goto out;
++
++		green = red + 256;
++		blue = green + 256;
++		cmap.red = red;
++		cmap.green = green;
++		cmap.blue = blue;
++
++		for (i = 0; i < cmap.len; i++) {
++			red[i] = green[i] = blue[i] = (0xffff * i)/(cmap.len-1);
++		}
++
++		h = fb_set_cmap(&cmap, info);
++		fbcon_decor_fix_pseudo_pal(info, vc_cons[fg_console].d);
++		kfree(red);
++
++		return h;
++
++	} else if (fbcon_decor_active(info, vc_cons[fg_console].d) &&
++		   info->var.bits_per_pixel == 8 && info->bgdecor.cmap.red != NULL)
++		fb_set_cmap(&info->bgdecor.cmap, info);
++
++out:	return fb_set_cmap(&palette_cmap, info);
+ }
+ 
+ static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
+ {
+ 	unsigned long p;
+ 	int line;
+-	
++
+ 	if (vc->vc_num != fg_console || !softback_lines)
+ 		return (u16 *) (vc->vc_origin + offset);
+ 	line = offset / vc->vc_size_row;
+@@ -2909,7 +3027,14 @@ static void fbcon_modechanged(struct fb_info *info)
+ 		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ 		cols /= vc->vc_font.width;
+ 		rows /= vc->vc_font.height;
+-		vc_resize(vc, cols, rows);
++
++		if (!fbcon_decor_active_nores(info, vc)) {
++			vc_resize(vc, cols, rows);
++		} else {
++			fbcon_decor_disable(vc, 0);
++			fbcon_decor_call_helper("modechange", vc->vc_num);
++		}
++
+ 		updatescrollmode(p, info, vc);
+ 		scrollback_max = 0;
+ 		scrollback_current = 0;
+@@ -2954,7 +3079,9 @@ static void fbcon_set_all_vcs(struct fb_info *info)
+ 		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ 		cols /= vc->vc_font.width;
+ 		rows /= vc->vc_font.height;
+-		vc_resize(vc, cols, rows);
++		if (!fbcon_decor_active_nores(info, vc)) {
++			vc_resize(vc, cols, rows);
++		}
+ 	}
+ 
+ 	if (fg != -1)
+@@ -3596,6 +3723,7 @@ static void fbcon_exit(void)
+ 		}
+ 	}
+ 
++	fbcon_decor_exit();
+ 	fbcon_has_exited = 1;
+ }
+ 
+diff --git a/drivers/video/console/fbcondecor.c b/drivers/video/console/fbcondecor.c
+new file mode 100644
+index 0000000..babc8c5
+--- /dev/null
++++ b/drivers/video/console/fbcondecor.c
+@@ -0,0 +1,555 @@
++/*
++ *  linux/drivers/video/console/fbcondecor.c -- Framebuffer console decorations
++ *
++ *  Copyright (C) 2004-2009 Michal Januszewski <michalj+fbcondecor@gmail.com>
++ *
++ *  Code based upon "Bootsplash" (C) 2001-2003
++ *       Volker Poplawski <volker@poplawski.de>,
++ *       Stefan Reinauer <stepan@suse.de>,
++ *       Steffen Winterfeldt <snwint@suse.de>,
++ *       Michael Schroeder <mls@suse.de>,
++ *       Ken Wimer <wimer@suse.de>.
++ *
++ *  Compat ioctl support by Thorsten Klein <TK@Thorsten-Klein.de>.
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ *
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/vt_kern.h>
++#include <linux/vmalloc.h>
++#include <linux/unistd.h>
++#include <linux/syscalls.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/workqueue.h>
++#include <linux/kmod.h>
++#include <linux/miscdevice.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/compat.h>
++#include <linux/console.h>
++
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++
++#include "fbcon.h"
++#include "fbcondecor.h"
++
++extern signed char con2fb_map[];
++static int fbcon_decor_enable(struct vc_data *vc);
++char fbcon_decor_path[KMOD_PATH_LEN] = "/sbin/fbcondecor_helper";
++static int initialized = 0;
++
++int fbcon_decor_call_helper(char* cmd, unsigned short vc)
++{
++	char *envp[] = {
++		"HOME=/",
++		"PATH=/sbin:/bin",
++		NULL
++	};
++
++	char tfb[5];
++	char tcons[5];
++	unsigned char fb = (int) con2fb_map[vc];
++
++	char *argv[] = {
++		fbcon_decor_path,
++		"2",
++		cmd,
++		tcons,
++		tfb,
++		vc_cons[vc].d->vc_decor.theme,
++		NULL
++	};
++
++	snprintf(tfb,5,"%d",fb);
++	snprintf(tcons,5,"%d",vc);
++
++	return call_usermodehelper(fbcon_decor_path, argv, envp, UMH_WAIT_EXEC);
++}
++
++/* Disables fbcondecor on a virtual console; called with console sem held. */
++int fbcon_decor_disable(struct vc_data *vc, unsigned char redraw)
++{
++	struct fb_info* info;
++
++	if (!vc->vc_decor.state)
++		return -EINVAL;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (info == NULL)
++		return -EINVAL;
++
++	vc->vc_decor.state = 0;
++	vc_resize(vc, info->var.xres / vc->vc_font.width,
++		  info->var.yres / vc->vc_font.height);
++
++	if (fg_console == vc->vc_num && redraw) {
++		redraw_screen(vc, 0);
++		update_region(vc, vc->vc_origin +
++			      vc->vc_size_row * vc->vc_top,
++			      vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
++	}
++
++	printk(KERN_INFO "fbcondecor: switched decor state to 'off' on console %d\n",
++			 vc->vc_num);
++
++	return 0;
++}
++
++/* Enables fbcondecor on a virtual console; called with console sem held. */
++static int fbcon_decor_enable(struct vc_data *vc)
++{
++	struct fb_info* info;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (vc->vc_decor.twidth == 0 || vc->vc_decor.theight == 0 ||
++	    info == NULL || vc->vc_decor.state || (!info->bgdecor.data &&
++	    vc->vc_num == fg_console))
++		return -EINVAL;
++
++	vc->vc_decor.state = 1;
++	vc_resize(vc, vc->vc_decor.twidth / vc->vc_font.width,
++		  vc->vc_decor.theight / vc->vc_font.height);
++
++	if (fg_console == vc->vc_num) {
++		redraw_screen(vc, 0);
++		update_region(vc, vc->vc_origin +
++			      vc->vc_size_row * vc->vc_top,
++			      vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
++		fbcon_decor_clear_margins(vc, info, 0);
++	}
++
++	printk(KERN_INFO "fbcondecor: switched decor state to 'on' on console %d\n",
++			 vc->vc_num);
++
++	return 0;
++}
++
++static inline int fbcon_decor_ioctl_dosetstate(struct vc_data *vc, unsigned int state, unsigned char origin)
++{
++	int ret;
++
++//	if (origin == FBCON_DECOR_IO_ORIG_USER)
++		console_lock();
++	if (!state)
++		ret = fbcon_decor_disable(vc, 1);
++	else
++		ret = fbcon_decor_enable(vc);
++//	if (origin == FBCON_DECOR_IO_ORIG_USER)
++		console_unlock();
++
++	return ret;
++}
++
++static inline void fbcon_decor_ioctl_dogetstate(struct vc_data *vc, unsigned int *state)
++{
++	*state = vc->vc_decor.state;
++}
++
++static int fbcon_decor_ioctl_dosetcfg(struct vc_data *vc, struct vc_decor *cfg, unsigned char origin)
++{
++	struct fb_info *info;
++	int len;
++	char *tmp;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (info == NULL || !cfg->twidth || !cfg->theight ||
++	    cfg->tx + cfg->twidth  > info->var.xres ||
++	    cfg->ty + cfg->theight > info->var.yres)
++		return -EINVAL;
++
++	len = strlen_user(cfg->theme);
++	if (!len || len > FBCON_DECOR_THEME_LEN)
++		return -EINVAL;
++	tmp = kmalloc(len, GFP_KERNEL);
++	if (!tmp)
++		return -ENOMEM;
++	if (copy_from_user(tmp, (void __user *)cfg->theme, len))
++		return -EFAULT;
++	cfg->theme = tmp;
++	cfg->state = 0;
++
++	/* If this ioctl is a response to a request from kernel, the console sem
++	 * is already held; we also don't need to disable decor because either the
++	 * new config and background picture will be successfully loaded, and the
++	 * decor will stay on, or in case of a failure it'll be turned off in fbcon. */
++//	if (origin == FBCON_DECOR_IO_ORIG_USER) {
++		console_lock();
++		if (vc->vc_decor.state)
++			fbcon_decor_disable(vc, 1);
++//	}
++
++	if (vc->vc_decor.theme)
++		kfree(vc->vc_decor.theme);
++
++	vc->vc_decor = *cfg;
++
++//	if (origin == FBCON_DECOR_IO_ORIG_USER)
++		console_unlock();
++
++	printk(KERN_INFO "fbcondecor: console %d using theme '%s'\n",
++			 vc->vc_num, vc->vc_decor.theme);
++	return 0;
++}
++
++static int fbcon_decor_ioctl_dogetcfg(struct vc_data *vc, struct vc_decor *decor)
++{
++	char __user *tmp;
++
++	tmp = decor->theme;
++	*decor = vc->vc_decor;
++	decor->theme = tmp;
++
++	if (vc->vc_decor.theme) {
++		if (copy_to_user(tmp, vc->vc_decor.theme, strlen(vc->vc_decor.theme) + 1))
++			return -EFAULT;
++	} else
++		if (put_user(0, tmp))
++			return -EFAULT;
++
++	return 0;
++}
++
++static int fbcon_decor_ioctl_dosetpic(struct vc_data *vc, struct fb_image *img, unsigned char origin)
++{
++	struct fb_info *info;
++	int len;
++	u8 *tmp;
++
++	if (vc->vc_num != fg_console)
++		return -EINVAL;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (info == NULL)
++		return -EINVAL;
++
++	if (img->width != info->var.xres || img->height != info->var.yres) {
++		printk(KERN_ERR "fbcondecor: picture dimensions mismatch\n");
++		printk(KERN_ERR "%dx%d vs %dx%d\n", img->width, img->height, info->var.xres, info->var.yres);
++		return -EINVAL;
++	}
++
++	if (img->depth != info->var.bits_per_pixel) {
++		printk(KERN_ERR "fbcondecor: picture depth mismatch\n");
++		return -EINVAL;
++	}
++
++	if (img->depth == 8) {
++		if (!img->cmap.len || !img->cmap.red || !img->cmap.green ||
++		    !img->cmap.blue)
++			return -EINVAL;
++
++		tmp = vmalloc(img->cmap.len * 3 * 2);
++		if (!tmp)
++			return -ENOMEM;
++
++		if (copy_from_user(tmp,
++			    	   (void __user*)img->cmap.red, (img->cmap.len << 1)) ||
++		    copy_from_user(tmp + (img->cmap.len << 1),
++			    	   (void __user*)img->cmap.green, (img->cmap.len << 1)) ||
++		    copy_from_user(tmp + (img->cmap.len << 2),
++			    	   (void __user*)img->cmap.blue, (img->cmap.len << 1))) {
++			vfree(tmp);
++			return -EFAULT;
++		}
++
++		img->cmap.transp = NULL;
++		img->cmap.red = (u16*)tmp;
++		img->cmap.green = img->cmap.red + img->cmap.len;
++		img->cmap.blue = img->cmap.green + img->cmap.len;
++	} else {
++		img->cmap.red = NULL;
++	}
++
++	len = ((img->depth + 7) >> 3) * img->width * img->height;
++
++	/*
++	 * Allocate an additional byte so that we never go outside of the
++	 * buffer boundaries in the rendering functions in a 24 bpp mode.
++	 */
++	tmp = vmalloc(len + 1);
++
++	if (!tmp)
++		goto out;
++
++	if (copy_from_user(tmp, (void __user*)img->data, len))
++		goto out;
++
++	img->data = tmp;
++
++	/* If this ioctl is a response to a request from kernel, the console sem
++	 * is already held. */
++//	if (origin == FBCON_DECOR_IO_ORIG_USER)
++		console_lock();
++
++	if (info->bgdecor.data)
++		vfree((u8*)info->bgdecor.data);
++	if (info->bgdecor.cmap.red)
++		vfree(info->bgdecor.cmap.red);
++
++	info->bgdecor = *img;
++
++	if (fbcon_decor_active_vc(vc) && fg_console == vc->vc_num) {
++		redraw_screen(vc, 0);
++		update_region(vc, vc->vc_origin +
++			      vc->vc_size_row * vc->vc_top,
++			      vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
++		fbcon_decor_clear_margins(vc, info, 0);
++	}
++
++//	if (origin == FBCON_DECOR_IO_ORIG_USER)
++		console_unlock();
++
++	return 0;
++
++out:	if (img->cmap.red)
++		vfree(img->cmap.red);
++
++	if (tmp)
++		vfree(tmp);
++	return -ENOMEM;
++}
++
++static long fbcon_decor_ioctl(struct file *filp, u_int cmd, u_long arg)
++{
++	struct fbcon_decor_iowrapper __user *wrapper = (void __user*) arg;
++	struct vc_data *vc = NULL;
++	unsigned short vc_num = 0;
++	unsigned char origin = 0;
++	void __user *data = NULL;
++
++	if (!access_ok(VERIFY_READ, wrapper,
++			sizeof(struct fbcon_decor_iowrapper)))
++		return -EFAULT;
++
++	__get_user(vc_num, &wrapper->vc);
++	__get_user(origin, &wrapper->origin);
++	__get_user(data, &wrapper->data);
++
++	if (!vc_cons_allocated(vc_num))
++		return -EINVAL;
++
++	vc = vc_cons[vc_num].d;
++
++	switch (cmd) {
++	case FBIOCONDECOR_SETPIC:
++	{
++		struct fb_image img;
++		if (copy_from_user(&img, (struct fb_image __user *)data, sizeof(struct fb_image)))
++			return -EFAULT;
++
++		return fbcon_decor_ioctl_dosetpic(vc, &img, origin);
++	}
++	case FBIOCONDECOR_SETCFG:
++	{
++		struct vc_decor cfg;
++		if (copy_from_user(&cfg, (struct vc_decor __user *)data, sizeof(struct vc_decor)))
++			return -EFAULT;
++
++		return fbcon_decor_ioctl_dosetcfg(vc, &cfg, origin);
++	}
++	case FBIOCONDECOR_GETCFG:
++	{
++		int rval;
++		struct vc_decor cfg;
++
++		if (copy_from_user(&cfg, (struct vc_decor __user *)data, sizeof(struct vc_decor)))
++			return -EFAULT;
++
++		rval = fbcon_decor_ioctl_dogetcfg(vc, &cfg);
++
++		if (copy_to_user(data, &cfg, sizeof(struct vc_decor)))
++			return -EFAULT;
++		return rval;
++	}
++	case FBIOCONDECOR_SETSTATE:
++	{
++		unsigned int state = 0;
++		if (get_user(state, (unsigned int __user *)data))
++			return -EFAULT;
++		return fbcon_decor_ioctl_dosetstate(vc, state, origin);
++	}
++	case FBIOCONDECOR_GETSTATE:
++	{
++		unsigned int state = 0;
++		fbcon_decor_ioctl_dogetstate(vc, &state);
++		return put_user(state, (unsigned int __user *)data);
++	}
++
++	default:
++		return -ENOIOCTLCMD;
++	}
++}
++
++#ifdef CONFIG_COMPAT
++
++static long fbcon_decor_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
++
++	struct fbcon_decor_iowrapper32 __user *wrapper = (void __user *)arg;
++	struct vc_data *vc = NULL;
++	unsigned short vc_num = 0;
++	unsigned char origin = 0;
++	compat_uptr_t data_compat = 0;
++	void __user *data = NULL;
++
++	if (!access_ok(VERIFY_READ, wrapper,
++                       sizeof(struct fbcon_decor_iowrapper32)))
++		return -EFAULT;
++
++	__get_user(vc_num, &wrapper->vc);
++	__get_user(origin, &wrapper->origin);
++	__get_user(data_compat, &wrapper->data);
++	data = compat_ptr(data_compat);
++
++	if (!vc_cons_allocated(vc_num))
++		return -EINVAL;
++
++	vc = vc_cons[vc_num].d;
++
++	switch (cmd) {
++	case FBIOCONDECOR_SETPIC32:
++	{
++		struct fb_image32 img_compat;
++		struct fb_image img;
++
++		if (copy_from_user(&img_compat, (struct fb_image32 __user *)data, sizeof(struct fb_image32)))
++			return -EFAULT;
++
++		fb_image_from_compat(img, img_compat);
++
++		return fbcon_decor_ioctl_dosetpic(vc, &img, origin);
++	}
++
++	case FBIOCONDECOR_SETCFG32:
++	{
++		struct vc_decor32 cfg_compat;
++		struct vc_decor cfg;
++
++		if (copy_from_user(&cfg_compat, (struct vc_decor32 __user *)data, sizeof(struct vc_decor32)))
++			return -EFAULT;
++
++		vc_decor_from_compat(cfg, cfg_compat);
++
++		return fbcon_decor_ioctl_dosetcfg(vc, &cfg, origin);
++	}
++
++	case FBIOCONDECOR_GETCFG32:
++	{
++		int rval;
++		struct vc_decor32 cfg_compat;
++		struct vc_decor cfg;
++
++		if (copy_from_user(&cfg_compat, (struct vc_decor32 __user *)data, sizeof(struct vc_decor32)))
++			return -EFAULT;
++		cfg.theme = compat_ptr(cfg_compat.theme);
++
++		rval = fbcon_decor_ioctl_dogetcfg(vc, &cfg);
++
++		vc_decor_to_compat(cfg_compat, cfg);
++
++		if (copy_to_user((struct vc_decor32 __user *)data, &cfg_compat, sizeof(struct vc_decor32)))
++			return -EFAULT;
++		return rval;
++	}
++
++	case FBIOCONDECOR_SETSTATE32:
++	{
++		compat_uint_t state_compat = 0;
++		unsigned int state = 0;
++
++		if (get_user(state_compat, (compat_uint_t __user *)data))
++			return -EFAULT;
++
++		state = (unsigned int)state_compat;
++
++		return fbcon_decor_ioctl_dosetstate(vc, state, origin);
++	}
++
++	case FBIOCONDECOR_GETSTATE32:
++	{
++		compat_uint_t state_compat = 0;
++		unsigned int state = 0;
++
++		fbcon_decor_ioctl_dogetstate(vc, &state);
++		state_compat = (compat_uint_t)state;
++
++		return put_user(state_compat, (compat_uint_t __user *)data);
++	}
++
++	default:
++		return -ENOIOCTLCMD;
++	}
++}
++#else
++  #define fbcon_decor_compat_ioctl NULL
++#endif
++
++static struct file_operations fbcon_decor_ops = {
++	.owner = THIS_MODULE,
++	.unlocked_ioctl = fbcon_decor_ioctl,
++	.compat_ioctl = fbcon_decor_compat_ioctl
++};
++
++static struct miscdevice fbcon_decor_dev = {
++	.minor = MISC_DYNAMIC_MINOR,
++	.name = "fbcondecor",
++	.fops = &fbcon_decor_ops
++};
++
++void fbcon_decor_reset(void)
++{
++	int i;
++
++	for (i = 0; i < num_registered_fb; i++) {
++		registered_fb[i]->bgdecor.data = NULL;
++		registered_fb[i]->bgdecor.cmap.red = NULL;
++	}
++
++	for (i = 0; i < MAX_NR_CONSOLES && vc_cons[i].d; i++) {
++		vc_cons[i].d->vc_decor.state = vc_cons[i].d->vc_decor.twidth =
++						vc_cons[i].d->vc_decor.theight = 0;
++		vc_cons[i].d->vc_decor.theme = NULL;
++	}
++
++	return;
++}
++
++int fbcon_decor_init(void)
++{
++	int i;
++
++	fbcon_decor_reset();
++
++	if (initialized)
++		return 0;
++
++	i = misc_register(&fbcon_decor_dev);
++	if (i) {
++		printk(KERN_ERR "fbcondecor: failed to register device\n");
++		return i;
++	}
++
++	fbcon_decor_call_helper("init", 0);
++	initialized = 1;
++	return 0;
++}
++
++int fbcon_decor_exit(void)
++{
++	fbcon_decor_reset();
++	return 0;
++}
++
++EXPORT_SYMBOL(fbcon_decor_path);
+diff --git a/drivers/video/console/fbcondecor.h b/drivers/video/console/fbcondecor.h
+new file mode 100644
+index 0000000..3b3724b
+--- /dev/null
++++ b/drivers/video/console/fbcondecor.h
+@@ -0,0 +1,78 @@
++/* 
++ *  linux/drivers/video/console/fbcondecor.h -- Framebuffer Console Decoration headers
++ *
++ *  Copyright (C) 2004 Michal Januszewski <michalj+fbcondecor@gmail.com>
++ *
++ */
++
++#ifndef __FBCON_DECOR_H
++#define __FBCON_DECOR_H
++
++#ifndef _LINUX_FB_H
++#include <linux/fb.h>
++#endif
++
++/* This is needed for vc_cons in fbcmap.c */
++#include <linux/vt_kern.h>
++
++struct fb_cursor;
++struct fb_info;
++struct vc_data;
++
++#ifdef CONFIG_FB_CON_DECOR
++/* fbcondecor.c */
++int fbcon_decor_init(void);
++int fbcon_decor_exit(void);
++int fbcon_decor_call_helper(char* cmd, unsigned short cons);
++int fbcon_decor_disable(struct vc_data *vc, unsigned char redraw);
++
++/* cfbcondecor.c */
++void fbcon_decor_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx);
++void fbcon_decor_cursor(struct fb_info *info, struct fb_cursor *cursor);
++void fbcon_decor_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width);
++void fbcon_decor_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only);
++void fbcon_decor_blank(struct vc_data *vc, struct fb_info *info, int blank);
++void fbcon_decor_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width);
++void fbcon_decor_copy(u8 *dst, u8 *src, int height, int width, int linebytes, int srclinesbytes, int bpp);
++void fbcon_decor_fix_pseudo_pal(struct fb_info *info, struct vc_data *vc);
++
++/* vt.c */
++void acquire_console_sem(void);
++void release_console_sem(void);
++void do_unblank_screen(int entering_gfx);
++
++/* struct vc_data *y */
++#define fbcon_decor_active_vc(y) (y->vc_decor.state && y->vc_decor.theme) 
++
++/* struct fb_info *x, struct vc_data *y */
++#define fbcon_decor_active_nores(x,y) (x->bgdecor.data && fbcon_decor_active_vc(y))
++
++/* struct fb_info *x, struct vc_data *y */
++#define fbcon_decor_active(x,y) (fbcon_decor_active_nores(x,y) &&		\
++			      x->bgdecor.width == x->var.xres && 	\
++			      x->bgdecor.height == x->var.yres &&	\
++			      x->bgdecor.depth == x->var.bits_per_pixel)
++
++
++#else /* CONFIG_FB_CON_DECOR */
++
++static inline void fbcon_decor_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx) {}
++static inline void fbcon_decor_putc(struct vc_data *vc, struct fb_info *info, int c, int ypos, int xpos) {}
++static inline void fbcon_decor_cursor(struct fb_info *info, struct fb_cursor *cursor) {}
++static inline void fbcon_decor_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) {}
++static inline void fbcon_decor_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only) {}
++static inline void fbcon_decor_blank(struct vc_data *vc, struct fb_info *info, int blank) {}
++static inline void fbcon_decor_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width) {}
++static inline void fbcon_decor_fix_pseudo_pal(struct fb_info *info, struct vc_data *vc) {}
++static inline int fbcon_decor_call_helper(char* cmd, unsigned short cons) { return 0; }
++static inline int fbcon_decor_init(void) { return 0; }
++static inline int fbcon_decor_exit(void) { return 0; }
++static inline int fbcon_decor_disable(struct vc_data *vc, unsigned char redraw) { return 0; }
++
++#define fbcon_decor_active_vc(y) (0)
++#define fbcon_decor_active_nores(x,y) (0)
++#define fbcon_decor_active(x,y) (0)
++
++#endif /* CONFIG_FB_CON_DECOR */
++
++#endif /* __FBCON_DECOR_H */
+diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
+index e1f4727..2952e33 100644
+--- a/drivers/video/fbdev/Kconfig
++++ b/drivers/video/fbdev/Kconfig
+@@ -1204,7 +1204,6 @@ config FB_MATROX
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+-	select FB_TILEBLITTING
+ 	select FB_MACMODES if PPC_PMAC
+ 	---help---
+ 	  Say Y here if you have a Matrox Millennium, Matrox Millennium II,
+diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
+index f89245b..05e036c 100644
+--- a/drivers/video/fbdev/core/fbcmap.c
++++ b/drivers/video/fbdev/core/fbcmap.c
+@@ -17,6 +17,8 @@
+ #include <linux/slab.h>
+ #include <linux/uaccess.h>
+ 
++#include "../../console/fbcondecor.h"
++
+ static u16 red2[] __read_mostly = {
+     0x0000, 0xaaaa
+ };
+@@ -249,14 +251,17 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
+ 			if (transp)
+ 				htransp = *transp++;
+ 			if (info->fbops->fb_setcolreg(start++,
+-						      hred, hgreen, hblue,
++						      hred, hgreen, hblue, 
+ 						      htransp, info))
+ 				break;
+ 		}
+ 	}
+-	if (rc == 0)
++	if (rc == 0) {
+ 		fb_copy_cmap(cmap, &info->cmap);
+-
++		if (fbcon_decor_active(info, vc_cons[fg_console].d) &&
++		    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
++			fbcon_decor_fix_pseudo_pal(info, vc_cons[fg_console].d);
++	}
+ 	return rc;
+ }
+ 
+diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
+index b6d5008..d6703f2 100644
+--- a/drivers/video/fbdev/core/fbmem.c
++++ b/drivers/video/fbdev/core/fbmem.c
+@@ -1250,15 +1250,6 @@ struct fb_fix_screeninfo32 {
+ 	u16			reserved[3];
+ };
+ 
+-struct fb_cmap32 {
+-	u32			start;
+-	u32			len;
+-	compat_caddr_t	red;
+-	compat_caddr_t	green;
+-	compat_caddr_t	blue;
+-	compat_caddr_t	transp;
+-};
+-
+ static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
+ 			  unsigned long arg)
+ {
+diff --git a/include/linux/console_decor.h b/include/linux/console_decor.h
+new file mode 100644
+index 0000000..04b8d80
+--- /dev/null
++++ b/include/linux/console_decor.h
+@@ -0,0 +1,46 @@
++#ifndef _LINUX_CONSOLE_DECOR_H_
++#define _LINUX_CONSOLE_DECOR_H_ 1
++
++/* A structure used by the framebuffer console decorations (drivers/video/console/fbcondecor.c) */
++struct vc_decor {
++	__u8 bg_color;				/* The color that is to be treated as transparent */
++	__u8 state;				/* Current decor state: 0 = off, 1 = on */
++	__u16 tx, ty;				/* Top left corner coordinates of the text field */
++	__u16 twidth, theight;			/* Width and height of the text field */
++	char* theme;
++};
++
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++#include <linux/compat.h>
++
++struct vc_decor32 {
++	__u8 bg_color;				/* The color that is to be treated as transparent */
++	__u8 state;				/* Current decor state: 0 = off, 1 = on */
++	__u16 tx, ty;				/* Top left corner coordinates of the text field */
++	__u16 twidth, theight;			/* Width and height of the text field */
++	compat_uptr_t theme;
++};
++
++#define vc_decor_from_compat(to, from) \
++	(to).bg_color = (from).bg_color; \
++	(to).state    = (from).state; \
++	(to).tx       = (from).tx; \
++	(to).ty       = (from).ty; \
++	(to).twidth   = (from).twidth; \
++	(to).theight  = (from).theight; \
++	(to).theme    = compat_ptr((from).theme)
++
++#define vc_decor_to_compat(to, from) \
++	(to).bg_color = (from).bg_color; \
++	(to).state    = (from).state; \
++	(to).tx       = (from).tx; \
++	(to).ty       = (from).ty; \
++	(to).twidth   = (from).twidth; \
++	(to).theight  = (from).theight; \
++	(to).theme    = ptr_to_compat((from).theme)
++
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
++#endif
+diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
+index 7f0c329..98f5d60 100644
+--- a/include/linux/console_struct.h
++++ b/include/linux/console_struct.h
+@@ -19,6 +19,7 @@
+ struct vt_struct;
+ 
+ #define NPAR 16
++#include <linux/console_decor.h>
+ 
+ struct vc_data {
+ 	struct tty_port port;			/* Upper level data */
+@@ -107,6 +108,8 @@ struct vc_data {
+ 	unsigned long	vc_uni_pagedir;
+ 	unsigned long	*vc_uni_pagedir_loc;  /* [!] Location of uni_pagedir variable for this console */
+ 	bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
++
++	struct vc_decor vc_decor;
+ 	/* additional information is in vt_kern.h */
+ };
+ 
+diff --git a/include/linux/fb.h b/include/linux/fb.h
+index fe6ac95..1e36b03 100644
+--- a/include/linux/fb.h
++++ b/include/linux/fb.h
+@@ -219,6 +219,34 @@ struct fb_deferred_io {
+ };
+ #endif
+ 
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++struct fb_image32 {
++	__u32 dx;			/* Where to place image */
++	__u32 dy;
++	__u32 width;			/* Size of image */
++	__u32 height;
++	__u32 fg_color;			/* Only used when a mono bitmap */
++	__u32 bg_color;
++	__u8  depth;			/* Depth of the image */
++	const compat_uptr_t data;	/* Pointer to image data */
++	struct fb_cmap32 cmap;		/* color map info */
++};
++
++#define fb_image_from_compat(to, from) \
++	(to).dx       = (from).dx; \
++	(to).dy       = (from).dy; \
++	(to).width    = (from).width; \
++	(to).height   = (from).height; \
++	(to).fg_color = (from).fg_color; \
++	(to).bg_color = (from).bg_color; \
++	(to).depth    = (from).depth; \
++	(to).data     = compat_ptr((from).data); \
++	fb_cmap_from_compat((to).cmap, (from).cmap)
++
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
+ /*
+  * Frame buffer operations
+  *
+@@ -489,6 +517,9 @@ struct fb_info {
+ #define FBINFO_STATE_SUSPENDED	1
+ 	u32 state;			/* Hardware state i.e suspend */
+ 	void *fbcon_par;                /* fbcon use-only private area */
++
++	struct fb_image bgdecor;
++
+ 	/* From here on everything is device dependent */
+ 	void *par;
+ 	/* we need the PCI or similar aperture base/size not
+diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h
+index fb795c3..dc77a03 100644
+--- a/include/uapi/linux/fb.h
++++ b/include/uapi/linux/fb.h
+@@ -8,6 +8,25 @@
+ 
+ #define FB_MAX			32	/* sufficient for now */
+ 
++struct fbcon_decor_iowrapper
++{
++	unsigned short vc;		/* Virtual console */
++	unsigned char origin;		/* Point of origin of the request */
++	void *data;
++};
++
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++#include <linux/compat.h>
++struct fbcon_decor_iowrapper32
++{
++	unsigned short vc;		/* Virtual console */
++	unsigned char origin;		/* Point of origin of the request */
++	compat_uptr_t data;
++};
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
+ /* ioctls
+    0x46 is 'F'								*/
+ #define FBIOGET_VSCREENINFO	0x4600
+@@ -35,6 +54,25 @@
+ #define FBIOGET_DISPINFO        0x4618
+ #define FBIO_WAITFORVSYNC	_IOW('F', 0x20, __u32)
+ 
++#define FBIOCONDECOR_SETCFG	_IOWR('F', 0x19, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_GETCFG	_IOR('F', 0x1A, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_SETSTATE	_IOWR('F', 0x1B, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_GETSTATE	_IOR('F', 0x1C, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_SETPIC 	_IOWR('F', 0x1D, struct fbcon_decor_iowrapper)
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++#define FBIOCONDECOR_SETCFG32	_IOWR('F', 0x19, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_GETCFG32	_IOR('F', 0x1A, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_SETSTATE32	_IOWR('F', 0x1B, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_GETSTATE32	_IOR('F', 0x1C, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_SETPIC32	_IOWR('F', 0x1D, struct fbcon_decor_iowrapper32)
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
++#define FBCON_DECOR_THEME_LEN		128	/* Maximum lenght of a theme name */
++#define FBCON_DECOR_IO_ORIG_KERNEL	0	/* Kernel ioctl origin */
++#define FBCON_DECOR_IO_ORIG_USER	1	/* User ioctl origin */
++ 
+ #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
+ #define FB_TYPE_PLANES			1	/* Non interleaved planes */
+ #define FB_TYPE_INTERLEAVED_PLANES	2	/* Interleaved planes	*/
+@@ -277,6 +315,29 @@ struct fb_var_screeninfo {
+ 	__u32 reserved[4];		/* Reserved for future compatibility */
+ };
+ 
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++struct fb_cmap32 {
++	__u32 start;
++	__u32 len;			/* Number of entries */
++	compat_uptr_t red;		/* Red values	*/
++	compat_uptr_t green;
++	compat_uptr_t blue;
++	compat_uptr_t transp;		/* transparency, can be NULL */
++};
++
++#define fb_cmap_from_compat(to, from) \
++	(to).start  = (from).start; \
++	(to).len    = (from).len; \
++	(to).red    = compat_ptr((from).red); \
++	(to).green  = compat_ptr((from).green); \
++	(to).blue   = compat_ptr((from).blue); \
++	(to).transp = compat_ptr((from).transp)
++
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
++
+ struct fb_cmap {
+ 	__u32 start;			/* First entry	*/
+ 	__u32 len;			/* Number of entries */
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 74f5b58..6386ab0 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -146,6 +146,10 @@ static const int cap_last_cap = CAP_LAST_CAP;
+ static unsigned long hung_task_timeout_max = (LONG_MAX/HZ);
+ #endif
+ 
++#ifdef CONFIG_FB_CON_DECOR
++extern char fbcon_decor_path[];
++#endif
++
+ #ifdef CONFIG_INOTIFY_USER
+ #include <linux/inotify.h>
+ #endif
+@@ -255,6 +259,15 @@ static struct ctl_table sysctl_base_table[] = {
+ 		.mode		= 0555,
+ 		.child		= dev_table,
+ 	},
++#ifdef CONFIG_FB_CON_DECOR
++	{
++		.procname	= "fbcondecor",
++		.data		= &fbcon_decor_path,
++		.maxlen		= KMOD_PATH_LEN,
++		.mode		= 0644,
++		.proc_handler	= &proc_dostring,
++	},
++#endif
+ 	{ }
+ };
+ 

diff --git a/4567_distro-Gentoo-Kconfig.patch b/4567_distro-Gentoo-Kconfig.patch
index c7af596..652e2a7 100644
--- a/4567_distro-Gentoo-Kconfig.patch
+++ b/4567_distro-Gentoo-Kconfig.patch
@@ -1,5 +1,5 @@
---- a/Kconfig
-+++ b/Kconfig
+--- a/Kconfig	2014-04-02 09:45:05.389224541 -0400
++++ b/Kconfig	2014-04-02 09:45:39.269224273 -0400
 @@ -8,4 +8,6 @@ config SRCARCH
  	string
  	option env="SRCARCH"
@@ -7,9 +7,9 @@
 +source "distro/Kconfig"
 +
  source "arch/$SRCARCH/Kconfig"
---- /dev/null
-+++ b/distro/Kconfig
-@@ -0,0 +1,131 @@
+--- 	1969-12-31 19:00:00.000000000 -0500
++++ b/distro/Kconfig	2014-04-02 09:57:03.539218861 -0400
+@@ -0,0 +1,108 @@
 +menu "Gentoo Linux"
 +
 +config GENTOO_LINUX
@@ -30,7 +30,7 @@
 +
 +	depends on GENTOO_LINUX
 +	default y if GENTOO_LINUX
-+
++	
 +	select DEVTMPFS
 +	select TMPFS
 +
@@ -51,29 +51,7 @@
 +		boot process; if not available, it causes sysfs and udev to malfunction.
 +
 +		To ensure Gentoo Linux boots, it is best to leave this setting enabled;
-+		if you run a custom setup, you could consider whether to disable this.
-+
-+config GENTOO_LINUX_PORTAGE
-+	bool "Select options required by Portage features"
-+
-+	depends on GENTOO_LINUX
-+	default y if GENTOO_LINUX
-+
-+	select CGROUPS
-+	select NAMESPACES
-+	select IPC_NS
-+	select NET_NS
-+
-+	help
-+		This enables options required by various Portage FEATURES.
-+		Currently this selects:
-+
-+		CGROUPS     (required for FEATURES=cgroup)
-+		IPC_NS      (required for FEATURES=ipc-sandbox)
-+		NET_NS      (required for FEATURES=network-sandbox)
-+
-+		It is highly recommended that you leave this enabled as these FEATURES
-+		are, or will soon be, enabled by default.
++		if you run a custom setup, you could consider whether to disable this. 
 +
 +menu "Support for init systems, system and service managers"
 +	visible if GENTOO_LINUX
@@ -109,13 +87,12 @@
 +	select AUTOFS4_FS
 +	select BLK_DEV_BSG
 +	select CGROUPS
-+	select DEVPTS_MULTIPLE_INSTANCES
 +	select EPOLL
 +	select FANOTIFY
 +	select FHANDLE
 +	select INOTIFY_USER
 +	select NET
-+	select NET_NS
++	select NET_NS 
 +	select PROC_FS
 +	select SIGNALFD
 +	select SYSFS

diff --git a/5000_enable-additional-cpu-optimizations-for-gcc.patch b/5000_enable-additional-cpu-optimizations-for-gcc.patch
new file mode 100644
index 0000000..f7ab6f0
--- /dev/null
+++ b/5000_enable-additional-cpu-optimizations-for-gcc.patch
@@ -0,0 +1,327 @@
+This patch has been tested on and known to work with kernel versions from 3.2
+up to the latest git version (pulled on 12/14/2013).
+
+This patch will expand the number of microarchitectures to include new
+processors including: AMD K10-family, AMD Family 10h (Barcelona), AMD Family
+14h (Bobcat), AMD Family 15h (Bulldozer), AMD Family 15h (Piledriver), AMD
+Family 16h (Jaguar), Intel 1st Gen Core i3/i5/i7 (Nehalem), Intel 2nd Gen Core
+i3/i5/i7 (Sandybridge), Intel 3rd Gen Core i3/i5/i7 (Ivybridge), and Intel 4th
+Gen Core i3/i5/i7 (Haswell). It also offers the compiler the 'native' flag.
+
+Small but real speed increases are measurable using a make endpoint comparing
+a generic kernel to one built with one of the respective microarchs.
+
+See the following experimental evidence supporting this statement:
+https://github.com/graysky2/kernel_gcc_patch
+
+REQUIREMENTS
+linux version >=3.15
+gcc version <4.9
+
+---
+diff -uprN a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h
+--- a/arch/x86/include/asm/module.h	2013-11-03 18:41:51.000000000 -0500
++++ b/arch/x86/include/asm/module.h	2013-12-15 06:21:24.351122516 -0500
+@@ -15,6 +15,16 @@
+ #define MODULE_PROC_FAMILY "586MMX "
+ #elif defined CONFIG_MCORE2
+ #define MODULE_PROC_FAMILY "CORE2 "
++#elif defined CONFIG_MNATIVE
++#define MODULE_PROC_FAMILY "NATIVE "
++#elif defined CONFIG_MCOREI7
++#define MODULE_PROC_FAMILY "COREI7 "
++#elif defined CONFIG_MCOREI7AVX
++#define MODULE_PROC_FAMILY "COREI7AVX "
++#elif defined CONFIG_MCOREAVXI
++#define MODULE_PROC_FAMILY "COREAVXI "
++#elif defined CONFIG_MCOREAVX2
++#define MODULE_PROC_FAMILY "COREAVX2 "
+ #elif defined CONFIG_MATOM
+ #define MODULE_PROC_FAMILY "ATOM "
+ #elif defined CONFIG_M686
+@@ -33,6 +43,18 @@
+ #define MODULE_PROC_FAMILY "K7 "
+ #elif defined CONFIG_MK8
+ #define MODULE_PROC_FAMILY "K8 "
++#elif defined CONFIG_MK10
++#define MODULE_PROC_FAMILY "K10 "
++#elif defined CONFIG_MBARCELONA
++#define MODULE_PROC_FAMILY "BARCELONA "
++#elif defined CONFIG_MBOBCAT
++#define MODULE_PROC_FAMILY "BOBCAT "
++#elif defined CONFIG_MBULLDOZER
++#define MODULE_PROC_FAMILY "BULLDOZER "
++#elif defined CONFIG_MPILEDRIVER
++#define MODULE_PROC_FAMILY "PILEDRIVER "
++#elif defined CONFIG_MJAGUAR
++#define MODULE_PROC_FAMILY "JAGUAR "
+ #elif defined CONFIG_MELAN
+ #define MODULE_PROC_FAMILY "ELAN "
+ #elif defined CONFIG_MCRUSOE
+diff -uprN a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
+--- a/arch/x86/Kconfig.cpu	2013-11-03 18:41:51.000000000 -0500
++++ b/arch/x86/Kconfig.cpu	2013-12-15 06:21:24.351122516 -0500
+@@ -139,7 +139,7 @@ config MPENTIUM4
+ 
+ 
+ config MK6
+-	bool "K6/K6-II/K6-III"
++	bool "AMD K6/K6-II/K6-III"
+ 	depends on X86_32
+ 	---help---
+ 	  Select this for an AMD K6-family processor.  Enables use of
+@@ -147,7 +147,7 @@ config MK6
+ 	  flags to GCC.
+ 
+ config MK7
+-	bool "Athlon/Duron/K7"
++	bool "AMD Athlon/Duron/K7"
+ 	depends on X86_32
+ 	---help---
+ 	  Select this for an AMD Athlon K7-family processor.  Enables use of
+@@ -155,12 +155,55 @@ config MK7
+ 	  flags to GCC.
+ 
+ config MK8
+-	bool "Opteron/Athlon64/Hammer/K8"
++	bool "AMD Opteron/Athlon64/Hammer/K8"
+ 	---help---
+ 	  Select this for an AMD Opteron or Athlon64 Hammer-family processor.
+ 	  Enables use of some extended instructions, and passes appropriate
+ 	  optimization flags to GCC.
+ 
++config MK10
++	bool "AMD 61xx/7x50/PhenomX3/X4/II/K10"
++	---help---
++	  Select this for an AMD 61xx Eight-Core Magny-Cours, Athlon X2 7x50,
++		Phenom X3/X4/II, Athlon II X2/X3/X4, or Turion II-family processor.
++	  Enables use of some extended instructions, and passes appropriate
++	  optimization flags to GCC.
++
++config MBARCELONA
++	bool "AMD Barcelona"
++	---help---
++	  Select this for AMD Barcelona and newer processors.
++
++	  Enables -march=barcelona
++
++config MBOBCAT
++	bool "AMD Bobcat"
++	---help---
++	  Select this for AMD Bobcat processors.
++
++	  Enables -march=btver1
++
++config MBULLDOZER
++	bool "AMD Bulldozer"
++	---help---
++	  Select this for AMD Bulldozer processors.
++
++	  Enables -march=bdver1
++
++config MPILEDRIVER
++	bool "AMD Piledriver"
++	---help---
++	  Select this for AMD Piledriver processors.
++
++	  Enables -march=bdver2
++
++config MJAGUAR
++	bool "AMD Jaguar"
++	---help---
++	  Select this for AMD Jaguar processors.
++
++	  Enables -march=btver2
++
+ config MCRUSOE
+ 	bool "Crusoe"
+ 	depends on X86_32
+@@ -251,8 +294,17 @@ config MPSC
+ 	  using the cpu family field
+ 	  in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one.
+ 
++config MATOM
++	bool "Intel Atom"
++	---help---
++
++	  Select this for the Intel Atom platform. Intel Atom CPUs have an
++	  in-order pipelining architecture and thus can benefit from
++	  accordingly optimized code. Use a recent GCC with specific Atom
++	  support in order to fully benefit from selecting this option.
++
+ config MCORE2
+-	bool "Core 2/newer Xeon"
++	bool "Intel Core 2"
+ 	---help---
+ 
+ 	  Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and
+@@ -260,14 +312,40 @@ config MCORE2
+ 	  family in /proc/cpuinfo. Newer ones have 6 and older ones 15
+ 	  (not a typo)
+ 
+-config MATOM
+-	bool "Intel Atom"
++	  Enables -march=core2
++
++config MCOREI7
++	bool "Intel Core i7"
+ 	---help---
+ 
+-	  Select this for the Intel Atom platform. Intel Atom CPUs have an
+-	  in-order pipelining architecture and thus can benefit from
+-	  accordingly optimized code. Use a recent GCC with specific Atom
+-	  support in order to fully benefit from selecting this option.
++	  Select this for the Intel Nehalem platform. Intel Nehalem proecessors
++	  include Core i3, i5, i7, Xeon: 34xx, 35xx, 55xx, 56xx, 75xx processors.
++
++	  Enables -march=corei7
++
++config MCOREI7AVX
++	bool "Intel Core 2nd Gen AVX"
++	---help---
++
++	  Select this for 2nd Gen Core processors including Sandy Bridge.
++
++	  Enables -march=corei7-avx
++
++config MCOREAVXI
++	bool "Intel Core 3rd Gen AVX"
++	---help---
++
++	  Select this for 3rd Gen Core processors including Ivy Bridge.
++
++	  Enables -march=core-avx-i
++
++config MCOREAVX2
++	bool "Intel Core AVX2"
++	---help---
++
++	  Select this for AVX2 enabled processors including Haswell.
++
++	  Enables -march=core-avx2
+ 
+ config GENERIC_CPU
+ 	bool "Generic-x86-64"
+@@ -276,6 +354,19 @@ config GENERIC_CPU
+ 	  Generic x86-64 CPU.
+ 	  Run equally well on all x86-64 CPUs.
+ 
++config MNATIVE
++ bool "Native optimizations autodetected by GCC"
++ ---help---
++
++   GCC 4.2 and above support -march=native, which automatically detects
++   the optimum settings to use based on your processor. -march=native
++   also detects and applies additional settings beyond -march specific
++   to your CPU, (eg. -msse4). Unless you have a specific reason not to
++   (e.g. distcc cross-compiling), you should probably be using
++   -march=native rather than anything listed below.
++
++   Enables -march=native
++
+ endchoice
+ 
+ config X86_GENERIC
+@@ -300,7 +391,7 @@ config X86_INTERNODE_CACHE_SHIFT
+ config X86_L1_CACHE_SHIFT
+ 	int
+ 	default "7" if MPENTIUM4 || MPSC
+-	default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
++	default "6" if MK7 || MK8 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MJAGUAR || MPENTIUMM || MCORE2 || MCOREI7 || MCOREI7AVX || MCOREAVXI || MCOREAVX2 || MATOM || MVIAC7 || X86_GENERIC || MNATIVE || GENERIC_CPU
+ 	default "4" if MELAN || M486 || MGEODEGX1
+ 	default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+ 
+@@ -331,11 +422,11 @@ config X86_ALIGNMENT_16
+ 
+ config X86_INTEL_USERCOPY
+ 	def_bool y
+-	depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2
++	depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || MNATIVE || X86_GENERIC || MK8 || MK7 || MK10 || MBARCELONA || MEFFICEON || MCORE2 || MCOREI7 || MCOREI7AVX || MCOREAVXI || MCOREAVX2
+ 
+ config X86_USE_PPRO_CHECKSUM
+ 	def_bool y
+-	depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM
++	depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MK10 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MCOREI7 || MCOREI7AVX || MCOREAVXI || MCOREAVX2 || MATOM || MNATIVE
+ 
+ config X86_USE_3DNOW
+ 	def_bool y
+@@ -363,17 +454,17 @@ config X86_P6_NOP
+ 
+ config X86_TSC
+ 	def_bool y
+-	depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64
++	depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MJAGUAR || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MCOREI7 || MCOREI7-AVX || MATOM) || X86_64 || MNATIVE
+ 
+ config X86_CMPXCHG64
+ 	def_bool y
+-	depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM
++	depends on X86_PAE || X86_64 || MCORE2 || MCOREI7 || MCOREI7AVX || MCOREAVXI || MCOREAVX2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM || MNATIVE
+ 
+ # this should be set for all -march=.. options where the compiler
+ # generates cmov.
+ config X86_CMOV
+ 	def_bool y
+-	depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX)
++	depends on (MK8 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MJAGUAR || MK7 || MCORE2 || MCOREI7 || MCOREI7AVX || MCOREAVXI || MCOREAVX2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MNATIVE || MATOM || MGEODE_LX)
+ 
+ config X86_MINIMUM_CPU_FAMILY
+ 	int
+diff -uprN a/arch/x86/Makefile b/arch/x86/Makefile
+--- a/arch/x86/Makefile	2013-11-03 18:41:51.000000000 -0500
++++ b/arch/x86/Makefile	2013-12-15 06:21:24.354455723 -0500
+@@ -61,11 +61,26 @@ else
+ 	KBUILD_CFLAGS += $(call cc-option,-mno-sse -mpreferred-stack-boundary=3)
+ 
+         # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
++        cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native)
+         cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
++        cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10)
++        cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona)
++        cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1)
++        cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1)
++        cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2)
++        cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2)
+         cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
+ 
+         cflags-$(CONFIG_MCORE2) += \
+-                $(call cc-option,-march=core2,$(call cc-option,-mtune=generic))
++                $(call cc-option,-march=core2,$(call cc-option,-mtune=core2))
++        cflags-$(CONFIG_MCOREI7) += \
++                $(call cc-option,-march=corei7,$(call cc-option,-mtune=corei7))
++        cflags-$(CONFIG_MCOREI7AVX) += \
++                $(call cc-option,-march=corei7-avx,$(call cc-option,-mtune=corei7-avx))
++        cflags-$(CONFIG_MCOREAVXI) += \
++                $(call cc-option,-march=core-avx-i,$(call cc-option,-mtune=core-avx-i))
++        cflags-$(CONFIG_MCOREAVX2) += \
++                $(call cc-option,-march=core-avx2,$(call cc-option,-mtune=core-avx2))
+ 	cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom) \
+ 		$(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
+         cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic)
+diff -uprN a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
+--- a/arch/x86/Makefile_32.cpu	2013-11-03 18:41:51.000000000 -0500
++++ b/arch/x86/Makefile_32.cpu	2013-12-15 06:21:24.354455723 -0500
+@@ -23,7 +23,14 @@ cflags-$(CONFIG_MK6)		+= -march=k6
+ # Please note, that patches that add -march=athlon-xp and friends are pointless.
+ # They make zero difference whatsosever to performance at this time.
+ cflags-$(CONFIG_MK7)		+= -march=athlon
++cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native)
+ cflags-$(CONFIG_MK8)		+= $(call cc-option,-march=k8,-march=athlon)
++cflags-$(CONFIG_MK10)	+= $(call cc-option,-march=amdfam10,-march=athlon)
++cflags-$(CONFIG_MBARCELONA)	+= $(call cc-option,-march=barcelona,-march=athlon)
++cflags-$(CONFIG_MBOBCAT)	+= $(call cc-option,-march=btver1,-march=athlon)
++cflags-$(CONFIG_MBULLDOZER)	+= $(call cc-option,-march=bdver1,-march=athlon)
++cflags-$(CONFIG_MPILEDRIVER)	+= $(call cc-option,-march=bdver2,-march=athlon)
++cflags-$(CONFIG_MJAGUAR)	+= $(call cc-option,-march=btver2,-march=athlon)
+ cflags-$(CONFIG_MCRUSOE)	+= -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
+ cflags-$(CONFIG_MEFFICEON)	+= -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
+ cflags-$(CONFIG_MWINCHIPC6)	+= $(call cc-option,-march=winchip-c6,-march=i586)
+@@ -32,6 +39,10 @@ cflags-$(CONFIG_MCYRIXIII)	+= $(call cc-
+ cflags-$(CONFIG_MVIAC3_2)	+= $(call cc-option,-march=c3-2,-march=i686)
+ cflags-$(CONFIG_MVIAC7)		+= -march=i686
+ cflags-$(CONFIG_MCORE2)		+= -march=i686 $(call tune,core2)
++cflags-$(CONFIG_MCOREI7)	+= -march=i686 $(call tune,corei7)
++cflags-$(CONFIG_MCOREI7AVX)	+= -march=i686 $(call tune,corei7-avx)
++cflags-$(CONFIG_MCOREAVXI)	+= -march=i686 $(call tune,core-avx-i)
++cflags-$(CONFIG_MCOREAVX2)	+= -march=i686 $(call tune,core-avx2)
+ cflags-$(CONFIG_MATOM)		+= $(call cc-option,-march=atom,$(call cc-option,-march=core2,-march=i686)) \
+ 	$(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))

diff --git a/5010_enable-additional-cpu-optimizations-for-gcc-4.9.patch b/5010_enable-additional-cpu-optimizations-for-gcc-4.9.patch
new file mode 100644
index 0000000..c4efd06
--- /dev/null
+++ b/5010_enable-additional-cpu-optimizations-for-gcc-4.9.patch
@@ -0,0 +1,402 @@
+WARNING - this version of the patch works with version 4.9+ of gcc and with
+kernel version 3.15.x+ and should NOT be applied when compiling on older
+versions due to name changes of the flags with the 4.9 release of gcc.
+Use the older version of this patch hosted on the same github for older
+versions of gcc. For example:
+
+corei7 --> nehalem
+corei7-avx --> sandybridge
+core-avx-i --> ivybridge
+core-avx2 --> haswell
+
+For more, see: https://gcc.gnu.org/gcc-4.9/changes.html
+
+It also changes 'atom' to 'bonnell' in accordance with the gcc v4.9 changes.
+Note that upstream is using the deprecated 'match=atom' flags when I believe it
+should use the newer 'march=bonnell' flag for atom processors.
+
+I have made that change to this patch set as well.  See the following kernel
+bug report to see if I'm right: https://bugzilla.kernel.org/show_bug.cgi?id=77461
+
+This patch will expand the number of microarchitectures to include newer
+processors including: AMD K10-family, AMD Family 10h (Barcelona), AMD Family
+14h (Bobcat), AMD Family 15h (Bulldozer), AMD Family 15h (Piledriver), AMD
+Family 16h (Jaguar), Intel 1st Gen Core i3/i5/i7 (Nehalem), Intel 1.5 Gen Core
+i3/i5/i7 (Westmere), Intel 2nd Gen Core i3/i5/i7 (Sandybridge), Intel 3rd Gen
+Core i3/i5/i7 (Ivybridge), Intel 4th Gen Core i3/i5/i7 (Haswell), Intel 5th
+Gen Core i3/i5/i7 (Broadwell), and the low power Silvermont series of Atom
+processors (Silvermont). It also offers the compiler the 'native' flag.
+
+Small but real speed increases are measurable using a make endpoint comparing
+a generic kernel to one built with one of the respective microarchs.
+
+See the following experimental evidence supporting this statement:
+https://github.com/graysky2/kernel_gcc_patch
+
+REQUIREMENTS
+linux version >=3.15
+gcc version >=4.9
+
+--- a/arch/x86/include/asm/module.h	2014-06-16 16:44:27.000000000 -0400
++++ b/arch/x86/include/asm/module.h	2015-03-07 03:27:32.556672424 -0500
+@@ -15,6 +15,22 @@
+ #define MODULE_PROC_FAMILY "586MMX "
+ #elif defined CONFIG_MCORE2
+ #define MODULE_PROC_FAMILY "CORE2 "
++#elif defined CONFIG_MNATIVE
++#define MODULE_PROC_FAMILY "NATIVE "
++#elif defined CONFIG_MNEHALEM
++#define MODULE_PROC_FAMILY "NEHALEM "
++#elif defined CONFIG_MWESTMERE
++#define MODULE_PROC_FAMILY "WESTMERE "
++#elif defined CONFIG_MSILVERMONT
++#define MODULE_PROC_FAMILY "SILVERMONT "
++#elif defined CONFIG_MSANDYBRIDGE
++#define MODULE_PROC_FAMILY "SANDYBRIDGE "
++#elif defined CONFIG_MIVYBRIDGE
++#define MODULE_PROC_FAMILY "IVYBRIDGE "
++#elif defined CONFIG_MHASWELL
++#define MODULE_PROC_FAMILY "HASWELL "
++#elif defined CONFIG_MBROADWELL
++#define MODULE_PROC_FAMILY "BROADWELL "
+ #elif defined CONFIG_MATOM
+ #define MODULE_PROC_FAMILY "ATOM "
+ #elif defined CONFIG_M686
+@@ -33,6 +49,20 @@
+ #define MODULE_PROC_FAMILY "K7 "
+ #elif defined CONFIG_MK8
+ #define MODULE_PROC_FAMILY "K8 "
++#elif defined CONFIG_MK8SSE3
++#define MODULE_PROC_FAMILY "K8SSE3 "
++#elif defined CONFIG_MK10
++#define MODULE_PROC_FAMILY "K10 "
++#elif defined CONFIG_MBARCELONA
++#define MODULE_PROC_FAMILY "BARCELONA "
++#elif defined CONFIG_MBOBCAT
++#define MODULE_PROC_FAMILY "BOBCAT "
++#elif defined CONFIG_MBULLDOZER
++#define MODULE_PROC_FAMILY "BULLDOZER "
++#elif defined CONFIG_MPILEDRIVER
++#define MODULE_PROC_FAMILY "PILEDRIVER "
++#elif defined CONFIG_MJAGUAR
++#define MODULE_PROC_FAMILY "JAGUAR "
+ #elif defined CONFIG_MELAN
+ #define MODULE_PROC_FAMILY "ELAN "
+ #elif defined CONFIG_MCRUSOE
+--- a/arch/x86/Kconfig.cpu	2014-06-16 16:44:27.000000000 -0400
++++ b/arch/x86/Kconfig.cpu	2015-03-07 03:32:14.337713226 -0500
+@@ -137,9 +137,8 @@ config MPENTIUM4
+ 		-Paxville
+ 		-Dempsey
+ 
+-
+ config MK6
+-	bool "K6/K6-II/K6-III"
++	bool "AMD K6/K6-II/K6-III"
+ 	depends on X86_32
+ 	---help---
+ 	  Select this for an AMD K6-family processor.  Enables use of
+@@ -147,7 +146,7 @@ config MK6
+ 	  flags to GCC.
+ 
+ config MK7
+-	bool "Athlon/Duron/K7"
++	bool "AMD Athlon/Duron/K7"
+ 	depends on X86_32
+ 	---help---
+ 	  Select this for an AMD Athlon K7-family processor.  Enables use of
+@@ -155,12 +154,62 @@ config MK7
+ 	  flags to GCC.
+ 
+ config MK8
+-	bool "Opteron/Athlon64/Hammer/K8"
++	bool "AMD Opteron/Athlon64/Hammer/K8"
+ 	---help---
+ 	  Select this for an AMD Opteron or Athlon64 Hammer-family processor.
+ 	  Enables use of some extended instructions, and passes appropriate
+ 	  optimization flags to GCC.
+ 
++config MK8SSE3
++	bool "AMD Opteron/Athlon64/Hammer/K8 with SSE3"
++	---help---
++	  Select this for improved AMD Opteron or Athlon64 Hammer-family processors.
++	  Enables use of some extended instructions, and passes appropriate
++	  optimization flags to GCC.
++
++config MK10
++	bool "AMD 61xx/7x50/PhenomX3/X4/II/K10"
++	---help---
++	  Select this for an AMD 61xx Eight-Core Magny-Cours, Athlon X2 7x50,
++		Phenom X3/X4/II, Athlon II X2/X3/X4, or Turion II-family processor.
++	  Enables use of some extended instructions, and passes appropriate
++	  optimization flags to GCC.
++
++config MBARCELONA
++	bool "AMD Barcelona"
++	---help---
++	  Select this for AMD Barcelona and newer processors.
++
++	  Enables -march=barcelona
++
++config MBOBCAT
++	bool "AMD Bobcat"
++	---help---
++	  Select this for AMD Bobcat processors.
++
++	  Enables -march=btver1
++
++config MBULLDOZER
++	bool "AMD Bulldozer"
++	---help---
++	  Select this for AMD Bulldozer processors.
++
++	  Enables -march=bdver1
++
++config MPILEDRIVER
++	bool "AMD Piledriver"
++	---help---
++	  Select this for AMD Piledriver processors.
++
++	  Enables -march=bdver2
++
++config MJAGUAR
++	bool "AMD Jaguar"
++	---help---
++	  Select this for AMD Jaguar processors.
++
++	  Enables -march=btver2
++
+ config MCRUSOE
+ 	bool "Crusoe"
+ 	depends on X86_32
+@@ -251,8 +300,17 @@ config MPSC
+ 	  using the cpu family field
+ 	  in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one.
+ 
++config MATOM
++	bool "Intel Atom"
++	---help---
++
++	  Select this for the Intel Atom platform. Intel Atom CPUs have an
++	  in-order pipelining architecture and thus can benefit from
++	  accordingly optimized code. Use a recent GCC with specific Atom
++	  support in order to fully benefit from selecting this option.
++
+ config MCORE2
+-	bool "Core 2/newer Xeon"
++	bool "Intel Core 2"
+ 	---help---
+ 
+ 	  Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and
+@@ -260,14 +318,63 @@ config MCORE2
+ 	  family in /proc/cpuinfo. Newer ones have 6 and older ones 15
+ 	  (not a typo)
+ 
+-config MATOM
+-	bool "Intel Atom"
++	  Enables -march=core2
++
++config MNEHALEM
++	bool "Intel Nehalem"
+ 	---help---
+ 
+-	  Select this for the Intel Atom platform. Intel Atom CPUs have an
+-	  in-order pipelining architecture and thus can benefit from
+-	  accordingly optimized code. Use a recent GCC with specific Atom
+-	  support in order to fully benefit from selecting this option.
++	  Select this for 1st Gen Core processors in the Nehalem family.
++
++	  Enables -march=nehalem
++
++config MWESTMERE
++	bool "Intel Westmere"
++	---help---
++
++	  Select this for the Intel Westmere formerly Nehalem-C family.
++
++	  Enables -march=westmere
++
++config MSILVERMONT
++	bool "Intel Silvermont"
++	---help---
++
++	  Select this for the Intel Silvermont platform.
++
++	  Enables -march=silvermont
++
++config MSANDYBRIDGE
++	bool "Intel Sandy Bridge"
++	---help---
++
++	  Select this for 2nd Gen Core processors in the Sandy Bridge family.
++
++	  Enables -march=sandybridge
++
++config MIVYBRIDGE
++	bool "Intel Ivy Bridge"
++	---help---
++
++	  Select this for 3rd Gen Core processors in the Ivy Bridge family.
++
++	  Enables -march=ivybridge
++
++config MHASWELL
++	bool "Intel Haswell"
++	---help---
++
++	  Select this for 4th Gen Core processors in the Haswell family.
++
++	  Enables -march=haswell
++
++config MBROADWELL
++	bool "Intel Broadwell"
++	---help---
++
++	  Select this for 5th Gen Core processors in the Broadwell family.
++
++	  Enables -march=broadwell
+ 
+ config GENERIC_CPU
+ 	bool "Generic-x86-64"
+@@ -276,6 +383,19 @@ config GENERIC_CPU
+ 	  Generic x86-64 CPU.
+ 	  Run equally well on all x86-64 CPUs.
+ 
++config MNATIVE
++ bool "Native optimizations autodetected by GCC"
++ ---help---
++
++   GCC 4.2 and above support -march=native, which automatically detects
++   the optimum settings to use based on your processor. -march=native 
++   also detects and applies additional settings beyond -march specific
++   to your CPU, (eg. -msse4). Unless you have a specific reason not to
++   (e.g. distcc cross-compiling), you should probably be using
++   -march=native rather than anything listed below.
++
++   Enables -march=native
++
+ endchoice
+ 
+ config X86_GENERIC
+@@ -300,7 +420,7 @@ config X86_INTERNODE_CACHE_SHIFT
+ config X86_L1_CACHE_SHIFT
+ 	int
+ 	default "7" if MPENTIUM4 || MPSC
+-	default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
++	default "6" if MK7 || MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MJAGUAR || MPENTIUMM || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || BROADWELL || MNATIVE || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
+ 	default "4" if MELAN || M486 || MGEODEGX1
+ 	default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+ 
+@@ -331,11 +451,11 @@ config X86_ALIGNMENT_16
+ 
+ config X86_INTEL_USERCOPY
+ 	def_bool y
+-	depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2
++	depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK8SSE3 || MK7 || MEFFICEON || MCORE2 || MK10 || MBARCELONA || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MNATIVE
+ 
+ config X86_USE_PPRO_CHECKSUM
+ 	def_bool y
+-	depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM
++	depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MK10 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MATOM || MNATIVE
+ 
+ config X86_USE_3DNOW
+ 	def_bool y
+@@ -359,17 +479,17 @@ config X86_P6_NOP
+ 
+ config X86_TSC
+ 	def_bool y
+-	depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64
++	depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MNATIVE || MATOM) || X86_64
+ 
+ config X86_CMPXCHG64
+ 	def_bool y
+-	depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM
++	depends on X86_PAE || X86_64 || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM || MNATIVE
+ 
+ # this should be set for all -march=.. options where the compiler
+ # generates cmov.
+ config X86_CMOV
+ 	def_bool y
+-	depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX)
++	depends on (MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MJAGUAR || MK7 || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MNATIVE || MATOM || MGEODE_LX)
+ 
+ config X86_MINIMUM_CPU_FAMILY
+ 	int
+--- a/arch/x86/Makefile	2014-06-16 16:44:27.000000000 -0400
++++ b/arch/x86/Makefile	2015-03-07 03:33:27.650843211 -0500
+@@ -92,13 +92,35 @@ else
+ 	KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
+ 
+         # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
++        cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native)
+         cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
++        cflags-$(CONFIG_MK8SSE3) += $(call cc-option,-march=k8-sse3,-mtune=k8)
++        cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10)
++        cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona)
++        cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1)
++        cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1)
++        cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2)
++        cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2)
+         cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
+ 
+         cflags-$(CONFIG_MCORE2) += \
+-                $(call cc-option,-march=core2,$(call cc-option,-mtune=generic))
+-	cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom) \
+-		$(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
++                $(call cc-option,-march=core2,$(call cc-option,-mtune=core2))
++        cflags-$(CONFIG_MNEHALEM) += \
++                $(call cc-option,-march=nehalem,$(call cc-option,-mtune=nehalem))
++        cflags-$(CONFIG_MWESTMERE) += \
++                $(call cc-option,-march=westmere,$(call cc-option,-mtune=westmere))
++        cflags-$(CONFIG_MSILVERMONT) += \
++                $(call cc-option,-march=silvermont,$(call cc-option,-mtune=silvermont))
++        cflags-$(CONFIG_MSANDYBRIDGE) += \
++                $(call cc-option,-march=sandybridge,$(call cc-option,-mtune=sandybridge))
++        cflags-$(CONFIG_MIVYBRIDGE) += \
++                $(call cc-option,-march=ivybridge,$(call cc-option,-mtune=ivybridge))
++        cflags-$(CONFIG_MHASWELL) += \
++                $(call cc-option,-march=haswell,$(call cc-option,-mtune=haswell))
++        cflags-$(CONFIG_MBROADWELL) += \
++                $(call cc-option,-march=broadwell,$(call cc-option,-mtune=broadwell))
++        cflags-$(CONFIG_MATOM) += $(call cc-option,-march=bonnell) \
++                $(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic))
+         cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic)
+         KBUILD_CFLAGS += $(cflags-y)
+ 
+--- a/arch/x86/Makefile_32.cpu	2014-06-16 16:44:27.000000000 -0400
++++ b/arch/x86/Makefile_32.cpu	2015-03-07 03:34:15.203586024 -0500
+@@ -23,7 +23,15 @@ cflags-$(CONFIG_MK6)		+= -march=k6
+ # Please note, that patches that add -march=athlon-xp and friends are pointless.
+ # They make zero difference whatsosever to performance at this time.
+ cflags-$(CONFIG_MK7)		+= -march=athlon
++cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native)
+ cflags-$(CONFIG_MK8)		+= $(call cc-option,-march=k8,-march=athlon)
++cflags-$(CONFIG_MK8SSE3)		+= $(call cc-option,-march=k8-sse3,-march=athlon)
++cflags-$(CONFIG_MK10)	+= $(call cc-option,-march=amdfam10,-march=athlon)
++cflags-$(CONFIG_MBARCELONA)	+= $(call cc-option,-march=barcelona,-march=athlon)
++cflags-$(CONFIG_MBOBCAT)	+= $(call cc-option,-march=btver1,-march=athlon)
++cflags-$(CONFIG_MBULLDOZER)	+= $(call cc-option,-march=bdver1,-march=athlon)
++cflags-$(CONFIG_MPILEDRIVER)	+= $(call cc-option,-march=bdver2,-march=athlon)
++cflags-$(CONFIG_MJAGUAR)	+= $(call cc-option,-march=btver2,-march=athlon)
+ cflags-$(CONFIG_MCRUSOE)	+= -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
+ cflags-$(CONFIG_MEFFICEON)	+= -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
+ cflags-$(CONFIG_MWINCHIPC6)	+= $(call cc-option,-march=winchip-c6,-march=i586)
+@@ -32,8 +40,15 @@ cflags-$(CONFIG_MCYRIXIII)	+= $(call cc-
+ cflags-$(CONFIG_MVIAC3_2)	+= $(call cc-option,-march=c3-2,-march=i686)
+ cflags-$(CONFIG_MVIAC7)		+= -march=i686
+ cflags-$(CONFIG_MCORE2)		+= -march=i686 $(call tune,core2)
+-cflags-$(CONFIG_MATOM)		+= $(call cc-option,-march=atom,$(call cc-option,-march=core2,-march=i686)) \
+-	$(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
++cflags-$(CONFIG_MNEHALEM)	+= -march=i686 $(call tune,nehalem)
++cflags-$(CONFIG_MWESTMERE)	+= -march=i686 $(call tune,westmere)
++cflags-$(CONFIG_MSILVERMONT)	+= -march=i686 $(call tune,silvermont)
++cflags-$(CONFIG_MSANDYBRIDGE)	+= -march=i686 $(call tune,sandybridge)
++cflags-$(CONFIG_MIVYBRIDGE)	+= -march=i686 $(call tune,ivybridge)
++cflags-$(CONFIG_MHASWELL)	+= -march=i686 $(call tune,haswell)
++cflags-$(CONFIG_MBROADWELL)	+= -march=i686 $(call tune,broadwell)
++cflags-$(CONFIG_MATOM)		+= $(call cc-option,-march=bonnell,$(call cc-option,-march=core2,-march=i686)) \
++	$(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic))
+ 
+ # AMD Elan support
+ cflags-$(CONFIG_MELAN)		+= -march=i486
+

diff --git a/5015_kdbus-8-12-2015.patch b/5015_kdbus-8-12-2015.patch
new file mode 100644
index 0000000..4e018f2
--- /dev/null
+++ b/5015_kdbus-8-12-2015.patch
@@ -0,0 +1,34349 @@
+diff --git a/Documentation/Makefile b/Documentation/Makefile
+index bc05482..e2127a7 100644
+--- a/Documentation/Makefile
++++ b/Documentation/Makefile
+@@ -1,4 +1,4 @@
+ subdir-y := accounting auxdisplay blackfin connector \
+-	filesystems filesystems ia64 laptops mic misc-devices \
++	filesystems filesystems ia64 kdbus laptops mic misc-devices \
+ 	networking pcmcia prctl ptp spi timers vDSO video4linux \
+ 	watchdog
+diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
+index 51f4221..ec7c81b 100644
+--- a/Documentation/ioctl/ioctl-number.txt
++++ b/Documentation/ioctl/ioctl-number.txt
+@@ -292,6 +292,7 @@ Code  Seq#(hex)	Include File		Comments
+ 0x92	00-0F	drivers/usb/mon/mon_bin.c
+ 0x93	60-7F	linux/auto_fs.h
+ 0x94	all	fs/btrfs/ioctl.h
++0x95	all	uapi/linux/kdbus.h	kdbus IPC driver
+ 0x97	00-7F	fs/ceph/ioctl.h		Ceph file system
+ 0x99	00-0F				537-Addinboard driver
+ 					<mailto:buk@buks.ipn.de>
+diff --git a/Documentation/kdbus/.gitignore b/Documentation/kdbus/.gitignore
+new file mode 100644
+index 0000000..b4a77cc
+--- /dev/null
++++ b/Documentation/kdbus/.gitignore
+@@ -0,0 +1,2 @@
++*.7
++*.html
+diff --git a/Documentation/kdbus/Makefile b/Documentation/kdbus/Makefile
+new file mode 100644
+index 0000000..8caffe5
+--- /dev/null
++++ b/Documentation/kdbus/Makefile
+@@ -0,0 +1,44 @@
++DOCS :=	\
++	kdbus.xml		\
++	kdbus.bus.xml		\
++	kdbus.connection.xml	\
++	kdbus.endpoint.xml	\
++	kdbus.fs.xml		\
++	kdbus.item.xml		\
++	kdbus.match.xml		\
++	kdbus.message.xml	\
++	kdbus.name.xml		\
++	kdbus.policy.xml	\
++	kdbus.pool.xml
++
++XMLFILES := $(addprefix $(obj)/,$(DOCS))
++MANFILES := $(patsubst %.xml, %.7, $(XMLFILES))
++HTMLFILES := $(patsubst %.xml, %.html, $(XMLFILES))
++
++XMLTO_ARGS := -m $(srctree)/$(src)/stylesheet.xsl --skip-validation
++
++quiet_cmd_db2man = MAN     $@
++      cmd_db2man = xmlto man $(XMLTO_ARGS) -o $(obj) $<
++%.7: %.xml
++	@(which xmlto > /dev/null 2>&1) || \
++	 (echo "*** You need to install xmlto ***"; \
++	  exit 1)
++	$(call cmd,db2man)
++
++quiet_cmd_db2html = HTML    $@
++      cmd_db2html = xmlto html-nochunks $(XMLTO_ARGS) -o $(obj) $<
++%.html: %.xml
++	@(which xmlto > /dev/null 2>&1) || \
++	 (echo "*** You need to install xmlto ***"; \
++	  exit 1)
++	$(call cmd,db2html)
++
++mandocs: $(MANFILES)
++
++htmldocs: $(HTMLFILES)
++
++clean-files := $(MANFILES) $(HTMLFILES)
++
++# we don't support other %docs targets right now
++%docs:
++	@true
+diff --git a/Documentation/kdbus/kdbus.bus.xml b/Documentation/kdbus/kdbus.bus.xml
+new file mode 100644
+index 0000000..83f1198
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.bus.xml
+@@ -0,0 +1,344 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.bus">
++
++  <refentryinfo>
++    <title>kdbus.bus</title>
++    <productname>kdbus.bus</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.bus</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.bus</refname>
++    <refpurpose>kdbus bus</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>
++      A bus is a resource that is shared between connections in order to
++      transmit messages (see
++      <citerefentry>
++        <refentrytitle>kdbus.message</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>).
++      Each bus is independent, and operations on the bus will not have any
++      effect on other buses. A bus is a management entity that controls the
++      addresses of its connections, their policies and message transactions
++      performed via this bus.
++    </para>
++    <para>
++      Each bus is bound to the mount instance it was created on. It has a
++      custom name that is unique across all buses of a domain. In
++      <citerefentry>
++        <refentrytitle>kdbus.fs</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      a bus is presented as a directory. No operations can be performed on
++      the bus itself; instead you need to perform the operations on an endpoint
++      associated with the bus. Endpoints are accessible as files underneath the
++      bus directory. A default endpoint called <constant>bus</constant> is
++      provided on each bus.
++    </para>
++    <para>
++      Bus names may be chosen freely except for one restriction: the name must
++      be prefixed with the numeric effective UID of the creator and a dash. This
++      is required to avoid namespace clashes between different users. When
++      creating a bus, the name that is passed in must be properly formatted, or
++      the kernel will refuse creation of the bus. Example:
++      <literal>1047-foobar</literal> is an acceptable name for a bus
++      registered by a user with UID 1047. However,
++      <literal>1024-foobar</literal> is not, and neither is
++      <literal>foobar</literal>. The UID must be provided in the
++      user-namespace of the bus owner.
++    </para>
++    <para>
++      To create a new bus, you need to open the control file of a domain and
++      employ the <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl. The control
++      file descriptor that was used to issue
++      <constant>KDBUS_CMD_BUS_MAKE</constant> must not previously have been
++      used for any other control-ioctl and must be kept open for the entire
++      life-time of the created bus. Closing it will immediately cleanup the
++      entire bus and all its associated resources and endpoints. Every control
++      file descriptor can only be used to create a single new bus; from that
++      point on, it is not used for any further communication until the final
++      <citerefentry>
++        <refentrytitle>close</refentrytitle>
++        <manvolnum>2</manvolnum>
++      </citerefentry>
++      .
++    </para>
++    <para>
++      Each bus will generate a random, 128-bit UUID upon creation. This UUID
++      will be returned to creators of connections through
++      <varname>kdbus_cmd_hello.id128</varname> and can be used to uniquely
++      identify buses, even across different machines or containers. The UUID
++      will have its variant bits set to <literal>DCE</literal>, and denote
++      version 4 (random). For more details on UUIDs, see <ulink
++      url="https://en.wikipedia.org/wiki/Universally_unique_identifier">
++      the Wikipedia article on UUIDs</ulink>.
++    </para>
++
++  </refsect1>
++
++  <refsect1>
++    <title>Creating buses</title>
++    <para>
++      To create a new bus, the <constant>KDBUS_CMD_BUS_MAKE</constant>
++      command is used. It takes a <type>struct kdbus_cmd</type> argument.
++    </para>
++    <programlisting>
++struct kdbus_cmd {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>The flags for creation.</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_MAKE_ACCESS_GROUP</constant></term>
++              <listitem>
++                <para>Make the bus file group-accessible.</para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_MAKE_ACCESS_WORLD</constant></term>
++              <listitem>
++                <para>Make the bus file world-accessible.</para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Requests a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will return
++                  <errorcode>0</errorcode>, and the <varname>flags</varname>
++                  field will have all bits set that are valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            The following items (see
++            <citerefentry>
++              <refentrytitle>kdbus.item</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>)
++            are expected for <constant>KDBUS_CMD_BUS_MAKE</constant>.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_MAKE_NAME</constant></term>
++              <listitem>
++                <para>
++                  Contains a null-terminated string that identifies the
++                  bus. The name must be unique across the kdbus domain and
++                  must start with the effective UID of the caller, followed by
++                  a '<literal>-</literal>' (dash). This item is mandatory.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_BLOOM_PARAMETER</constant></term>
++              <listitem>
++                <para>
++                  Bus-wide bloom parameters passed in a
++                  <type>struct kdbus_bloom_parameter</type>. These settings are
++                  copied back to new connections verbatim. This item is
++                  mandatory. See
++                  <citerefentry>
++                    <refentrytitle>kdbus.item</refentrytitle>
++                    <manvolnum>7</manvolnum>
++                  </citerefentry>
++                  for a more detailed description of this item.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term>
++              <listitem>
++                <para>
++                  An optional item that contains a set of attach flags that are
++                  returned to connections when they query the bus creator
++                  metadata. If not set, no metadata is returned.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++              <listitem><para>
++                With this item, programs can <emphasis>probe</emphasis> the
++                kernel for known item types. See
++                <citerefentry>
++                  <refentrytitle>kdbus.item</refentrytitle>
++                  <manvolnum>7</manvolnum>
++                </citerefentry>
++                for more details.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      Unrecognized items are rejected, and the ioctl will fail with
++      <varname>errno</varname> set to <constant>EINVAL</constant>.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>
++      On success, all mentioned ioctl commands return <errorcode>0</errorcode>;
++      on error, <errorcode>-1</errorcode> is returned, and
++      <varname>errno</varname> is set to indicate the error.
++      If the issued ioctl is illegal for the file descriptor used,
++      <varname>errno</varname> will be set to <constant>ENOTTY</constant>.
++    </para>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_BUS_MAKE</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EBADMSG</constant></term>
++          <listitem><para>
++            A mandatory item is missing.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            The flags supplied in the <constant>struct kdbus_cmd</constant>
++            are invalid or the supplied name does not start with the current
++            UID and a '<literal>-</literal>' (dash).
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EEXIST</constant></term>
++          <listitem><para>
++            A bus of that name already exists.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ESHUTDOWN</constant></term>
++          <listitem><para>
++            The kdbus mount instance for the bus was already shut down.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EMFILE</constant></term>
++          <listitem><para>
++            The maximum number of buses for the current user is exhausted.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.fs</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.connection.xml b/Documentation/kdbus/kdbus.connection.xml
+new file mode 100644
+index 0000000..4bb5f30
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.connection.xml
+@@ -0,0 +1,1244 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.connection">
++
++  <refentryinfo>
++    <title>kdbus.connection</title>
++    <productname>kdbus.connection</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.connection</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.connection</refname>
++    <refpurpose>kdbus connection</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>
++      Connections are identified by their <emphasis>connection ID</emphasis>,
++      internally implemented as a <type>uint64_t</type> counter.
++      The IDs of every newly created bus start at <constant>1</constant>, and
++      every new connection will increment the counter by <constant>1</constant>.
++      The IDs are not reused.
++    </para>
++    <para>
++      In higher level tools, the user visible representation of a connection is
++      defined by the D-Bus protocol specification as
++      <constant>":1.&lt;ID&gt;"</constant>.
++    </para>
++    <para>
++      Messages with a specific <type>uint64_t</type> destination ID are
++      directly delivered to the connection with the corresponding ID. Signal
++      messages (see
++      <citerefentry>
++        <refentrytitle>kdbus.message</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>)
++      may be addressed to the special destination ID
++      <constant>KDBUS_DST_ID_BROADCAST</constant> (~0ULL) and will then
++      potentially be delivered to all currently active connections on the bus.
++      However, in order to receive any signal messages, clients must subscribe
++      to them by installing a match (see
++      <citerefentry>
++        <refentrytitle>kdbus.match</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>).
++    </para>
++    <para>
++      Messages synthesized and sent directly by the kernel will carry the
++      special source ID <constant>KDBUS_SRC_ID_KERNEL</constant> (0).
++    </para>
++    <para>
++      In addition to the unique <type>uint64_t</type> connection ID,
++      established connections can request the ownership of
++      <emphasis>well-known names</emphasis>, under which they can be found and
++      addressed by other bus clients. A well-known name is associated with one
++      and only one connection at a time. See
++      <citerefentry>
++        <refentrytitle>kdbus.name</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      on name acquisition, the name registry, and the validity of names.
++    </para>
++    <para>
++      Messages can specify the special destination ID
++      <constant>KDBUS_DST_ID_NAME</constant> (0) and carry a well-known name
++      in the message data. Such a message is delivered to the destination
++      connection which owns that well-known name.
++    </para>
++
++    <programlisting><![CDATA[
++  +-------------------------------------------------------------------------+
++  | +---------------+     +---------------------------+                     |
++  | | Connection    |     | Message                   | -----------------+  |
++  | | :1.22         | --> | src: 22                   |                  |  |
++  | |               |     | dst: 25                   |                  |  |
++  | |               |     |                           |                  |  |
++  | |               |     |                           |                  |  |
++  | |               |     +---------------------------+                  |  |
++  | |               |                                                    |  |
++  | |               | <--------------------------------------+           |  |
++  | +---------------+                                        |           |  |
++  |                                                          |           |  |
++  | +---------------+     +---------------------------+      |           |  |
++  | | Connection    |     | Message                   | -----+           |  |
++  | | :1.25         | --> | src: 25                   |                  |  |
++  | |               |     | dst: 0xffffffffffffffff   | -------------+   |  |
++  | |               |     |  (KDBUS_DST_ID_BROADCAST) |              |   |  |
++  | |               |     |                           | ---------+   |   |  |
++  | |               |     +---------------------------+          |   |   |  |
++  | |               |                                            |   |   |  |
++  | |               | <--------------------------------------------------+  |
++  | +---------------+                                            |   |      |
++  |                                                              |   |      |
++  | +---------------+     +---------------------------+          |   |      |
++  | | Connection    |     | Message                   | --+      |   |      |
++  | | :1.55         | --> | src: 55                   |   |      |   |      |
++  | |               |     | dst: 0 / org.foo.bar      |   |      |   |      |
++  | |               |     |                           |   |      |   |      |
++  | |               |     |                           |   |      |   |      |
++  | |               |     +---------------------------+   |      |   |      |
++  | |               |                                     |      |   |      |
++  | |               | <------------------------------------------+   |      |
++  | +---------------+                                     |          |      |
++  |                                                       |          |      |
++  | +---------------+                                     |          |      |
++  | | Connection    |                                     |          |      |
++  | | :1.81         |                                     |          |      |
++  | | org.foo.bar   |                                     |          |      |
++  | |               |                                     |          |      |
++  | |               |                                     |          |      |
++  | |               | <-----------------------------------+          |      |
++  | |               |                                                |      |
++  | |               | <----------------------------------------------+      |
++  | +---------------+                                                       |
++  +-------------------------------------------------------------------------+
++    ]]></programlisting>
++  </refsect1>
++
++  <refsect1>
++    <title>Privileged connections</title>
++    <para>
++      A connection is considered <emphasis>privileged</emphasis> if the user
++      it was created by is the same that created the bus, or if the creating
++      task had <constant>CAP_IPC_OWNER</constant> set when it called
++      <constant>KDBUS_CMD_HELLO</constant> (see below).
++    </para>
++    <para>
++      Privileged connections have permission to employ certain restricted
++      functions and commands, which are explained below and in other kdbus
++      man-pages.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Activator and policy holder connection</title>
++    <para>
++      An <emphasis>activator</emphasis> connection is a placeholder for a
++      <emphasis>well-known name</emphasis>. Messages sent to such a connection
++      can be used to start an implementer connection, which will then get all
++      the messages from the activator copied over. An activator connection
++      cannot be used to send any message.
++    </para>
++    <para>
++      A <emphasis>policy holder</emphasis> connection only installs a policy
++      for one or more names. These policy entries are kept active as long as
++      the connection is alive, and are removed once it terminates. Such a
++      policy connection type can be used to deploy restrictions for names that
++      are not yet active on the bus. A policy holder connection cannot be used
++      to send any message.
++    </para>
++    <para>
++      The creation of activator or policy holder connections is restricted to
++      privileged users on the bus (see above).
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Monitor connections</title>
++    <para>
++      Monitors are eavesdropping connections that receive all the traffic on the
++      bus, but is invisible to other connections. Such connections have all
++      properties of any other, regular connection, except for the following
++      details:
++    </para>
++
++    <itemizedlist>
++      <listitem><para>
++        They will get every message sent over the bus, both unicasts and
++        broadcasts.
++      </para></listitem>
++
++      <listitem><para>
++        Installing matches for signal messages is neither necessary
++        nor allowed.
++      </para></listitem>
++
++      <listitem><para>
++        They cannot send messages or be directly addressed as receiver.
++      </para></listitem>
++
++      <listitem><para>
++        They cannot own well-known names. Therefore, they also can't operate as
++        activators.
++      </para></listitem>
++
++      <listitem><para>
++        Their creation and destruction will not cause
++        <constant>KDBUS_ITEM_ID_{ADD,REMOVE}</constant> (see
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>).
++      </para></listitem>
++
++      <listitem><para>
++        They are not listed with their unique name in name registry dumps
++        (see <constant>KDBUS_CMD_NAME_LIST</constant> in
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>), so other connections cannot detect the presence of
++	a monitor.
++      </para></listitem>
++    </itemizedlist>
++    <para>
++      The creation of monitor connections is restricted to privileged users on
++      the bus (see above).
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Creating connections</title>
++    <para>
++      A connection to a bus is created by opening an endpoint file (see
++      <citerefentry>
++        <refentrytitle>kdbus.endpoint</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>)
++      of a bus and becoming an active client with the
++      <constant>KDBUS_CMD_HELLO</constant> ioctl. Every connection has a unique
++      identifier on the bus and can address messages to every other connection
++      on the same bus by using the peer's connection ID as the destination.
++    </para>
++    <para>
++      The <constant>KDBUS_CMD_HELLO</constant> ioctl takes a <type>struct
++      kdbus_cmd_hello</type> as argument.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd_hello {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  __u64 attach_flags_send;
++  __u64 attach_flags_recv;
++  __u64 bus_flags;
++  __u64 id;
++  __u64 pool_size;
++  __u64 offset;
++  __u8 id128[16];
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem>
++          <para>Flags to apply to this connection</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_HELLO_ACCEPT_FD</constant></term>
++              <listitem>
++                <para>
++                  When this flag is set, the connection can be sent file
++                  descriptors as message payload of unicast messages. If it's
++                  not set, an attempt to send file descriptors will result in
++                  <constant>-ECOMM</constant> on the sender's side.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_HELLO_ACTIVATOR</constant></term>
++              <listitem>
++                <para>
++                  Make this connection an activator (see above). With this bit
++                  set, an item of type <constant>KDBUS_ITEM_NAME</constant> has
++                  to be attached. This item describes the well-known name this
++                  connection should be an activator for.
++                  A connection can not be an activator and a policy holder at
++                  the same time time, so this bit is not allowed together with
++                  <constant>KDBUS_HELLO_POLICY_HOLDER</constant>.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_HELLO_POLICY_HOLDER</constant></term>
++              <listitem>
++                <para>
++                  Make this connection a policy holder (see above). With this
++                  bit set, an item of type <constant>KDBUS_ITEM_NAME</constant>
++                  has to be attached. This item describes the well-known name
++                  this connection should hold a policy for.
++                  A connection can not be an activator and a policy holder at
++                  the same time time, so this bit is not allowed together with
++                  <constant>KDBUS_HELLO_ACTIVATOR</constant>.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_HELLO_MONITOR</constant></term>
++              <listitem>
++                <para>
++                  Make this connection a monitor connection (see above).
++                </para>
++                <para>
++                  This flag can only be set by privileged bus connections. See
++                  below for more information.
++                  A connection can not be monitor and an activator or a policy
++                  holder at the same time time, so this bit is not allowed
++                  together with <constant>KDBUS_HELLO_ACTIVATOR</constant> or
++                  <constant>KDBUS_HELLO_POLICY_HOLDER</constant>.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Requests a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will return
++                  <errorcode>0</errorcode>, and the <varname>flags</varname>
++                  field will have all bits set that are valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>attach_flags_send</varname></term>
++        <listitem><para>
++          Set the bits for metadata this connection permits to be sent to the
++          receiving peer. Only metadata items that are both allowed to be sent
++          by the sender and that are requested by the receiver will be attached
++          to the message.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>attach_flags_recv</varname></term>
++        <listitem><para>
++          Request the attachment of metadata for each message received by this
++          connection. See
++          <citerefentry>
++            <refentrytitle>kdbus</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for information about metadata, and
++          <citerefentry>
++            <refentrytitle>kdbus.item</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          regarding items in general.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>bus_flags</varname></term>
++        <listitem><para>
++          Upon successful completion of the ioctl, this member will contain the
++          flags of the bus it connected to.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>id</varname></term>
++        <listitem><para>
++          Upon successful completion of the command, this member will contain
++          the numerical ID of the new connection.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>pool_size</varname></term>
++        <listitem><para>
++          The size of the communication pool, in bytes. The pool can be
++          accessed by calling
++          <citerefentry>
++            <refentrytitle>mmap</refentrytitle>
++            <manvolnum>2</manvolnum>
++          </citerefentry>
++          on the file descriptor that was used to issue the
++          <constant>KDBUS_CMD_HELLO</constant> ioctl.
++          The pool size of a connection must be greater than
++          <constant>0</constant> and a multiple of
++          <constant>PAGE_SIZE</constant>. See
++          <citerefentry>
++            <refentrytitle>kdbus.pool</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for more information.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>offset</varname></term>
++        <listitem><para>
++          The kernel will return the offset in the pool where returned details
++          will be stored. See below.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>id128</varname></term>
++        <listitem><para>
++          Upon successful completion of the ioctl, this member will contain the
++          <emphasis>128-bit UUID</emphasis> of the connected bus.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            Variable list of items containing optional additional information.
++            The following items are currently expected/valid:
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_CONN_DESCRIPTION</constant></term>
++              <listitem>
++                <para>
++                  Contains a string that describes this connection, so it can
++                  be identified later.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NAME</constant></term>
++              <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term>
++              <listitem>
++                <para>
++                  For activators and policy holders only, combinations of
++                  these two items describe policy access entries. See
++                  <citerefentry>
++                    <refentrytitle>kdbus.policy</refentrytitle>
++                    <manvolnum>7</manvolnum>
++                  </citerefentry>
++                  for further details.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_CREDS</constant></term>
++              <term><constant>KDBUS_ITEM_PIDS</constant></term>
++              <term><constant>KDBUS_ITEM_SECLABEL</constant></term>
++              <listitem>
++                <para>
++                  Privileged bus users may submit these types in order to
++                  create connections with faked credentials. This information
++                  will be returned when peer information is queried by
++                  <constant>KDBUS_CMD_CONN_INFO</constant>. See below for more
++                  information on retrieving information on connections.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++              <listitem><para>
++                With this item, programs can <emphasis>probe</emphasis> the
++                kernel for known item types. See
++                <citerefentry>
++                  <refentrytitle>kdbus.item</refentrytitle>
++                  <manvolnum>7</manvolnum>
++                </citerefentry>
++                for more details.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      At the offset returned in the <varname>offset</varname> field of
++      <type>struct kdbus_cmd_hello</type>, the kernel will store items
++      of the following types:
++    </para>
++
++    <variablelist>
++      <varlistentry>
++        <term><constant>KDBUS_ITEM_BLOOM_PARAMETER</constant></term>
++        <listitem>
++          <para>
++            Bloom filter parameter as defined by the bus creator.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      The offset in the pool has to be freed with the
++      <constant>KDBUS_CMD_FREE</constant> ioctl. See
++      <citerefentry>
++        <refentrytitle>kdbus.pool</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for further information.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Retrieving information on a connection</title>
++    <para>
++      The <constant>KDBUS_CMD_CONN_INFO</constant> ioctl can be used to
++      retrieve credentials and properties of the initial creator of a
++      connection. This ioctl uses the following struct.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd_info {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  __u64 id;
++  __u64 attach_flags;
++  __u64 offset;
++  __u64 info_size;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          Currently, no flags are supported.
++          <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for
++          valid flags. If set, the ioctl will return <errorcode>0</errorcode>,
++          and the <varname>flags</varname> field is set to
++          <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>id</varname></term>
++        <listitem><para>
++          The numerical ID of the connection for which information is to be
++          retrieved. If set to a non-zero value, the
++          <constant>KDBUS_ITEM_OWNED_NAME</constant> item is ignored.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>attach_flags</varname></term>
++        <listitem><para>
++          Specifies which metadata items should be attached to the answer. See
++          <citerefentry>
++            <refentrytitle>kdbus.message</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>offset</varname></term>
++        <listitem><para>
++          When the ioctl returns, this field will contain the offset of the
++          connection information inside the caller's pool. See
++          <citerefentry>
++            <refentrytitle>kdbus.pool</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for further information.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>info_size</varname></term>
++        <listitem><para>
++          The kernel will return the size of the returned information, so
++          applications can optionally
++          <citerefentry>
++            <refentrytitle>mmap</refentrytitle>
++            <manvolnum>2</manvolnum>
++          </citerefentry>
++          specific parts of the pool. See
++          <citerefentry>
++            <refentrytitle>kdbus.pool</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for further information.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            The following items are expected for
++            <constant>KDBUS_CMD_CONN_INFO</constant>.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_OWNED_NAME</constant></term>
++              <listitem>
++                <para>
++                  Contains the well-known name of the connection to look up as.
++                  This item is mandatory if the <varname>id</varname> field is
++                  set to 0.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++              <listitem><para>
++                With this item, programs can <emphasis>probe</emphasis> the
++                kernel for known item types. See
++                <citerefentry>
++                  <refentrytitle>kdbus.item</refentrytitle>
++                  <manvolnum>7</manvolnum>
++                </citerefentry>
++                for more details.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      When the ioctl returns, the following struct will be stored in the
++      caller's pool at <varname>offset</varname>. The fields in this struct
++      are described below.
++    </para>
++
++    <programlisting>
++struct kdbus_info {
++  __u64 size;
++  __u64 id;
++  __u64 flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>id</varname></term>
++        <listitem><para>
++          The connection's unique ID.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          The connection's flags as specified when it was created.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            Depending on the <varname>flags</varname> field in
++            <type>struct kdbus_cmd_info</type>, items of types
++            <constant>KDBUS_ITEM_OWNED_NAME</constant> and
++            <constant>KDBUS_ITEM_CONN_DESCRIPTION</constant> may follow here.
++            <constant>KDBUS_ITEM_NEGOTIATE</constant> is also allowed.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      Once the caller is finished with parsing the return buffer, it needs to
++      employ the <constant>KDBUS_CMD_FREE</constant> command for the offset, in
++      order to free the buffer part. See
++      <citerefentry>
++        <refentrytitle>kdbus.pool</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for further information.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Getting information about a connection's bus creator</title>
++    <para>
++      The <constant>KDBUS_CMD_BUS_CREATOR_INFO</constant> ioctl takes the same
++      struct as <constant>KDBUS_CMD_CONN_INFO</constant>, but is used to
++      retrieve information about the creator of the bus the connection is
++      attached to. The metadata returned by this call is collected during the
++      creation of the bus and is never altered afterwards, so it provides
++      pristine information on the task that created the bus, at the moment when
++      it did so.
++    </para>
++    <para>
++      In response to this call, a slice in the connection's pool is allocated
++      and filled with an object of type <type>struct kdbus_info</type>,
++      pointed to by the ioctl's <varname>offset</varname> field.
++    </para>
++
++    <programlisting>
++struct kdbus_info {
++  __u64 size;
++  __u64 id;
++  __u64 flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>id</varname></term>
++        <listitem><para>
++          The bus ID.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          The bus flags as specified when it was created.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            Metadata information is stored in items here. The item list
++            contains a <constant>KDBUS_ITEM_MAKE_NAME</constant> item that
++            indicates the bus name of the calling connection.
++            <constant>KDBUS_ITEM_NEGOTIATE</constant> is allowed to probe
++            for known item types.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      Once the caller is finished with parsing the return buffer, it needs to
++      employ the <constant>KDBUS_CMD_FREE</constant> command for the offset, in
++      order to free the buffer part. See
++      <citerefentry>
++        <refentrytitle>kdbus.pool</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for further information.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Updating connection details</title>
++    <para>
++      Some of a connection's details can be updated with the
++      <constant>KDBUS_CMD_CONN_UPDATE</constant> ioctl, using the file
++      descriptor that was used to create the connection. The update command
++      uses the following struct.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          Currently, no flags are supported.
++          <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for
++          valid flags. If set, the ioctl will return <errorcode>0</errorcode>,
++          and the <varname>flags</varname> field is set to
++          <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            Items to describe the connection details to be updated. The
++            following item types are supported.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term>
++              <listitem>
++                <para>
++                  Supply a new set of metadata items that this connection
++                  permits to be sent along with messages.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term>
++              <listitem>
++                <para>
++                  Supply a new set of metadata items that this connection
++                  requests to be attached to each message.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NAME</constant></term>
++              <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term>
++              <listitem>
++                <para>
++                  Policy holder connections may supply a new set of policy
++                  information with these items. For other connection types,
++                  <constant>EOPNOTSUPP</constant> is returned in
++                  <varname>errno</varname>.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++              <listitem><para>
++                With this item, programs can <emphasis>probe</emphasis> the
++                kernel for known item types. See
++                <citerefentry>
++                  <refentrytitle>kdbus.item</refentrytitle>
++                  <manvolnum>7</manvolnum>
++                </citerefentry>
++                for more details.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Termination of connections</title>
++    <para>
++      A connection can be terminated by simply calling
++      <citerefentry>
++        <refentrytitle>close</refentrytitle>
++        <manvolnum>2</manvolnum>
++      </citerefentry>
++      on its file descriptor. All pending incoming messages will be discarded,
++      and the memory allocated by the pool will be freed.
++    </para>
++
++    <para>
++      An alternative way of closing down a connection is via the
++      <constant>KDBUS_CMD_BYEBYE</constant> ioctl. This ioctl will succeed only
++      if the message queue of the connection is empty at the time of closing;
++      otherwise, the ioctl will fail with <varname>errno</varname> set to
++      <constant>EBUSY</constant>. When this ioctl returns
++      successfully, the connection has been terminated and won't accept any new
++      messages from remote peers. This way, a connection can be terminated
++      race-free, without losing any messages. The ioctl takes an argument of
++      type <type>struct kdbus_cmd</type>.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          Currently, no flags are supported.
++          <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for
++          valid flags. If set, the ioctl will fail with
++          <varname>errno</varname> set to <constant>EPROTO</constant>, and
++          the <varname>flags</varname> field is set to <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            The following item types are supported.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++              <listitem><para>
++                With this item, programs can <emphasis>probe</emphasis> the
++                kernel for known item types. See
++                <citerefentry>
++                  <refentrytitle>kdbus.item</refentrytitle>
++                  <manvolnum>7</manvolnum>
++                </citerefentry>
++                for more details.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>
++      On success, all mentioned ioctl commands return <errorcode>0</errorcode>;
++      on error, <errorcode>-1</errorcode> is returned, and
++      <varname>errno</varname> is set to indicate the error.
++      If the issued ioctl is illegal for the file descriptor used,
++      <varname>errno</varname> will be set to <constant>ENOTTY</constant>.
++    </para>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_HELLO</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EFAULT</constant></term>
++          <listitem><para>
++            The supplied pool size was 0 or not a multiple of the page size.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            The flags supplied in <type>struct kdbus_cmd_hello</type>
++            are invalid.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            An illegal combination of
++            <constant>KDBUS_HELLO_MONITOR</constant>,
++            <constant>KDBUS_HELLO_ACTIVATOR</constant> and
++            <constant>KDBUS_HELLO_POLICY_HOLDER</constant> was passed in
++            <varname>flags</varname>.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            An invalid set of items was supplied.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ECONNREFUSED</constant></term>
++          <listitem><para>
++            The attach_flags_send field did not satisfy the requirements of
++            the bus.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EPERM</constant></term>
++          <listitem><para>
++            A <constant>KDBUS_ITEM_CREDS</constant> items was supplied, but the
++            current user is not privileged.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ESHUTDOWN</constant></term>
++          <listitem><para>
++            The bus you were trying to connect to has already been shut down.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EMFILE</constant></term>
++          <listitem><para>
++            The maximum number of connections on the bus has been reached.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EOPNOTSUPP</constant></term>
++          <listitem><para>
++            The endpoint does not support the connection flags supplied in
++            <type>struct kdbus_cmd_hello</type>.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_BYEBYE</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EALREADY</constant></term>
++          <listitem><para>
++            The connection has already been shut down.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EBUSY</constant></term>
++          <listitem><para>
++            There are still messages queued up in the connection's pool.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_CONN_INFO</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Invalid flags, or neither an ID nor a name was provided, or the
++            name is invalid.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ESRCH</constant></term>
++          <listitem><para>
++            Connection lookup by name failed.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ENXIO</constant></term>
++          <listitem><para>
++            No connection with the provided connection ID found.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_CONN_UPDATE</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Illegal flags or items.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Wildcards submitted in policy entries, or illegal sequence
++            of policy items.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EOPNOTSUPP</constant></term>
++          <listitem><para>
++            Operation not supported by connection.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>E2BIG</constant></term>
++          <listitem><para>
++            Too many policy items attached.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.policy</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.endpoint.xml b/Documentation/kdbus/kdbus.endpoint.xml
+new file mode 100644
+index 0000000..6632485
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.endpoint.xml
+@@ -0,0 +1,429 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.endpoint">
++
++  <refentryinfo>
++    <title>kdbus.endpoint</title>
++    <productname>kdbus.endpoint</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.endpoint</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.endpoint</refname>
++    <refpurpose>kdbus endpoint</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>
++      Endpoints are entry points to a bus (see
++      <citerefentry>
++        <refentrytitle>kdbus.bus</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>).
++      By default, each bus has a default
++      endpoint called 'bus'. The bus owner has the ability to create custom
++      endpoints with specific names, permissions, and policy databases
++      (see below). An endpoint is presented as file underneath the directory
++      of the parent bus.
++    </para>
++    <para>
++      To create a custom endpoint, open the default endpoint
++      (<literal>bus</literal>) and use the
++      <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> ioctl with
++      <type>struct kdbus_cmd</type>. Custom endpoints always have a policy
++      database that, by default, forbids any operation. You have to explicitly
++      install policy entries to allow any operation on this endpoint.
++    </para>
++    <para>
++      Once <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> succeeded, the new
++      endpoint will appear in the filesystem
++      (<citerefentry>
++        <refentrytitle>kdbus.bus</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>), and the used file descriptor will manage the
++      newly created endpoint resource. It cannot be used to manage further
++      resources and must be kept open as long as the endpoint is needed. The
++      endpoint will be terminated as soon as the file descriptor is closed.
++    </para>
++    <para>
++      Endpoint names may be chosen freely except for one restriction: the name
++      must be prefixed with the numeric effective UID of the creator and a dash.
++      This is required to avoid namespace clashes between different users. When
++      creating an endpoint, the name that is passed in must be properly
++      formatted or the kernel will refuse creation of the endpoint. Example:
++      <literal>1047-my-endpoint</literal> is an acceptable name for an
++      endpoint registered by a user with UID 1047. However,
++      <literal>1024-my-endpoint</literal> is not, and neither is
++      <literal>my-endpoint</literal>. The UID must be provided in the
++      user-namespace of the bus.
++    </para>
++    <para>
++      To create connections to a bus, use <constant>KDBUS_CMD_HELLO</constant>
++      on a file descriptor returned by <function>open()</function> on an
++      endpoint node. See
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for further details.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Creating custom endpoints</title>
++    <para>
++      To create a new endpoint, the
++      <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> command is used. Along with
++      the endpoint's name, which will be used to expose the endpoint in the
++      <citerefentry>
++        <refentrytitle>kdbus.fs</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>,
++      the command also optionally takes items to set up the endpoint's
++      <citerefentry>
++        <refentrytitle>kdbus.policy</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>.
++      <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> takes a
++      <type>struct kdbus_cmd</type> argument.
++    </para>
++    <programlisting>
++struct kdbus_cmd {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>The flags for creation.</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_MAKE_ACCESS_GROUP</constant></term>
++              <listitem>
++                <para>Make the endpoint file group-accessible.</para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_MAKE_ACCESS_WORLD</constant></term>
++              <listitem>
++                <para>Make the endpoint file world-accessible.</para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Requests a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will return
++                  <errorcode>0</errorcode>, and the <varname>flags</varname>
++                  field will have all bits set that are valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            The following items are expected for
++            <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_MAKE_NAME</constant></term>
++              <listitem>
++                <para>Contains a string to identify the endpoint name.</para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NAME</constant></term>
++              <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term>
++              <listitem>
++                <para>
++                  These items are used to set the policy attached to the
++                  endpoint. For more details on bus and endpoint policies, see
++                  <citerefentry>
++                    <refentrytitle>kdbus.policy</refentrytitle>
++                    <manvolnum>7</manvolnum>
++                  </citerefentry>.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <varname>EINVAL</varname>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Updating endpoints</title>
++    <para>
++      To update an existing endpoint, the
++      <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant> command is used on the file
++      descriptor that was used to create the endpoint, using
++      <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>. The only relevant detail of
++      the endpoint that can be updated is the policy. When the command is
++      employed, the policy of the endpoint is <emphasis>replaced</emphasis>
++      atomically with the new set of rules.
++      The command takes a <type>struct kdbus_cmd</type> argument.
++    </para>
++    <programlisting>
++struct kdbus_cmd {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          Unused for this command.
++          <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for
++          valid flags. If set, the ioctl will return <errorcode>0</errorcode>,
++          and the <varname>flags</varname> field is set to
++          <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            The following items are expected for
++            <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant>.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NAME</constant></term>
++              <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term>
++              <listitem>
++                <para>
++                  These items are used to set the policy attached to the
++                  endpoint. For more details on bus and endpoint policies, see
++                  <citerefentry>
++                    <refentrytitle>kdbus.policy</refentrytitle>
++                    <manvolnum>7</manvolnum>
++                  </citerefentry>.
++                  Existing policy is atomically replaced with the new rules
++                  provided.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++              <listitem><para>
++                With this item, programs can <emphasis>probe</emphasis> the
++                kernel for known item types. See
++                <citerefentry>
++                  <refentrytitle>kdbus.item</refentrytitle>
++                  <manvolnum>7</manvolnum>
++                </citerefentry>
++                for more details.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>
++      On success, all mentioned ioctl commands return <errorcode>0</errorcode>;
++      on error, <errorcode>-1</errorcode> is returned, and
++      <varname>errno</varname> is set to indicate the error.
++      If the issued ioctl is illegal for the file descriptor used,
++      <varname>errno</varname> will be set to <constant>ENOTTY</constant>.
++    </para>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> may fail with the
++        following errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            The flags supplied in the <type>struct kdbus_cmd</type>
++            are invalid.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Illegal combination of <constant>KDBUS_ITEM_NAME</constant> and
++            <constant>KDBUS_ITEM_POLICY_ACCESS</constant> was provided.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EEXIST</constant></term>
++          <listitem><para>
++            An endpoint of that name already exists.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EPERM</constant></term>
++          <listitem><para>
++            The calling user is not privileged. See
++            <citerefentry>
++              <refentrytitle>kdbus</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for information about privileged users.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant> may fail with the
++        following errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            The flags supplied in <type>struct kdbus_cmd</type>
++            are invalid.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Illegal combination of <constant>KDBUS_ITEM_NAME</constant> and
++            <constant>KDBUS_ITEM_POLICY_ACCESS</constant> was provided.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.fs</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++           <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.fs.xml b/Documentation/kdbus/kdbus.fs.xml
+new file mode 100644
+index 0000000..8c2a90e
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.fs.xml
+@@ -0,0 +1,124 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus_fs">
++
++  <refentryinfo>
++    <title>kdbus.fs</title>
++    <productname>kdbus.fs</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.fs</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.fs</refname>
++    <refpurpose>kdbus file system</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>File-system Layout</title>
++
++    <para>
++      The <emphasis>kdbusfs</emphasis> pseudo filesystem provides access to
++      kdbus entities, such as <emphasis>buses</emphasis> and
++      <emphasis>endpoints</emphasis>. Each time the filesystem is mounted,
++      a new, isolated kdbus instance is created, which is independent from the
++      other instances.
++    </para>
++    <para>
++      The system-wide standard mount point for <emphasis>kdbusfs</emphasis> is
++      <constant>/sys/fs/kdbus</constant>.
++    </para>
++
++    <para>
++      Buses are represented as directories in the file system layout, whereas
++      endpoints are exposed as files inside these directories. At the top-level,
++      a <emphasis>control</emphasis> node is present, which can be opened to
++      create new buses via the <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl.
++      Each <emphasis>bus</emphasis> shows a default endpoint called
++      <varname>bus</varname>, which can be opened to either create a connection
++      with the <constant>KDBUS_CMD_HELLO</constant> ioctl, or to create new
++      custom endpoints for the bus with
++      <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>. See
++      <citerefentry>
++        <refentrytitle>kdbus.bus</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry> and
++      <citerefentry>
++        <refentrytitle>kdbus.endpoint</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more details.
++    </para>
++
++    <para>Following, you can see an example layout of the
++    <emphasis>kdbusfs</emphasis> filesystem:</para>
++
++<programlisting>
++        /sys/fs/kdbus/                          ; mount-point
++        |-- 0-system                            ; bus directory
++        |   |-- bus                             ; default endpoint
++        |   `-- 1017-custom                     ; custom endpoint
++        |-- 1000-user                           ; bus directory
++        |   |-- bus                             ; default endpoint
++        |   |-- 1000-service-A                  ; custom endpoint
++        |   `-- 1000-service-B                  ; custom endpoint
++        `-- control                             ; control file
++</programlisting>
++  </refsect1>
++
++  <refsect1>
++    <title>Mounting instances</title>
++    <para>
++      In order to get a new and separate kdbus environment, a new instance
++      of <emphasis>kdbusfs</emphasis> can be mounted like this:
++    </para>
++<programlisting>
++  # mount -t kdbusfs kdbusfs /tmp/new_kdbus/
++</programlisting>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>mount</refentrytitle>
++          <manvolnum>8</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.item.xml b/Documentation/kdbus/kdbus.item.xml
+new file mode 100644
+index 0000000..ee09dfa
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.item.xml
+@@ -0,0 +1,839 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus">
++
++  <refentryinfo>
++    <title>kdbus.item</title>
++    <productname>kdbus item</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.item</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.item</refname>
++    <refpurpose>kdbus item structure, layout and usage</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>
++      To flexibly augment transport structures, data blobs of type
++      <type>struct kdbus_item</type> can be attached to the structs passed
++      into the ioctls. Some ioctls make items of certain types mandatory,
++      others are optional. Items that are unsupported by ioctls they are
++      attached to will cause the ioctl to fail with <varname>errno</varname>
++      set to <constant>EINVAL</constant>.
++      Items are also used for information stored in a connection's
++      <emphasis>pool</emphasis>, such as received messages, name lists or
++      requested connection or bus owner information. Depending on the type of
++      an item, its total size is either fixed or variable.
++    </para>
++
++    <refsect2>
++      <title>Chaining items</title>
++      <para>
++        Whenever items are used as part of the kdbus kernel API, they are
++        embedded in structs that are embedded inside structs that themselves
++        include a size field containing the overall size of the structure.
++        This allows multiple items to be chained up, and an item iterator
++        (see below) is capable of detecting the end of an item chain.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Alignment</title>
++      <para>
++        The kernel expects all items to be aligned to 8-byte boundaries.
++        Unaligned items will cause the ioctl they are used with to fail
++        with <varname>errno</varname> set to <constant>EINVAL</constant>.
++        An item that has an unaligned size itself hence needs to be padded
++        if it is followed by another item.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Iterating items</title>
++      <para>
++        A simple iterator would iterate over the items until the items have
++        reached the embedding structure's overall size. An example
++        implementation is shown below.
++      </para>
++
++      <programlisting><![CDATA[
++#define KDBUS_ALIGN8(val) (((val) + 7) & ~7)
++
++#define KDBUS_ITEM_NEXT(item) \
++    (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size))
++
++#define KDBUS_ITEM_FOREACH(item, head, first)                      \
++    for ((item) = (head)->first;                                   \
++         ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \
++          ((uint8_t *)(item) >= (uint8_t *)(head));                \
++         (item) = KDBUS_ITEM_NEXT(item))
++      ]]></programlisting>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>Item layout</title>
++    <para>
++      A <type>struct kdbus_item</type> consists of a
++      <varname>size</varname> field, describing its overall size, and a
++      <varname>type</varname> field, both 64 bit wide. They are followed by
++      a union to store information that is specific to the item's type.
++      The struct layout is shown below.
++    </para>
++
++    <programlisting>
++struct kdbus_item {
++  __u64 size;
++  __u64 type;
++  /* item payload - see below */
++  union {
++    __u8 data[0];
++    __u32 data32[0];
++    __u64 data64[0];
++    char str[0];
++
++    __u64 id;
++    struct kdbus_vec vec;
++    struct kdbus_creds creds;
++    struct kdbus_pids pids;
++    struct kdbus_audit audit;
++    struct kdbus_caps caps;
++    struct kdbus_timestamp timestamp;
++    struct kdbus_name name;
++    struct kdbus_bloom_parameter bloom_parameter;
++    struct kdbus_bloom_filter bloom_filter;
++    struct kdbus_memfd memfd;
++    int fds[0];
++    struct kdbus_notify_name_change name_change;
++    struct kdbus_notify_id_change id_change;
++    struct kdbus_policy_access policy_access;
++  };
++};
++    </programlisting>
++
++    <para>
++      <type>struct kdbus_item</type> should never be used to allocate
++      an item instance, as its size may grow in future releases of the API.
++      Instead, it should be manually assembled by storing the
++      <varname>size</varname>, <varname>type</varname> and payload to a
++      struct of its own.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Item types</title>
++
++    <refsect2>
++      <title>Negotiation item</title>
++      <variablelist>
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++          <listitem><para>
++            With this item is attached to any ioctl, programs can
++            <emphasis>probe</emphasis> the kernel for known item types.
++            The item carries an array of <type>uint64_t</type> values in
++            <varname>item.data64</varname>, each set to an item type to
++            probe. The kernel will reset each member of this array that is
++            not recognized as valid item type to <constant>0</constant>.
++            This way, users can negotiate kernel features at start-up to
++            keep newer userspace compatible with older kernels. This item
++            is never attached by the kernel in response to any command.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>Command specific items</title>
++      <variablelist>
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_PAYLOAD_VEC</constant></term>
++          <term><constant>KDBUS_ITEM_PAYLOAD_OFF</constant></term>
++          <listitem><para>
++            Messages are directly copied by the sending process into the
++            receiver's
++            <citerefentry>
++              <refentrytitle>kdbus.pool</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++            This way, two peers can exchange data by effectively doing a
++            single-copy from one process to another; the kernel will not buffer
++            the data anywhere else. <constant>KDBUS_ITEM_PAYLOAD_VEC</constant>
++            is used when <emphasis>sending</emphasis> message. The item
++            references a memory address when the payload data can be found.
++            <constant>KDBUS_ITEM_PAYLOAD_OFF</constant> is used when messages
++            are <emphasis>received</emphasis>, and the
++            <constant>offset</constant> value describes the offset inside the
++            receiving connection's
++            <citerefentry>
++              <refentrytitle>kdbus.pool</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            where the message payload can be found. See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on passing of payload data along with a
++            message.
++            <programlisting>
++struct kdbus_vec {
++  __u64 size;
++  union {
++    __u64 address;
++    __u64 offset;
++  };
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant></term>
++          <listitem><para>
++            Transports a file descriptor of a <emphasis>memfd</emphasis> in
++            <type>struct kdbus_memfd</type> in <varname>item.memfd</varname>.
++            The <varname>size</varname> field has to match the actual size of
++            the memfd that was specified when it was created. The
++            <varname>start</varname> parameter denotes the offset inside the
++            memfd at which the referenced payload starts. See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on passing of payload data along with a
++            message.
++            <programlisting>
++struct kdbus_memfd {
++  __u64 start;
++  __u64 size;
++  int fd;
++  __u32 __pad;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_FDS</constant></term>
++          <listitem><para>
++            Contains an array of <emphasis>file descriptors</emphasis>.
++            When used with <constant>KDBUS_CMD_SEND</constant>, the values of
++            this array must be filled with valid file descriptor numbers.
++            When received as item attached to a message, the array will
++            contain the numbers of the installed file descriptors, or
++            <constant>-1</constant> in case an error occurred.
++            In either case, the number of entries in the array is derived from
++            the item's total size. See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>Items specific to some commands</title>
++      <variablelist>
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_CANCEL_FD</constant></term>
++          <listitem><para>
++            Transports a file descriptor that can be used to cancel a
++            synchronous <constant>KDBUS_CMD_SEND</constant> operation by
++            writing to it. The file descriptor is stored in
++            <varname>item.fd[0]</varname>. The item may only contain one
++            file descriptor. See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on this item and how to use it.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_BLOOM_PARAMETER</constant></term>
++          <listitem><para>
++            Contains a set of <emphasis>bloom parameters</emphasis> as
++            <type>struct kdbus_bloom_parameter</type> in
++            <varname>item.bloom_parameter</varname>.
++            The item is passed from userspace to kernel during the
++            <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl, and returned
++            verbatim when <constant>KDBUS_CMD_HELLO</constant> is called.
++            The kernel does not use the bloom parameters, but they need to
++            be known by each connection on the bus in order to define the
++            bloom filter hash details. See
++            <citerefentry>
++              <refentrytitle>kdbus.match</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on matching and bloom filters.
++            <programlisting>
++struct kdbus_bloom_parameter {
++  __u64 size;
++  __u64 n_hash;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_BLOOM_FILTER</constant></term>
++          <listitem><para>
++            Carries a <emphasis>bloom filter</emphasis> as
++            <type>struct kdbus_bloom_filter</type> in
++            <varname>item.bloom_filter</varname>. It is mandatory to send this
++            item attached to a <type>struct kdbus_msg</type>, in case the
++            message is a signal. This item is never transported from kernel to
++            userspace. See
++            <citerefentry>
++              <refentrytitle>kdbus.match</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on matching and bloom filters.
++            <programlisting>
++struct kdbus_bloom_filter {
++  __u64 generation;
++  __u64 data[0];
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_BLOOM_MASK</constant></term>
++          <listitem><para>
++            Transports a <emphasis>bloom mask</emphasis> as binary data blob
++            stored in <varname>item.data</varname>. This item is used to
++            describe a match into a connection's match database. See
++            <citerefentry>
++              <refentrytitle>kdbus.match</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on matching and bloom filters.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_DST_NAME</constant></term>
++          <listitem><para>
++            Contains a <emphasis>well-known name</emphasis> to send a
++            message to, as null-terminated string in
++            <varname>item.str</varname>. This item is used with
++            <constant>KDBUS_CMD_SEND</constant>. See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on how to send a message.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_MAKE_NAME</constant></term>
++          <listitem><para>
++            Contains a <emphasis>bus name</emphasis> or
++            <emphasis>endpoint name</emphasis>, stored as null-terminated
++            string in <varname>item.str</varname>. This item is sent from
++            userspace to kernel when buses or endpoints are created, and
++            returned back to userspace when the bus creator information is
++            queried. See
++            <citerefentry>
++              <refentrytitle>kdbus.bus</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            and
++            <citerefentry>
++              <refentrytitle>kdbus.endpoint</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term>
++          <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term>
++          <listitem><para>
++            Contains a set of <emphasis>attach flags</emphasis> at
++            <emphasis>send</emphasis> or <emphasis>receive</emphasis> time. See
++            <citerefentry>
++              <refentrytitle>kdbus</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>,
++            <citerefentry>
++              <refentrytitle>kdbus.bus</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry> and
++            <citerefentry>
++              <refentrytitle>kdbus.connection</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on attach flags.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_ID</constant></term>
++          <listitem><para>
++            Transports a connection's <emphasis>numerical ID</emphasis> of
++            a connection as <type>uint64_t</type> value in
++            <varname>item.id</varname>.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_NAME</constant></term>
++          <listitem><para>
++            Transports a name associated with the
++            <emphasis>name registry</emphasis> as null-terminated string as
++            <type>struct kdbus_name</type> in
++            <varname>item.name</varname>. The <varname>flags</varname>
++            contains the flags of the name. See
++            <citerefentry>
++              <refentrytitle>kdbus.name</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on how to access the name registry of a bus.
++            <programlisting>
++struct kdbus_name {
++  __u64 flags;
++  char name[0];
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>Items attached by the kernel as metadata</title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_TIMESTAMP</constant></term>
++          <listitem><para>
++            Contains both the <emphasis>monotonic</emphasis> and the
++            <emphasis>realtime</emphasis> timestamp, taken when the message
++            was processed on the kernel side.
++            Stored as <type>struct kdbus_timestamp</type> in
++            <varname>item.timestamp</varname>.
++            <programlisting>
++struct kdbus_timestamp {
++  __u64 seqnum;
++  __u64 monotonic_ns;
++  __u64 realtime_ns;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_CREDS</constant></term>
++          <listitem><para>
++            Contains a set of <emphasis>user</emphasis> and
++            <emphasis>group</emphasis> information as 32-bit values, in the
++            usual four flavors: real, effective, saved and filesystem related.
++            Stored as <type>struct kdbus_creds</type> in
++            <varname>item.creds</varname>.
++            <programlisting>
++struct kdbus_creds {
++  __u32 uid;
++  __u32 euid;
++  __u32 suid;
++  __u32 fsuid;
++  __u32 gid;
++  __u32 egid;
++  __u32 sgid;
++  __u32 fsgid;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_PIDS</constant></term>
++          <listitem><para>
++            Contains the <emphasis>PID</emphasis>, <emphasis>TID</emphasis>
++            and <emphasis>parent PID (PPID)</emphasis> of a remote peer.
++            Stored as <type>struct kdbus_pids</type> in
++            <varname>item.pids</varname>.
++            <programlisting>
++struct kdbus_pids {
++  __u64 pid;
++  __u64 tid;
++  __u64 ppid;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_AUXGROUPS</constant></term>
++          <listitem><para>
++            Contains the <emphasis>auxiliary (supplementary) groups</emphasis>
++            a remote peer is a member of, stored as array of
++            <type>uint32_t</type> values in <varname>item.data32</varname>.
++            The array length can be determined by looking at the item's total
++            size, subtracting the size of the header and dividing the
++            remainder by <constant>sizeof(uint32_t)</constant>.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_OWNED_NAME</constant></term>
++          <listitem><para>
++            Contains a <emphasis>well-known name</emphasis> currently owned
++            by a connection. The name is stored as null-terminated string in
++            <varname>item.str</varname>. Its length can also be derived from
++            the item's total size.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_TID_COMM</constant> [*]</term>
++          <listitem><para>
++            Contains the <emphasis>comm</emphasis> string of a task's
++            <emphasis>TID</emphasis> (thread ID), stored as null-terminated
++            string in <varname>item.str</varname>. Its length can also be
++            derived from the item's total size. Receivers of this item should
++            not use its contents for any kind of security measures. See below.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_PID_COMM</constant> [*]</term>
++          <listitem><para>
++            Contains the <emphasis>comm</emphasis> string of a task's
++            <emphasis>PID</emphasis> (process ID), stored as null-terminated
++            string in <varname>item.str</varname>. Its length can also be
++            derived from the item's total size. Receivers of this item should
++            not use its contents for any kind of security measures. See below.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_EXE</constant> [*]</term>
++          <listitem><para>
++            Contains the <emphasis>path to the executable</emphasis> of a task,
++            stored as null-terminated string in <varname>item.str</varname>. Its
++            length can also be derived from the item's total size. Receivers of
++            this item should not use its contents for any kind of security
++            measures. See below.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_CMDLINE</constant> [*]</term>
++          <listitem><para>
++            Contains the <emphasis>command line arguments</emphasis> of a
++            task, stored as an <emphasis>array</emphasis> of null-terminated
++            strings in <varname>item.str</varname>. The total length of all
++            strings in the array can be derived from the item's total size.
++            Receivers of this item should not use its contents for any kind
++            of security measures. See below.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_CGROUP</constant></term>
++          <listitem><para>
++            Contains the <emphasis>cgroup path</emphasis> of a task, stored
++            as null-terminated string in <varname>item.str</varname>. Its
++            length can also be derived from the item's total size.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_CAPS</constant></term>
++          <listitem><para>
++            Contains sets of <emphasis>capabilities</emphasis>, stored as
++            <type>struct kdbus_caps</type> in <varname>item.caps</varname>.
++            As the item size may increase in the future, programs should be
++            written in a way that it takes
++            <varname>item.caps.last_cap</varname> into account, and derive
++            the number of sets and rows from the item size and the reported
++            number of valid capability bits.
++            <programlisting>
++struct kdbus_caps {
++  __u32 last_cap;
++  __u32 caps[0];
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_SECLABEL</constant></term>
++          <listitem><para>
++            Contains the <emphasis>LSM label</emphasis> of a task, stored as
++            null-terminated string in <varname>item.str</varname>. Its length
++            can also be derived from the item's total size.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_AUDIT</constant></term>
++          <listitem><para>
++            Contains the audit <emphasis>sessionid</emphasis> and
++            <emphasis>loginuid</emphasis> of a task, stored as
++            <type>struct kdbus_audit</type> in
++            <varname>item.audit</varname>.
++            <programlisting>
++struct kdbus_audit {
++  __u32 sessionid;
++  __u32 loginuid;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_CONN_DESCRIPTION</constant></term>
++          <listitem><para>
++            Contains the <emphasis>connection description</emphasis>, as set
++            by <constant>KDBUS_CMD_HELLO</constant> or
++            <constant>KDBUS_CMD_CONN_UPDATE</constant>, stored as
++            null-terminated string in <varname>item.str</varname>. Its length
++            can also be derived from the item's total size.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++
++      <para>
++        All metadata is automatically translated into the
++        <emphasis>namespaces</emphasis> of the task that receives them. See
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more information.
++      </para>
++
++      <para>
++        [*] Note that the content stored in metadata items of type
++        <constant>KDBUS_ITEM_TID_COMM</constant>,
++        <constant>KDBUS_ITEM_PID_COMM</constant>,
++        <constant>KDBUS_ITEM_EXE</constant> and
++        <constant>KDBUS_ITEM_CMDLINE</constant>
++        can easily be tampered by the sending tasks. Therefore, they should
++        <emphasis>not</emphasis> be used for any sort of security relevant
++        assumptions. The only reason they are transmitted is to let
++        receivers know about details that were set when metadata was
++        collected, even though the task they were collected from is not
++        active any longer when the items are received.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Items used for policy entries, matches and notifications</title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term>
++          <listitem><para>
++            This item describes a <emphasis>policy access</emphasis> entry to
++            access the policy database of a
++            <citerefentry>
++              <refentrytitle>kdbus.bus</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry> or
++            <citerefentry>
++              <refentrytitle>kdbus.endpoint</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++            Please refer to
++            <citerefentry>
++              <refentrytitle>kdbus.policy</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on the policy database and how to access it.
++            <programlisting>
++struct kdbus_policy_access {
++  __u64 type;
++  __u64 access;
++  __u64 id;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_ID_ADD</constant></term>
++          <term><constant>KDBUS_ITEM_ID_REMOVE</constant></term>
++          <listitem><para>
++            This item is sent as attachment to a
++            <emphasis>kernel notification</emphasis> and indicates that a
++            new connection was created on the bus, or that a connection was
++            disconnected, respectively. It stores a
++            <type>struct kdbus_notify_id_change</type> in
++            <varname>item.id_change</varname>.
++            The <varname>id</varname> field contains the numeric ID of the
++            connection that was added or removed, and <varname>flags</varname>
++            is set to the connection flags, as passed by
++            <constant>KDBUS_CMD_HELLO</constant>. See
++            <citerefentry>
++              <refentrytitle>kdbus.match</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            and
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on matches and notification messages.
++            <programlisting>
++struct kdbus_notify_id_change {
++  __u64 id;
++  __u64 flags;
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_NAME_ADD</constant></term>
++          <term><constant>KDBUS_ITEM_NAME_REMOVE</constant></term>
++          <term><constant>KDBUS_ITEM_NAME_CHANGE</constant></term>
++          <listitem><para>
++            This item is sent as attachment to a
++            <emphasis>kernel notification</emphasis> and indicates that a
++            <emphasis>well-known name</emphasis> appeared, disappeared or
++            transferred to another owner on the bus. It stores a
++            <type>struct kdbus_notify_name_change</type> in
++            <varname>item.name_change</varname>.
++            <varname>old_id</varname> describes the former owner of the name
++            and is set to <constant>0</constant> values in case of
++            <constant>KDBUS_ITEM_NAME_ADD</constant>.
++            <varname>new_id</varname> describes the new owner of the name and
++            is set to <constant>0</constant> values in case of
++            <constant>KDBUS_ITEM_NAME_REMOVE</constant>.
++            The <varname>name</varname> field contains the well-known name the
++            notification is about, as null-terminated string. See
++            <citerefentry>
++              <refentrytitle>kdbus.match</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            and
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information on matches and notification messages.
++            <programlisting>
++struct kdbus_notify_name_change {
++  struct kdbus_notify_id_change old_id;
++  struct kdbus_notify_id_change new_id;
++  char name[0];
++};
++            </programlisting>
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_REPLY_TIMEOUT</constant></term>
++          <listitem><para>
++            This item is sent as attachment to a
++            <emphasis>kernel notification</emphasis>. It informs the receiver
++            that an expected reply to a message was not received in time.
++            The remote peer ID and the message cookie are stored in the message
++            header. See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information about messages, timeouts and notifications.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ITEM_REPLY_DEAD</constant></term>
++          <listitem><para>
++            This item is sent as attachment to a
++            <emphasis>kernel notification</emphasis>. It informs the receiver
++            that a remote connection a reply is expected from was disconnected
++            before that reply was sent. The remote peer ID and the message
++            cookie are stored in the message header. See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for more information about messages, timeouts and notifications.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.fs</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>memfd_create</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.match.xml b/Documentation/kdbus/kdbus.match.xml
+new file mode 100644
+index 0000000..ae38e04
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.match.xml
+@@ -0,0 +1,555 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.match">
++
++  <refentryinfo>
++    <title>kdbus.match</title>
++    <productname>kdbus.match</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.match</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.match</refname>
++    <refpurpose>kdbus match</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>
++      kdbus connections can install matches in order to subscribe to signal
++      messages sent on the bus. Such signal messages can be either directed
++      to a single connection (by setting a specific connection ID in
++      <varname>struct kdbus_msg.dst_id</varname> or by sending it to a
++      well-known name), or to potentially <emphasis>all</emphasis> currently
++      active connections on the bus (by setting
++      <varname>struct kdbus_msg.dst_id</varname> to
++      <constant>KDBUS_DST_ID_BROADCAST</constant>).
++      A signal message always has the <constant>KDBUS_MSG_SIGNAL</constant>
++      bit set in the <varname>flags</varname> bitfield.
++      Also, signal messages can originate from either the kernel (called
++      <emphasis>notifications</emphasis>), or from other bus connections.
++      In either case, a bus connection needs to have a suitable
++      <emphasis>match</emphasis> installed in order to receive any signal
++      message. Without any rules installed in the connection, no signal message
++      will be received.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Matches for signal messages from other connections</title>
++    <para>
++      Matches for messages from other connections (not kernel notifications)
++      are implemented as bloom filters (see below). The sender adds certain
++      properties of the message as elements to a bloom filter bit field, and
++      sends that along with the signal message.
++
++      The receiving connection adds the message properties it is interested in
++      as elements to a bloom mask bit field, and uploads the mask as match rule,
++      possibly along with some other rules to further limit the match.
++
++      The kernel will match the signal message's bloom filter against the
++      connection's bloom mask (simply by &amp;-ing it), and will decide whether
++      the message should be delivered to a connection.
++    </para>
++    <para>
++      The kernel has no notion of any specific properties of the signal message,
++      all it sees are the bit fields of the bloom filter and the mask to match
++      against. The use of bloom filters allows simple and efficient matching,
++      without exposing any message properties or internals to the kernel side.
++      Clients need to deal with the fact that they might receive signal messages
++      which they did not subscribe to, as the bloom filter might allow
++      false-positives to pass the filter.
++
++      To allow the future extension of the set of elements in the bloom filter,
++      the filter specifies a <emphasis>generation</emphasis> number. A later
++      generation must always contain all elements of the set of the previous
++      generation, but can add new elements to the set. The match rules mask can
++      carry an array with all previous generations of masks individually stored.
++      When the filter and mask are matched by the kernel, the mask with the
++      closest matching generation is selected as the index into the mask array.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Bloom filters</title>
++    <para>
++      Bloom filters allow checking whether a given word is present in a
++      dictionary.  This allows connections to set up a mask for information it
++      is interested in, and will be delivered signal messages that have a
++      matching filter.
++
++      For general information, see
++      <ulink url="https://en.wikipedia.org/wiki/Bloom_filter">the Wikipedia
++      article on bloom filters</ulink>.
++    </para>
++    <para>
++      The size of the bloom filter is defined per bus when it is created, in
++      <varname>kdbus_bloom_parameter.size</varname>. All bloom filters attached
++      to signal messages on the bus must match this size, and all bloom filter
++      matches uploaded by connections must also match the size, or a multiple
++      thereof (see below).
++
++      The calculation of the mask has to be done in userspace applications. The
++      kernel just checks the bitmasks to decide whether or not to let the
++      message pass. All bits in the mask must match the filter in and bit-wise
++      <emphasis>AND</emphasis> logic, but the mask may have more bits set than
++      the filter. Consequently, false positive matches are expected to happen,
++      and programs must deal with that fact by checking the contents of the
++      payload again at receive time.
++    </para>
++    <para>
++      Masks are entities that are always passed to the kernel as part of a
++      match (with an item of type <constant>KDBUS_ITEM_BLOOM_MASK</constant>),
++      and filters can be attached to signals, with an item of type
++      <constant>KDBUS_ITEM_BLOOM_FILTER</constant>. For a filter to match, all
++      its bits have to be set in the match mask as well.
++    </para>
++    <para>
++      For example, consider a bus that has a bloom size of 8 bytes, and the
++      following mask/filter combinations:
++    </para>
++    <programlisting><![CDATA[
++          filter  0x0101010101010101
++          mask    0x0101010101010101
++                  -> matches
++
++          filter  0x0303030303030303
++          mask    0x0101010101010101
++                  -> doesn't match
++
++          filter  0x0101010101010101
++          mask    0x0303030303030303
++                  -> matches
++    ]]></programlisting>
++
++    <para>
++      Hence, in order to catch all messages, a mask filled with
++      <constant>0xff</constant> bytes can be installed as a wildcard match rule.
++    </para>
++
++    <refsect2>
++      <title>Generations</title>
++
++      <para>
++        Uploaded matches may contain multiple masks, which have to be as large
++        as the bloom filter size defined by the bus. Each block of a mask is
++        called a <emphasis>generation</emphasis>, starting at index 0.
++
++        At match time, when a signal is about to be delivered, a bloom mask
++        generation is passed, which denotes which of the bloom masks the filter
++        should be matched against. This allows programs to provide backward
++        compatible masks at upload time, while older clients can still match
++        against older versions of filters.
++      </para>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>Matches for kernel notifications</title>
++    <para>
++      To receive kernel generated notifications (see
++      <citerefentry>
++        <refentrytitle>kdbus.message</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>),
++      a connection must install match rules that are different from
++      the bloom filter matches described in the section above. They can be
++      filtered by the connection ID that caused the notification to be sent, by
++      one of the names it currently owns, or by the type of the notification
++      (ID/name add/remove/change).
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Adding a match</title>
++    <para>
++      To add a match, the <constant>KDBUS_CMD_MATCH_ADD</constant> ioctl is
++      used, which takes a <type>struct kdbus_cmd_match</type> as an argument
++      described below.
++
++      Note that each of the items attached to this command will internally
++      create one match <emphasis>rule</emphasis>, and the collection of them,
++      which is submitted as one block via the ioctl, is called a
++      <emphasis>match</emphasis>. To allow a message to pass, all rules of a
++      match have to be satisfied. Hence, adding more items to the command will
++      only narrow the possibility of a match to effectively let the message
++      pass, and will decrease the chance that the connection's process will be
++      woken up needlessly.
++
++      Multiple matches can be installed per connection. As long as one of it has
++      a set of rules which allows the message to pass, this one will be
++      decisive.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd_match {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  __u64 cookie;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>Flags to control the behavior of the ioctl.</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_MATCH_REPLACE</constant></term>
++              <listitem>
++                <para>Make the endpoint file group-accessible</para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Requests a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will return
++                  <errorcode>0</errorcode>, and the <varname>flags</varname>
++                  field will have all bits set that are valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>cookie</varname></term>
++        <listitem><para>
++          A cookie which identifies the match, so it can be referred to when
++          removing it.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++        <para>
++          Items to define the actual rules of the matches. The following item
++          types are expected. Each item will create one new match rule.
++        </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_BLOOM_MASK</constant></term>
++              <listitem>
++                <para>
++                  An item that carries the bloom filter mask to match against
++                  in its data field. The payload size must match the bloom
++                  filter size that was specified when the bus was created.
++                  See the "Bloom filters" section above for more information on
++                  bloom filters.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NAME</constant></term>
++              <listitem>
++                <para>
++                  When used as part of kernel notifications, this item specifies
++                  a name that is acquired, lost or that changed its owner (see
++                  below). When used as part of a match for user-generated signal
++                  messages, it specifies a name that the sending connection must
++                  own at the time of sending the signal.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_ID</constant></term>
++              <listitem>
++                <para>
++                  Specify a sender connection's ID that will match this rule.
++                  For kernel notifications, this specifies the ID of a
++                  connection that was added to or removed from the bus.
++                  For used-generated signals, it specifies the ID of the
++                  connection that sent the signal message.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NAME_ADD</constant></term>
++              <term><constant>KDBUS_ITEM_NAME_REMOVE</constant></term>
++              <term><constant>KDBUS_ITEM_NAME_CHANGE</constant></term>
++              <listitem>
++                <para>
++                  These items request delivery of kernel notifications that
++                  describe a name acquisition, loss, or change. The details
++                  are stored in the item's
++                  <varname>kdbus_notify_name_change</varname> member.
++                  All information specified must be matched in order to make
++                  the message pass. Use
++                  <constant>KDBUS_MATCH_ID_ANY</constant> to
++                  match against any unique connection ID.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_ID_ADD</constant></term>
++              <term><constant>KDBUS_ITEM_ID_REMOVE</constant></term>
++              <listitem>
++                <para>
++                  These items request delivery of kernel notifications that are
++                  generated when a connection is created or terminated.
++                  <type>struct kdbus_notify_id_change</type> is used to
++                  store the actual match information. This item can be used to
++                  monitor one particular connection ID, or, when the ID field
++                  is set to <constant>KDBUS_MATCH_ID_ANY</constant>,
++                  all of them.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term>
++              <listitem><para>
++                With this item, programs can <emphasis>probe</emphasis> the
++                kernel for known item types. See
++                <citerefentry>
++                  <refentrytitle>kdbus.item</refentrytitle>
++                  <manvolnum>7</manvolnum>
++                </citerefentry>
++                for more details.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      Refer to
++      <citerefentry>
++        <refentrytitle>kdbus.message</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information on message types.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Removing a match</title>
++    <para>
++      Matches can be removed with the
++      <constant>KDBUS_CMD_MATCH_REMOVE</constant> ioctl, which takes
++      <type>struct kdbus_cmd_match</type> as argument, but its fields
++      usage slightly differs compared to that of
++      <constant>KDBUS_CMD_MATCH_ADD</constant>.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd_match {
++  __u64 size;
++  __u64 cookie;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>cookie</varname></term>
++        <listitem><para>
++          The cookie of the match, as it was passed when the match was added.
++          All matches that have this cookie will be removed.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          No flags are supported for this use case.
++          <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for
++          valid flags. If set, the ioctl will fail with
++          <errorcode>-1</errorcode>, <varname>errno</varname> is set to
++          <constant>EPROTO</constant>, and the <varname>flags</varname> field
++          is set to <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            No items are supported for this use case, but
++            <constant>KDBUS_ITEM_NEGOTIATE</constant> is allowed nevertheless.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>
++      On success, all mentioned ioctl commands return <errorcode>0</errorcode>;
++      on error, <errorcode>-1</errorcode> is returned, and
++      <varname>errno</varname> is set to indicate the error.
++      If the issued ioctl is illegal for the file descriptor used,
++      <varname>errno</varname> will be set to <constant>ENOTTY</constant>.
++    </para>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_MATCH_ADD</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Illegal flags or items.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EDOM</constant></term>
++          <listitem><para>
++            Illegal bloom filter size.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EMFILE</constant></term>
++          <listitem><para>
++            Too many matches for this connection.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_MATCH_REMOVE</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Illegal flags.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EBADSLT</constant></term>
++          <listitem><para>
++            A match entry with the given cookie could not be found.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.match</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.fs</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.message.xml b/Documentation/kdbus/kdbus.message.xml
+new file mode 100644
+index 0000000..0115d9d
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.message.xml
+@@ -0,0 +1,1276 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.message">
++
++  <refentryinfo>
++    <title>kdbus.message</title>
++    <productname>kdbus.message</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.message</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.message</refname>
++    <refpurpose>kdbus message</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>
++      A kdbus message is used to exchange information between two connections
++      on a bus, or to transport notifications from the kernel to one or many
++      connections. This document describes the layout of messages, how payload
++      is added to them and how they are sent and received.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Message layout</title>
++
++    <para>The layout of a message is shown below.</para>
++
++    <programlisting>
++  +-------------------------------------------------------------------------+
++  | Message                                                                 |
++  | +---------------------------------------------------------------------+ |
++  | | Header                                                              | |
++  | | size:          overall message size, including the data records     | |
++  | | destination:   connection ID of the receiver                        | |
++  | | source:        connection ID of the sender (set by kernel)          | |
++  | | payload_type:  "DBusDBus" textual identifier stored as uint64_t     | |
++  | +---------------------------------------------------------------------+ |
++  | +---------------------------------------------------------------------+ |
++  | | Data Record                                                         | |
++  | | size:  overall record size (without padding)                        | |
++  | | type:  type of data                                                 | |
++  | | data:  reference to data (address or file descriptor)               | |
++  | +---------------------------------------------------------------------+ |
++  | +---------------------------------------------------------------------+ |
++  | | padding bytes to the next 8 byte alignment                          | |
++  | +---------------------------------------------------------------------+ |
++  | +---------------------------------------------------------------------+ |
++  | | Data Record                                                         | |
++  | | size:  overall record size (without padding)                        | |
++  | | ...                                                                 | |
++  | +---------------------------------------------------------------------+ |
++  | +---------------------------------------------------------------------+ |
++  | | padding bytes to the next 8 byte alignment                          | |
++  | +---------------------------------------------------------------------+ |
++  | +---------------------------------------------------------------------+ |
++  | | Data Record                                                         | |
++  | | size:  overall record size                                          | |
++  | | ...                                                                 | |
++  | +---------------------------------------------------------------------+ |
++  |   ... further data records ...                                          |
++  +-------------------------------------------------------------------------+
++    </programlisting>
++  </refsect1>
++
++  <refsect1>
++    <title>Message payload</title>
++
++    <para>
++      When connecting to the bus, receivers request a memory pool of a given
++      size, large enough to carry all backlog of data enqueued for the
++      connection. The pool is internally backed by a shared memory file which
++      can be <function>mmap()</function>ed by the receiver. See
++      <citerefentry>
++        <refentrytitle>kdbus.pool</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information.
++    </para>
++
++    <para>
++      Message payload must be described in items attached to a message when
++      it is sent. A receiver can access the payload by looking at the items
++      that are attached to a message in its pool. The following items are used.
++    </para>
++
++    <variablelist>
++      <varlistentry>
++        <term><constant>KDBUS_ITEM_PAYLOAD_VEC</constant></term>
++        <listitem>
++          <para>
++            This item references a piece of memory on the sender side which is
++            directly copied into the receiver's pool. This way, two peers can
++            exchange data by effectively doing a single-copy from one process
++            to another; the kernel will not buffer the data anywhere else.
++            This item is never found in a message received by a connection.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><constant>KDBUS_ITEM_PAYLOAD_OFF</constant></term>
++        <listitem>
++          <para>
++            This item is attached to messages on the receiving side and points
++            to a memory area inside the receiver's pool. The
++            <varname>offset</varname> variable in the item denotes the memory
++            location relative to the message itself.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant></term>
++        <listitem>
++          <para>
++            Messages can reference <emphasis>memfd</emphasis> files which
++            contain the data. memfd files are tmpfs-backed files that allow
++            sealing of the content of the file, which prevents all writable
++            access to the file content.
++          </para>
++          <para>
++            Only memfds that have
++            <constant>(F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL)
++            </constant>
++            set are accepted as payload data, which enforces reliable passing of
++            data. The receiver can assume that neither the sender nor anyone
++            else can alter the content after the message is sent. If those
++            seals are not set on the memfd, the ioctl will fail with
++            <errorcode>-1</errorcode>, and <varname>errno</varname> will be
++            set to <constant>ETXTBUSY</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><constant>KDBUS_ITEM_FDS</constant></term>
++        <listitem>
++          <para>
++            Messages can transport regular file descriptors via
++            <constant>KDBUS_ITEM_FDS</constant>. This item carries an array
++            of <type>int</type> values in <varname>item.fd</varname>. The
++            maximum number of file descriptors in the item is
++            <constant>253</constant>, and only one item of this type is
++            accepted per message. All passed values must be valid file
++            descriptors; the open count of each file descriptors is increased
++            by installing it to the receiver's task. This item can only be
++            used for directed messages, not for broadcasts, and only to
++            remote peers that have opted-in for receiving file descriptors
++            at connection time (<constant>KDBUS_HELLO_ACCEPT_FD</constant>).
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      The sender must not make any assumptions on the type in which data is
++      received by the remote peer. The kernel is free to re-pack multiple
++      <constant>KDBUS_ITEM_PAYLOAD_VEC</constant> and
++      <constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant> payloads. For instance, the
++      kernel may decide to merge multiple <constant>VECs</constant> into a
++      single <constant>VEC</constant>, inline <constant>MEMFD</constant>
++      payloads into memory, or merge all passed <constant>VECs</constant> into a
++      single <constant>MEMFD</constant>. However, the kernel preserves the order
++      of passed data. This means that the order of all <constant>VEC</constant>
++      and <constant>MEMFD</constant> items is not changed in respect to each
++      other. In other words: All passed <constant>VEC</constant> and
++      <constant>MEMFD</constant> data payloads are treated as a single stream
++      of data that may be received by the remote peer in a different set of
++      chunks than it was sent as.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Sending messages</title>
++
++    <para>
++      Messages are passed to the kernel with the
++      <constant>KDBUS_CMD_SEND</constant> ioctl. Depending on the destination
++      address of the message, the kernel delivers the message to the specific
++      destination connection, or to some subset of all connections on the same
++      bus. Sending messages across buses is not possible. Messages are always
++      queued in the memory pool of the destination connection (see above).
++    </para>
++
++    <para>
++      The <constant>KDBUS_CMD_SEND</constant> ioctl uses a
++      <type>struct kdbus_cmd_send</type> to describe the message
++      transfer.
++    </para>
++    <programlisting>
++struct kdbus_cmd_send {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  __u64 msg_address;
++  struct kdbus_msg_info reply;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>Flags for message delivery</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_SEND_SYNC_REPLY</constant></term>
++              <listitem>
++                <para>
++                  By default, all calls to kdbus are considered asynchronous,
++                  non-blocking. However, as there are many use cases that need
++                  to wait for a remote peer to answer a method call, there's a
++                  way to send a message and wait for a reply in a synchronous
++                  fashion. This is what the
++                  <constant>KDBUS_SEND_SYNC_REPLY</constant> controls. The
++                  <constant>KDBUS_CMD_SEND</constant> ioctl will block until the
++                  reply has arrived, the timeout limit is reached, in case the
++                  remote connection was shut down, or if interrupted by a signal
++                  before any reply; see
++                  <citerefentry>
++                    <refentrytitle>signal</refentrytitle>
++                    <manvolnum>7</manvolnum>
++                  </citerefentry>.
++
++                  The offset of the reply message in the sender's pool is stored
++                  in <varname>reply</varname> when the ioctl has returned without
++                  error. Hence, there is no need for another
++                  <constant>KDBUS_CMD_RECV</constant> ioctl or anything else to
++                  receive the reply.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Request a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will fail with
++                  <errorcode>-1</errorcode>, <varname>errno</varname>
++                  is set to <constant>EPROTO</constant>.
++                  Once the ioctl returned, the <varname>flags</varname>
++                  field will have all bits set that the kernel recognizes as
++                  valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>msg_address</varname></term>
++        <listitem><para>
++          In this field, users have to provide a pointer to a message
++          (<type>struct kdbus_msg</type>) to send. See below for a
++          detailed description.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>reply</varname></term>
++        <listitem><para>
++          Only used for synchronous replies. See description of
++          <type>struct kdbus_cmd_recv</type> for more details.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            The following items are currently recognized.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_CANCEL_FD</constant></term>
++              <listitem>
++                <para>
++                  When this optional item is passed in, and the call is
++                  executed as SYNC call, the passed in file descriptor can be
++                  used as alternative cancellation point. The kernel will call
++                  <citerefentry>
++                    <refentrytitle>poll</refentrytitle>
++                    <manvolnum>2</manvolnum>
++                  </citerefentry>
++                  on this file descriptor, and once it reports any incoming
++                  bytes, the blocking send operation will be canceled; the
++                  blocking, synchronous ioctl call will return
++                  <errorcode>-1</errorcode>, and <varname>errno</varname> will
++                  be set to <errorname>ECANCELED</errorname>.
++                  Any type of file descriptor on which
++                  <citerefentry>
++                    <refentrytitle>poll</refentrytitle>
++                    <manvolnum>2</manvolnum>
++                  </citerefentry>
++                  can be called on can be used as payload to this item; for
++                  example, an eventfd can be used for this purpose, see
++                  <citerefentry>
++                    <refentrytitle>eventfd</refentrytitle>
++                    <manvolnum>2</manvolnum>
++                  </citerefentry>.
++                  For asynchronous message sending, this item is allowed but
++                  ignored.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      The message referenced by the <varname>msg_address</varname> above has
++      the following layout.
++    </para>
++
++    <programlisting>
++struct kdbus_msg {
++  __u64 size;
++  __u64 flags;
++  __s64 priority;
++  __u64 dst_id;
++  __u64 src_id;
++  __u64 payload_type;
++  __u64 cookie;
++  __u64 timeout_ns;
++  __u64 cookie_reply;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>Flags to describe message details.</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_MSG_EXPECT_REPLY</constant></term>
++              <listitem>
++                <para>
++                  Expect a reply to this message from the remote peer. With
++                  this bit set, the timeout_ns field must be set to a non-zero
++                  number of nanoseconds in which the receiving peer is expected
++                  to reply. If such a reply is not received in time, the sender
++                  will be notified with a timeout message (see below). The
++                  value must be an absolute value, in nanoseconds and based on
++                  <constant>CLOCK_MONOTONIC</constant>.
++                </para><para>
++                  For a message to be accepted as reply, it must be a direct
++                  message to the original sender (not a broadcast and not a
++                  signal message), and its
++                  <varname>kdbus_msg.cookie_reply</varname> must match the
++                  previous message's <varname>kdbus_msg.cookie</varname>.
++                </para><para>
++                  Expected replies also temporarily open the policy of the
++                  sending connection, so the other peer is allowed to respond
++                  within the given time window.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_MSG_NO_AUTO_START</constant></term>
++              <listitem>
++                <para>
++                  By default, when a message is sent to an activator
++                  connection, the activator is notified and will start an
++                  implementer. This flag inhibits that behavior. With this bit
++                  set, and the remote being an activator, the ioctl will fail
++                  with <varname>errno</varname> set to
++                  <constant>EADDRNOTAVAIL</constant>.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Requests a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will return
++                  <errorcode>0</errorcode>, and the <varname>flags</varname>
++                  field will have all bits set that are valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>priority</varname></term>
++        <listitem><para>
++          The priority of this message. Receiving messages (see below) may
++          optionally be constrained to messages of a minimal priority. This
++          allows for use cases where timing critical data is interleaved with
++          control data on the same connection. If unused, the priority field
++          should be set to <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>dst_id</varname></term>
++        <listitem><para>
++          The numeric ID of the destination connection, or
++          <constant>KDBUS_DST_ID_BROADCAST</constant>
++          (~0ULL) to address every peer on the bus, or
++          <constant>KDBUS_DST_ID_NAME</constant> (0) to look
++          it up dynamically from the bus' name registry.
++          In the latter case, an item of type
++          <constant>KDBUS_ITEM_DST_NAME</constant> is mandatory.
++          Also see
++          <citerefentry>
++            <refentrytitle>kdbus.name</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          .
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>src_id</varname></term>
++        <listitem><para>
++          Upon return of the ioctl, this member will contain the sending
++          connection's numerical ID. Should be 0 at send time.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>payload_type</varname></term>
++        <listitem><para>
++          Type of the payload in the actual data records. Currently, only
++          <constant>KDBUS_PAYLOAD_DBUS</constant> is accepted as input value
++          of this field. When receiving messages that are generated by the
++          kernel (notifications), this field will contain
++          <constant>KDBUS_PAYLOAD_KERNEL</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>cookie</varname></term>
++        <listitem><para>
++          Cookie of this message, for later recognition. Also, when replying
++          to a message (see above), the <varname>cookie_reply</varname>
++          field must match this value.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>timeout_ns</varname></term>
++        <listitem><para>
++          If the message sent requires a reply from the remote peer (see above),
++          this field contains the timeout in absolute nanoseconds based on
++          <constant>CLOCK_MONOTONIC</constant>. Also see
++          <citerefentry>
++            <refentrytitle>clock_gettime</refentrytitle>
++            <manvolnum>2</manvolnum>
++          </citerefentry>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>cookie_reply</varname></term>
++        <listitem><para>
++          If the message sent is a reply to another message, this field must
++          match the cookie of the formerly received message.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            A dynamically sized list of items to contain additional information.
++            The following items are expected/valid:
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_PAYLOAD_VEC</constant></term>
++              <term><constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant></term>
++              <term><constant>KDBUS_ITEM_FDS</constant></term>
++              <listitem>
++                <para>
++                  Actual data records containing the payload. See section
++                  "Message payload".
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_BLOOM_FILTER</constant></term>
++              <listitem>
++                <para>
++                  Bloom filter for matches (see below).
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_ITEM_DST_NAME</constant></term>
++              <listitem>
++                <para>
++                  Well-known name to send this message to. Required if
++                  <varname>dst_id</varname> is set to
++                  <constant>KDBUS_DST_ID_NAME</constant>.
++                  If a connection holding the given name can't be found,
++                  the ioctl will fail with <varname>errno</varname> set to
++                  <constant>ESRCH</constant> is returned.
++                </para>
++                <para>
++                  For messages to a unique name (ID), this item is optional. If
++                  present, the kernel will make sure the name owner matches the
++                  given unique name. This allows programs to tie the message
++                  sending to the condition that a name is currently owned by a
++                  certain unique name.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      The message will be augmented by the requested metadata items when
++      queued into the receiver's pool. See
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      and
++      <citerefentry>
++        <refentrytitle>kdbus.item</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information on metadata.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Receiving messages</title>
++
++    <para>
++      Messages are received by the client with the
++      <constant>KDBUS_CMD_RECV</constant> ioctl. The endpoint file of the bus
++      supports <function>poll()/epoll()/select()</function>; when new messages
++      are available on the connection's file descriptor,
++      <constant>POLLIN</constant> is reported. For compatibility reasons,
++      <constant>POLLOUT</constant> is always reported as well. Note, however,
++      that the latter does not guarantee that a message can in fact be sent, as
++      this depends on how many pending messages the receiver has in its pool.
++    </para>
++
++    <para>
++      With the <constant>KDBUS_CMD_RECV</constant> ioctl, a
++      <type>struct kdbus_cmd_recv</type> is used.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd_recv {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  __s64 priority;
++  __u64 dropped_msgs;
++  struct kdbus_msg_info msg;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>Flags to control the receive command.</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_RECV_PEEK</constant></term>
++              <listitem>
++                <para>
++                  Just return the location of the next message. Do not install
++                  file descriptors or anything else. This is usually used to
++                  determine the sender of the next queued message.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_RECV_DROP</constant></term>
++              <listitem>
++                <para>
++                  Drop the next message without doing anything else with it,
++                  and free the pool slice. This a short-cut for
++                  <constant>KDBUS_RECV_PEEK</constant> and
++                  <constant>KDBUS_CMD_FREE</constant>.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_RECV_USE_PRIORITY</constant></term>
++              <listitem>
++                <para>
++                  Dequeue the messages ordered by their priority, and filtering
++                  them with the priority field (see below).
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Request a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will fail with
++                  <errorcode>-1</errorcode>, <varname>errno</varname>
++                  is set to <constant>EPROTO</constant>.
++                  Once the ioctl returned, the <varname>flags</varname>
++                  field will have all bits set that the kernel recognizes as
++                  valid for this command.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. If the <varname>dropped_msgs</varname>
++          field is non-zero, <constant>KDBUS_RECV_RETURN_DROPPED_MSGS</constant>
++          is set. If a file descriptor could not be installed, the
++          <constant>KDBUS_RECV_RETURN_INCOMPLETE_FDS</constant> flag is set.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>priority</varname></term>
++        <listitem><para>
++          With <constant>KDBUS_RECV_USE_PRIORITY</constant> set in
++          <varname>flags</varname>, messages will be dequeued ordered by their
++          priority, starting with the highest value. Also, messages will be
++          filtered by the value given in this field, so the returned message
++          will at least have the requested priority. If no such message is
++          waiting in the queue, the ioctl will fail, and
++          <varname>errno</varname> will be set to <constant>EAGAIN</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>dropped_msgs</varname></term>
++        <listitem><para>
++          Whenever a message with <constant>KDBUS_MSG_SIGNAL</constant> is sent
++          but cannot be queued on a peer (e.g., as it contains FDs but the peer
++          does not support FDs, or there is no space left in the peer's pool)
++          the 'dropped_msgs' counter of the peer is incremented. On the next
++          RECV ioctl, the 'dropped_msgs' field is copied into the ioctl struct
++          and cleared on the peer. If it was non-zero, the
++          <constant>KDBUS_RECV_RETURN_DROPPED_MSGS</constant> flag will be set
++          in <varname>return_flags</varname>. Note that this will only happen
++          if the ioctl succeeded or failed with <constant>EAGAIN</constant>. In
++          other error cases, the 'dropped_msgs' field of the peer is left
++          untouched.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>msg</varname></term>
++        <listitem><para>
++          Embedded struct containing information on the received message when
++          this command succeeded (see below).
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem><para>
++          Items to specify further details for the receive command.
++          Currently unused, and all items will be rejected with
++          <varname>errno</varname> set to <constant>EINVAL</constant>.
++        </para></listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      Both <type>struct kdbus_cmd_recv</type> and
++      <type>struct kdbus_cmd_send</type> embed
++      <type>struct kdbus_msg_info</type>.
++      For the <constant>KDBUS_CMD_SEND</constant> ioctl, it is used to catch
++      synchronous replies, if one was requested, and is unused otherwise.
++    </para>
++
++    <programlisting>
++struct kdbus_msg_info {
++  __u64 offset;
++  __u64 msg_size;
++  __u64 return_flags;
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>offset</varname></term>
++        <listitem><para>
++          Upon return of the ioctl, this field contains the offset in the
++          receiver's memory pool. The memory must be freed with
++          <constant>KDBUS_CMD_FREE</constant>. See
++          <citerefentry>
++            <refentrytitle>kdbus.pool</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for further details.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>msg_size</varname></term>
++        <listitem><para>
++          Upon successful return of the ioctl, this field contains the size of
++          the allocated slice at offset <varname>offset</varname>.
++          It is the combination of the size of the stored
++          <type>struct kdbus_msg</type> object plus all appended VECs.
++          You can use it in combination with <varname>offset</varname> to map
++          a single message, instead of mapping the entire pool. See
++          <citerefentry>
++            <refentrytitle>kdbus.pool</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for further details.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem>
++          <para>
++            Kernel-provided return flags. Currently, the following flags are
++            defined.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_RECV_RETURN_INCOMPLETE_FDS</constant></term>
++              <listitem>
++                <para>
++                  The message contained memfds or file descriptors, and the
++                  kernel failed to install one or more of them at receive time.
++                  Most probably that happened because the maximum number of
++                  file descriptors for the receiver's task were exceeded.
++                  In such cases, the message is still delivered, so this is not
++                  a fatal condition. File descriptors numbers inside the
++                  <constant>KDBUS_ITEM_FDS</constant> item or memfd files
++                  referenced by <constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant>
++                  items which could not be installed will be set to
++                  <constant>-1</constant>.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      Unless <constant>KDBUS_RECV_DROP</constant> was passed, the
++      <varname>offset</varname> field contains the location of the new message
++      inside the receiver's pool after the <constant>KDBUS_CMD_RECV</constant>
++      ioctl was employed. The message is stored as <type>struct kdbus_msg</type>
++      at this offset, and can be interpreted with the semantics described above.
++    </para>
++    <para>
++      Also, if the connection allowed for file descriptor to be passed
++      (<constant>KDBUS_HELLO_ACCEPT_FD</constant>), and if the message contained
++      any, they will be installed into the receiving process when the
++      <constant>KDBUS_CMD_RECV</constant> ioctl is called.
++      <emphasis>memfds</emphasis> may always be part of the message payload.
++      The receiving task is obliged to close all file descriptors appropriately
++      once no longer needed. If <constant>KDBUS_RECV_PEEK</constant> is set, no
++      file descriptors are installed. This allows for peeking at a message,
++      looking at its metadata only and dropping it via
++      <constant>KDBUS_RECV_DROP</constant>, without installing any of the file
++      descriptors into the receiving process.
++    </para>
++    <para>
++      The caller is obliged to call the <constant>KDBUS_CMD_FREE</constant>
++      ioctl with the returned offset when the memory is no longer needed.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Notifications</title>
++    <para>
++      A kernel notification is a regular kdbus message with the following
++      details.
++    </para>
++
++    <itemizedlist>
++      <listitem><para>
++          kdbus_msg.src_id == <constant>KDBUS_SRC_ID_KERNEL</constant>
++      </para></listitem>
++      <listitem><para>
++        kdbus_msg.dst_id == <constant>KDBUS_DST_ID_BROADCAST</constant>
++      </para></listitem>
++      <listitem><para>
++        kdbus_msg.payload_type == <constant>KDBUS_PAYLOAD_KERNEL</constant>
++      </para></listitem>
++      <listitem><para>
++        Has exactly one of the items attached that are described below.
++      </para></listitem>
++      <listitem><para>
++        Always has a timestamp item (<constant>KDBUS_ITEM_TIMESTAMP</constant>)
++        attached.
++      </para></listitem>
++    </itemizedlist>
++
++    <para>
++      The kernel will notify its users of the following events.
++    </para>
++
++    <itemizedlist>
++      <listitem><para>
++        When connection <emphasis>A</emphasis> is terminated while connection
++        <emphasis>B</emphasis> is waiting for a reply from it, connection
++        <emphasis>B</emphasis> is notified with a message with an item of
++        type <constant>KDBUS_ITEM_REPLY_DEAD</constant>.
++      </para></listitem>
++
++      <listitem><para>
++        When connection <emphasis>A</emphasis> does not receive a reply from
++        connection <emphasis>B</emphasis> within the specified timeout window,
++        connection <emphasis>A</emphasis> will receive a message with an
++        item of type <constant>KDBUS_ITEM_REPLY_TIMEOUT</constant>.
++      </para></listitem>
++
++      <listitem><para>
++        When an ordinary connection (not a monitor) is created on or removed
++        from a bus, messages with an item of type
++        <constant>KDBUS_ITEM_ID_ADD</constant> or
++        <constant>KDBUS_ITEM_ID_REMOVE</constant>, respectively, are delivered
++        to all bus members that match these messages through their match
++        database. Eavesdroppers (monitor connections) do not cause such
++        notifications to be sent. They are invisible on the bus.
++      </para></listitem>
++
++      <listitem><para>
++        When a connection gains or loses ownership of a name, messages with an
++        item of type <constant>KDBUS_ITEM_NAME_ADD</constant>,
++        <constant>KDBUS_ITEM_NAME_REMOVE</constant> or
++        <constant>KDBUS_ITEM_NAME_CHANGE</constant> are delivered to all bus
++        members that match these messages through their match database.
++      </para></listitem>
++    </itemizedlist>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>
++      On success, all mentioned ioctl commands return <errorcode>0</errorcode>;
++      on error, <errorcode>-1</errorcode> is returned, and
++      <varname>errno</varname> is set to indicate the error.
++      If the issued ioctl is illegal for the file descriptor used,
++      <varname>errno</varname> will be set to <constant>ENOTTY</constant>.
++    </para>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_SEND</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EOPNOTSUPP</constant></term>
++          <listitem><para>
++            The connection is not an ordinary connection, or the passed
++            file descriptors in <constant>KDBUS_ITEM_FDS</constant> item are
++            either kdbus handles or unix domain sockets. Both are currently
++            unsupported.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            The submitted payload type is
++            <constant>KDBUS_PAYLOAD_KERNEL</constant>,
++            <constant>KDBUS_MSG_EXPECT_REPLY</constant> was set without timeout
++            or cookie values, <constant>KDBUS_SEND_SYNC_REPLY</constant> was
++            set without <constant>KDBUS_MSG_EXPECT_REPLY</constant>, an invalid
++            item was supplied, <constant>src_id</constant> was non-zero and was
++            different from the current connection's ID, a supplied memfd had a
++            size of 0, or a string was not properly null-terminated.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ENOTUNIQ</constant></term>
++          <listitem><para>
++            The supplied destination is
++            <constant>KDBUS_DST_ID_BROADCAST</constant> and either
++            file descriptors were passed, or
++            <constant>KDBUS_MSG_EXPECT_REPLY</constant> was set,
++            or a timeout was given.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>E2BIG</constant></term>
++          <listitem><para>
++            Too many items.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EMSGSIZE</constant></term>
++          <listitem><para>
++            The size of the message header and items or the payload vector
++            is excessive.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EEXIST</constant></term>
++          <listitem><para>
++            Multiple <constant>KDBUS_ITEM_FDS</constant>,
++            <constant>KDBUS_ITEM_BLOOM_FILTER</constant> or
++            <constant>KDBUS_ITEM_DST_NAME</constant> items were supplied.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EBADF</constant></term>
++          <listitem><para>
++            The supplied <constant>KDBUS_ITEM_FDS</constant> or
++            <constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant> items
++            contained an illegal file descriptor.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EMEDIUMTYPE</constant></term>
++          <listitem><para>
++            The supplied memfd is not a sealed kdbus memfd.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EMFILE</constant></term>
++          <listitem><para>
++            Too many file descriptors inside a
++            <constant>KDBUS_ITEM_FDS</constant>.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EBADMSG</constant></term>
++          <listitem><para>
++            An item had illegal size, both a <constant>dst_id</constant> and a
++            <constant>KDBUS_ITEM_DST_NAME</constant> was given, or both a name
++            and a bloom filter was given.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ETXTBSY</constant></term>
++          <listitem><para>
++            The supplied kdbus memfd file cannot be sealed or the seal
++            was removed, because it is shared with other processes or
++            still mapped with
++            <citerefentry>
++              <refentrytitle>mmap</refentrytitle>
++              <manvolnum>2</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ECOMM</constant></term>
++          <listitem><para>
++            A peer does not accept the file descriptors addressed to it.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EFAULT</constant></term>
++          <listitem><para>
++            The supplied bloom filter size was not 64-bit aligned, or supplied
++            memory could not be accessed by the kernel.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EDOM</constant></term>
++          <listitem><para>
++            The supplied bloom filter size did not match the bloom filter
++            size of the bus.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EDESTADDRREQ</constant></term>
++          <listitem><para>
++            <constant>dst_id</constant> was set to
++            <constant>KDBUS_DST_ID_NAME</constant>, but no
++            <constant>KDBUS_ITEM_DST_NAME</constant> was attached.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ESRCH</constant></term>
++          <listitem><para>
++            The name to look up was not found in the name registry.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EADDRNOTAVAIL</constant></term>
++          <listitem><para>
++            <constant>KDBUS_MSG_NO_AUTO_START</constant> was given but the
++            destination connection is an activator.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ENXIO</constant></term>
++          <listitem><para>
++            The passed numeric destination connection ID couldn't be found,
++            or is not connected.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ECONNRESET</constant></term>
++          <listitem><para>
++            The destination connection is no longer active.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ETIMEDOUT</constant></term>
++          <listitem><para>
++            Timeout while synchronously waiting for a reply.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINTR</constant></term>
++          <listitem><para>
++            Interrupted system call while synchronously waiting for a reply.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EPIPE</constant></term>
++          <listitem><para>
++            When sending a message, a synchronous reply from the receiving
++            connection was expected but the connection died before answering.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ENOBUFS</constant></term>
++          <listitem><para>
++            Too many pending messages on the receiver side.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EREMCHG</constant></term>
++          <listitem><para>
++            Both a well-known name and a unique name (ID) was given, but
++            the name is not currently owned by that connection.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EXFULL</constant></term>
++          <listitem><para>
++            The memory pool of the receiver is full.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EREMOTEIO</constant></term>
++          <listitem><para>
++            While synchronously waiting for a reply, the remote peer
++            failed with an I/O error.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_RECV</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EOPNOTSUPP</constant></term>
++          <listitem><para>
++            The connection is not an ordinary connection, or the passed
++            file descriptors are either kdbus handles or unix domain
++            sockets. Both are currently unsupported.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Invalid flags or offset.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EAGAIN</constant></term>
++          <listitem><para>
++            No message found in the queue.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.fs</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>clock_gettime</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>ioctl</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>poll</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>select</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>epoll</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>eventfd</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>memfd_create</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.name.xml b/Documentation/kdbus/kdbus.name.xml
+new file mode 100644
+index 0000000..3f5f6a6
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.name.xml
+@@ -0,0 +1,711 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.name">
++
++  <refentryinfo>
++    <title>kdbus.name</title>
++    <productname>kdbus.name</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.name</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.name</refname>
++    <refpurpose>kdbus.name</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++    <para>
++      Each
++      <citerefentry>
++        <refentrytitle>kdbus.bus</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      instantiates a name registry to resolve well-known names into unique
++      connection IDs for message delivery. The registry will be queried when a
++      message is sent with <varname>kdbus_msg.dst_id</varname> set to
++      <constant>KDBUS_DST_ID_NAME</constant>, or when a registry dump is
++      requested with <constant>KDBUS_CMD_NAME_LIST</constant>.
++    </para>
++
++    <para>
++      All of the below is subject to policy rules for <emphasis>SEE</emphasis>
++      and <emphasis>OWN</emphasis> permissions. See
++      <citerefentry>
++        <refentrytitle>kdbus.policy</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Name validity</title>
++    <para>
++      A name has to comply with the following rules in order to be considered
++      valid.
++    </para>
++
++    <itemizedlist>
++      <listitem>
++        <para>
++          The name has two or more elements separated by a
++          '<literal>.</literal>' (period) character.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          All elements must contain at least one character.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          Each element must only contain the ASCII characters
++          <literal>[A-Z][a-z][0-9]_</literal> and must not begin with a
++          digit.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          The name must contain at least one '<literal>.</literal>' (period)
++          character (and thus at least two elements).
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          The name must not begin with a '<literal>.</literal>' (period)
++          character.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          The name must not exceed <constant>255</constant> characters in
++          length.
++        </para>
++      </listitem>
++    </itemizedlist>
++  </refsect1>
++
++  <refsect1>
++    <title>Acquiring a name</title>
++    <para>
++      To acquire a name, a client uses the
++      <constant>KDBUS_CMD_NAME_ACQUIRE</constant> ioctl with
++      <type>struct kdbus_cmd</type> as argument.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>Flags to control details in the name acquisition.</para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_NAME_REPLACE_EXISTING</constant></term>
++              <listitem>
++                <para>
++                  Acquiring a name that is already present usually fails,
++                  unless this flag is set in the call, and
++                  <constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant> (see below)
++                  was set when the current owner of the name acquired it, or
++                  if the current owner is an activator connection (see
++                  <citerefentry>
++                    <refentrytitle>kdbus.connection</refentrytitle>
++                    <manvolnum>7</manvolnum>
++                  </citerefentry>).
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant></term>
++              <listitem>
++                <para>
++                  Allow other connections to take over this name. When this
++                  happens, the former owner of the connection will be notified
++                  of the name loss.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_NAME_QUEUE</constant></term>
++              <listitem>
++                <para>
++                  A name that is already acquired by a connection can not be
++                  acquired again (unless the
++                  <constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant> flag was
++                  set during acquisition; see above).
++                  However, a connection can put itself in a queue of
++                  connections waiting for the name to be released. Once that
++                  happens, the first connection in that queue becomes the new
++                  owner and is notified accordingly.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Request a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will fail with
++                  <errorcode>-1</errorcode>, and <varname>errno</varname>
++                  is set to <constant>EPROTO</constant>.
++                  Once the ioctl returned, the <varname>flags</varname>
++                  field will have all bits set that the kernel recognizes as
++                  valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem>
++          <para>
++            Flags returned by the kernel. Currently, the following may be
++            returned by the kernel.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_NAME_IN_QUEUE</constant></term>
++              <listitem>
++                <para>
++                  The name was not acquired yet, but the connection was
++                  placed in the queue of peers waiting for the name.
++                  This can only happen if <constant>KDBUS_NAME_QUEUE</constant>
++                  was set in the <varname>flags</varname> member (see above).
++                  The connection will receive a name owner change notification
++                  once the current owner has given up the name and its
++                  ownership was transferred.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            Items to submit the name. Currently, one item of type
++            <constant>KDBUS_ITEM_NAME</constant> is expected and allowed, and
++            the contained string must be a valid bus name.
++            <constant>KDBUS_ITEM_NEGOTIATE</constant> may be used to probe for
++            valid item types. See
++            <citerefentry>
++              <refentrytitle>kdbus.item</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for a detailed description of how this item is used.
++          </para>
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <errorname>>EINVAL</errorname>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Releasing a name</title>
++    <para>
++      A connection may release a name explicitly with the
++      <constant>KDBUS_CMD_NAME_RELEASE</constant> ioctl. If the connection was
++      an implementer of an activatable name, its pending messages are moved
++      back to the activator. If there are any connections queued up as waiters
++      for the name, the first one in the queue (the oldest entry) will become
++      the new owner. The same happens implicitly for all names once a
++      connection terminates. See
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information on connections.
++    </para>
++    <para>
++      The <constant>KDBUS_CMD_NAME_RELEASE</constant> ioctl uses the same data
++      structure as the acquisition call
++      (<constant>KDBUS_CMD_NAME_ACQUIRE</constant>),
++      but with slightly different field usage.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          Flags to the command. Currently unused.
++          <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for
++          valid flags. If set, the ioctl will return <errorcode>0</errorcode>,
++          and the <varname>flags</varname> field is set to
++          <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            Items to submit the name. Currently, one item of type
++            <constant>KDBUS_ITEM_NAME</constant> is expected and allowed, and
++            the contained string must be a valid bus name.
++            <constant>KDBUS_ITEM_NEGOTIATE</constant> may be used to probe for
++            valid item types. See
++            <citerefentry>
++              <refentrytitle>kdbus.item</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++            for a detailed description of how this item is used.
++          </para>
++          <para>
++            Unrecognized items are rejected, and the ioctl will fail with
++            <varname>errno</varname> set to <constant>EINVAL</constant>.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Dumping the name registry</title>
++    <para>
++      A connection may request a complete or filtered dump of currently active
++      bus names with the <constant>KDBUS_CMD_LIST</constant> ioctl, which
++      takes a <type>struct kdbus_cmd_list</type> as argument.
++    </para>
++
++    <programlisting>
++struct kdbus_cmd_list {
++  __u64 flags;
++  __u64 return_flags;
++  __u64 offset;
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem>
++          <para>
++            Any combination of flags to specify which names should be dumped.
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_LIST_UNIQUE</constant></term>
++              <listitem>
++                <para>
++                  List the unique (numeric) IDs of the connection, whether it
++                  owns a name or not.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_LIST_NAMES</constant></term>
++              <listitem>
++                <para>
++                  List well-known names stored in the database which are
++                  actively owned by a real connection (not an activator).
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_LIST_ACTIVATORS</constant></term>
++              <listitem>
++                <para>
++                  List names that are owned by an activator.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_LIST_QUEUED</constant></term>
++              <listitem>
++                <para>
++                  List connections that are not yet owning a name but are
++                  waiting for it to become available.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Request a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will fail with
++                  <errorcode>-1</errorcode>, and <varname>errno</varname>
++                  is set to <constant>EPROTO</constant>.
++                  Once the ioctl returned, the <varname>flags</varname>
++                  field will have all bits set that the kernel recognizes as
++                  valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>offset</varname></term>
++        <listitem><para>
++          When the ioctl returns successfully, the offset to the name registry
++          dump inside the connection's pool will be stored in this field.
++        </para></listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      The returned list of names is stored in a <type>struct kdbus_list</type>
++      that in turn contains an array of type <type>struct kdbus_info</type>,
++      The array-size in bytes is given as <varname>list_size</varname>.
++      The fields inside <type>struct kdbus_info</type> is described next.
++    </para>
++
++    <programlisting>
++struct kdbus_info {
++  __u64 size;
++  __u64 id;
++  __u64 flags;
++  struct kdbus_item items[0];
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>id</varname></term>
++        <listitem><para>
++          The owning connection's unique ID.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          The flags of the owning connection.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem>
++          <para>
++            Items containing the actual name. Currently, one item of type
++            <constant>KDBUS_ITEM_OWNED_NAME</constant> will be attached,
++            including the name's flags. In that item, the flags field of the
++            name may carry the following bits:
++          </para>
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant></term>
++              <listitem>
++                <para>
++                  Other connections are allowed to take over this name from the
++                  connection that owns it.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_NAME_IN_QUEUE</constant></term>
++              <listitem>
++                <para>
++                  When retrieving a list of currently acquired names in the
++                  registry, this flag indicates whether the connection
++                  actually owns the name or is currently waiting for it to
++                  become available.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_NAME_ACTIVATOR</constant></term>
++              <listitem>
++                <para>
++                  An activator connection owns a name as a placeholder for an
++                  implementer, which is started on demand by programs as soon
++                  as the first message arrives. There's some more information
++                  on this topic in
++                  <citerefentry>
++                    <refentrytitle>kdbus.connection</refentrytitle>
++                    <manvolnum>7</manvolnum>
++                  </citerefentry>
++                  .
++                </para>
++                <para>
++                  In contrast to
++                  <constant>KDBUS_NAME_REPLACE_EXISTING</constant>,
++                  when a name is taken over from an activator connection, all
++                  the messages that have been queued in the activator
++                  connection will be moved over to the new owner. The activator
++                  connection will still be tracked for the name and will take
++                  control again if the implementer connection terminates.
++                </para>
++                <para>
++                  This flag can not be used when acquiring a name, but is
++                  implicitly set through <constant>KDBUS_CMD_HELLO</constant>
++                  with <constant>KDBUS_HELLO_ACTIVATOR</constant> set in
++                  <varname>kdbus_cmd_hello.conn_flags</varname>.
++                </para>
++              </listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term>
++              <listitem>
++                <para>
++                  Requests a set of valid flags for this ioctl. When this bit is
++                  set, no action is taken; the ioctl will return
++                  <errorcode>0</errorcode>, and the <varname>flags</varname>
++                  field will have all bits set that are valid for this command.
++                  The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be
++                  cleared by the operation.
++                </para>
++              </listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      The returned buffer must be freed with the
++      <constant>KDBUS_CMD_FREE</constant> ioctl when the user is finished with
++      it. See
++      <citerefentry>
++        <refentrytitle>kdbus.pool</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>
++      On success, all mentioned ioctl commands return <errorcode>0</errorcode>;
++      on error, <errorcode>-1</errorcode> is returned, and
++      <varname>errno</varname> is set to indicate the error.
++      If the issued ioctl is illegal for the file descriptor used,
++      <varname>errno</varname> will be set to <constant>ENOTTY</constant>.
++    </para>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_NAME_ACQUIRE</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Illegal command flags, illegal name provided, or an activator
++            tried to acquire a second name.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EPERM</constant></term>
++          <listitem><para>
++            Policy prohibited name ownership.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EALREADY</constant></term>
++          <listitem><para>
++            Connection already owns that name.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EEXIST</constant></term>
++          <listitem><para>
++            The name already exists and can not be taken over.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>E2BIG</constant></term>
++          <listitem><para>
++            The maximum number of well-known names per connection is exhausted.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_NAME_RELEASE</constant>
++        may fail with the following errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Invalid command flags, or invalid name provided.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ESRCH</constant></term>
++          <listitem><para>
++            Name is not found in the registry.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EADDRINUSE</constant></term>
++          <listitem><para>
++            Name is owned by a different connection and can't be released.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_LIST</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Invalid command flags
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>ENOBUFS</constant></term>
++          <listitem><para>
++            No available memory in the connection's pool.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.policy</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.policy.xml b/Documentation/kdbus/kdbus.policy.xml
+new file mode 100644
+index 0000000..6732416
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.policy.xml
+@@ -0,0 +1,406 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.policy">
++
++  <refentryinfo>
++    <title>kdbus.policy</title>
++    <productname>kdbus.policy</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.policy</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.policy</refname>
++    <refpurpose>kdbus policy</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para>
++      A kdbus policy restricts the possibilities of connections to own, see and
++      talk to well-known names. A policy can be associated with a bus (through a
++      policy holder connection) or a custom endpoint. kdbus stores its policy
++      information in a database that can be accessed through the following
++      ioctl commands:
++    </para>
++
++    <variablelist>
++      <varlistentry>
++        <term><constant>KDBUS_CMD_HELLO</constant></term>
++        <listitem><para>
++          When creating, or updating, a policy holder connection. See
++          <citerefentry>
++            <refentrytitle>kdbus.connection</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><constant>KDBUS_CMD_ENDPOINT_MAKE</constant></term>
++        <term><constant>KDBUS_CMD_ENDPOINT_UPDATE</constant></term>
++        <listitem><para>
++          When creating, or updating, a bus custom endpoint. See
++          <citerefentry>
++            <refentrytitle>kdbus.endpoint</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>.
++        </para></listitem>
++      </varlistentry>
++    </variablelist>
++
++    <para>
++      In all cases, the name and policy access information is stored in items
++      of type <constant>KDBUS_ITEM_NAME</constant> and
++      <constant>KDBUS_ITEM_POLICY_ACCESS</constant>. For this transport, the
++      following rules apply.
++    </para>
++
++    <itemizedlist>
++      <listitem>
++        <para>
++          An item of type <constant>KDBUS_ITEM_NAME</constant> must be followed
++          by at least one <constant>KDBUS_ITEM_POLICY_ACCESS</constant> item.
++        </para>
++      </listitem>
++
++      <listitem>
++        <para>
++          An item of type <constant>KDBUS_ITEM_NAME</constant> can be followed
++          by an arbitrary number of
++          <constant>KDBUS_ITEM_POLICY_ACCESS</constant> items.
++        </para>
++      </listitem>
++
++      <listitem>
++        <para>
++          An arbitrary number of groups of names and access levels can be given.
++        </para>
++      </listitem>
++    </itemizedlist>
++
++    <para>
++      Names passed in items of type <constant>KDBUS_ITEM_NAME</constant> must
++      comply to the rules of valid kdbus.name. See
++      <citerefentry>
++        <refentrytitle>kdbus.name</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information.
++
++      The payload of an item of type
++      <constant>KDBUS_ITEM_POLICY_ACCESS</constant> is defined by the following
++      struct. For more information on the layout of items, please refer to
++      <citerefentry>
++        <refentrytitle>kdbus.item</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>.
++    </para>
++
++    <programlisting>
++struct kdbus_policy_access {
++  __u64 type;
++  __u64 access;
++  __u64 id;
++};
++    </programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>type</varname></term>
++        <listitem>
++          <para>
++            One of the following.
++          </para>
++
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_POLICY_ACCESS_USER</constant></term>
++              <listitem><para>
++                Grant access to a user with the UID stored in the
++                <varname>id</varname> field.
++              </para></listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_POLICY_ACCESS_GROUP</constant></term>
++              <listitem><para>
++                Grant access to a user with the GID stored in the
++                <varname>id</varname> field.
++              </para></listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_POLICY_ACCESS_WORLD</constant></term>
++              <listitem><para>
++                Grant access to everyone. The <varname>id</varname> field
++                is ignored.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>access</varname></term>
++        <listitem>
++          <para>
++            The access to grant. One of the following.
++          </para>
++
++          <variablelist>
++            <varlistentry>
++              <term><constant>KDBUS_POLICY_SEE</constant></term>
++              <listitem><para>
++                Allow the name to be seen.
++              </para></listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_POLICY_TALK</constant></term>
++              <listitem><para>
++                Allow the name to be talked to.
++              </para></listitem>
++            </varlistentry>
++
++            <varlistentry>
++              <term><constant>KDBUS_POLICY_OWN</constant></term>
++              <listitem><para>
++                Allow the name to be owned.
++              </para></listitem>
++            </varlistentry>
++          </variablelist>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>id</varname></term>
++        <listitem><para>
++           For <constant>KDBUS_POLICY_ACCESS_USER</constant>, stores the UID.
++           For <constant>KDBUS_POLICY_ACCESS_GROUP</constant>, stores the GID.
++        </para></listitem>
++      </varlistentry>
++
++    </variablelist>
++
++    <para>
++      All endpoints of buses have an empty policy database by default.
++      Therefore, unless policy rules are added, all operations will also be
++      denied by default. Also see
++      <citerefentry>
++        <refentrytitle>kdbus.endpoint</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Wildcard names</title>
++    <para>
++      Policy holder connections may upload names that contain the wildcard
++      suffix (<literal>".*"</literal>). Such a policy entry is effective for
++      every well-known name that extends the provided name by exactly one more
++      level.
++
++      For example, the name <literal>foo.bar.*</literal> matches both
++      <literal>"foo.bar.baz"</literal> and
++      <literal>"foo.bar.bazbaz"</literal> are, but not
++      <literal>"foo.bar.baz.baz"</literal>.
++
++      This allows connections to take control over multiple names that the
++      policy holder doesn't need to know about when uploading the policy.
++
++      Such wildcard entries are not allowed for custom endpoints.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Privileged connections</title>
++    <para>
++      The policy database is overruled when action is taken by a privileged
++      connection. Please refer to
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information on what makes a connection privileged.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Examples</title>
++    <para>
++      For instance, a set of policy rules may look like this:
++    </para>
++
++    <programlisting>
++KDBUS_ITEM_NAME: str='org.foo.bar'
++KDBUS_ITEM_POLICY_ACCESS: type=USER, access=OWN, ID=1000
++KDBUS_ITEM_POLICY_ACCESS: type=USER, access=TALK, ID=1001
++KDBUS_ITEM_POLICY_ACCESS: type=WORLD, access=SEE
++
++KDBUS_ITEM_NAME: str='org.blah.baz'
++KDBUS_ITEM_POLICY_ACCESS: type=USER, access=OWN, ID=0
++KDBUS_ITEM_POLICY_ACCESS: type=WORLD, access=TALK
++    </programlisting>
++
++    <para>
++      That means that 'org.foo.bar' may only be owned by UID 1000, but every
++      user on the bus is allowed to see the name. However, only UID 1001 may
++      actually send a message to the connection and receive a reply from it.
++
++      The second rule allows 'org.blah.baz' to be owned by UID 0 only, but
++      every user may talk to it.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>TALK access and multiple well-known names per connection</title>
++    <para>
++      Note that TALK access is checked against all names of a connection. For
++      example, if a connection owns both <constant>'org.foo.bar'</constant> and
++      <constant>'org.blah.baz'</constant>, and the policy database allows
++      <constant>'org.blah.baz'</constant> to be talked to by WORLD, then this
++      permission is also granted to <constant>'org.foo.bar'</constant>. That
++      might sound illogical, but after all, we allow messages to be directed to
++      either the ID or a well-known name, and policy is applied to the
++      connection, not the name. In other words, the effective TALK policy for a
++      connection is the most permissive of all names the connection owns.
++
++      For broadcast messages, the receiver needs TALK permissions to the sender
++      to receive the broadcast.
++    </para>
++    <para>
++      Both the endpoint and the bus policy databases are consulted to allow
++      name registry listing, owning a well-known name and message delivery.
++      If either one fails, the operation is failed with
++      <varname>errno</varname> set to <constant>EPERM</constant>.
++
++      For best practices, connections that own names with a restricted TALK
++      access should not install matches. This avoids cases where the sent
++      message may pass the bloom filter due to false-positives and may also
++      satisfy the policy rules.
++
++      Also see
++      <citerefentry>
++        <refentrytitle>kdbus.match</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Implicit policies</title>
++    <para>
++      Depending on the type of the endpoint, a set of implicit rules that
++      override installed policies might be enforced.
++
++      On default endpoints, the following set is enforced and checked before
++      any user-supplied policy is checked.
++    </para>
++
++    <itemizedlist>
++      <listitem>
++        <para>
++          Privileged connections always override any installed policy. Those
++          connections could easily install their own policies, so there is no
++          reason to enforce installed policies.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          Connections can always talk to connections of the same user. This
++          includes broadcast messages.
++        </para>
++      </listitem>
++    </itemizedlist>
++
++    <para>
++      Custom endpoints have stricter policies. The following rules apply:
++    </para>
++
++    <itemizedlist>
++      <listitem>
++        <para>
++          Policy rules are always enforced, even if the connection is a
++          privileged connection.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          Policy rules are always enforced for <constant>TALK</constant> access,
++          even if both ends are running under the same user. This includes
++          broadcast messages.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          To restrict the set of names that can be seen, endpoint policies can
++          install <constant>SEE</constant> policies.
++        </para>
++      </listitem>
++    </itemizedlist>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.fs</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.pool.xml b/Documentation/kdbus/kdbus.pool.xml
+new file mode 100644
+index 0000000..a9e16f1
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.pool.xml
+@@ -0,0 +1,326 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus.pool">
++
++  <refentryinfo>
++    <title>kdbus.pool</title>
++    <productname>kdbus.pool</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus.pool</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus.pool</refname>
++    <refpurpose>kdbus pool</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Description</title>
++    <para>
++      A pool for data received from the kernel is installed for every
++      <emphasis>connection</emphasis> of the <emphasis>bus</emphasis>, and
++      is sized according to the information stored in the
++      <varname>pool_size</varname> member of <type>struct kdbus_cmd_hello</type>
++      when <constant>KDBUS_CMD_HELLO</constant> is employed. Internally, the
++      pool is segmented into <emphasis>slices</emphasis>, each referenced by its
++      <emphasis>offset</emphasis> in the pool, expressed in <type>bytes</type>.
++      See
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more information about <constant>KDBUS_CMD_HELLO</constant>.
++    </para>
++
++    <para>
++      The pool is written to by the kernel when one of the following
++      <emphasis>ioctls</emphasis> is issued:
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>KDBUS_CMD_HELLO</constant></term>
++          <listitem><para>
++            ... to receive details about the bus the connection was made to
++          </para></listitem>
++        </varlistentry>
++        <varlistentry>
++          <term><constant>KDBUS_CMD_RECV</constant></term>
++          <listitem><para>
++            ... to receive a message
++          </para></listitem>
++        </varlistentry>
++        <varlistentry>
++          <term><constant>KDBUS_CMD_LIST</constant></term>
++          <listitem><para>
++            ... to dump the name registry
++          </para></listitem>
++        </varlistentry>
++        <varlistentry>
++          <term><constant>KDBUS_CMD_CONN_INFO</constant></term>
++          <listitem><para>
++            ... to retrieve information on a connection
++          </para></listitem>
++        </varlistentry>
++        <varlistentry>
++          <term><constant>KDBUS_CMD_BUS_CREATOR_INFO</constant></term>
++          <listitem><para>
++            ... to retrieve information about a connection's bus creator
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++
++    </para>
++    <para>
++      The <varname>offset</varname> fields returned by either one of the
++      aforementioned ioctls describe offsets inside the pool. In order to make
++      the slice available for subsequent calls,
++      <constant>KDBUS_CMD_FREE</constant> has to be called on that offset
++      (see below). Otherwise, the pool will fill up, and the connection won't
++      be able to receive any more information through its pool.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Pool slice allocation</title>
++    <para>
++      Pool slices are allocated by the kernel in order to report information
++      back to a task, such as messages, returned name list etc.
++      Allocation of pool slices cannot be initiated by userspace. See
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      and
++      <citerefentry>
++        <refentrytitle>kdbus.name</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for examples of commands that use the <emphasis>pool</emphasis> to
++      return data.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Accessing the pool memory</title>
++    <para>
++      Memory in the pool is read-only for userspace and may only be written
++      to by the kernel. To read from the pool memory, the caller is expected to
++      <citerefentry>
++        <refentrytitle>mmap</refentrytitle>
++        <manvolnum>2</manvolnum>
++      </citerefentry>
++      the buffer into its task, like this:
++    </para>
++    <programlisting>
++uint8_t *buf = mmap(NULL, size, PROT_READ, MAP_SHARED, conn_fd, 0);
++    </programlisting>
++
++    <para>
++      In order to map the entire pool, the <varname>size</varname> parameter in
++      the example above should be set to the value of the
++      <varname>pool_size</varname> member of
++      <type>struct kdbus_cmd_hello</type> when
++      <constant>KDBUS_CMD_HELLO</constant> was employed to create the
++      connection (see above).
++    </para>
++
++    <para>
++      The <emphasis>file descriptor</emphasis> used to map the memory must be
++      the one that was used to create the <emphasis>connection</emphasis>.
++      In other words, the one that was used to call
++      <constant>KDBUS_CMD_HELLO</constant>. See
++      <citerefentry>
++        <refentrytitle>kdbus.connection</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>
++      for more details.
++    </para>
++
++    <para>
++      Alternatively, instead of mapping the entire pool buffer, only parts
++      of it can be mapped. Every kdbus command that returns an
++      <emphasis>offset</emphasis> (see above) also reports a
++      <emphasis>size</emphasis> along with it, so programs can be written
++      in a way that it only maps portions of the pool to access a specific
++      <emphasis>slice</emphasis>.
++    </para>
++
++    <para>
++      When access to the pool memory is no longer needed, programs should
++      call <function>munmap()</function> on the pointer returned by
++      <function>mmap()</function>.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Freeing pool slices</title>
++    <para>
++      The <constant>KDBUS_CMD_FREE</constant> ioctl is used to free a slice
++      inside the pool, describing an offset that was returned in an
++      <varname>offset</varname> field of another ioctl struct.
++      The <constant>KDBUS_CMD_FREE</constant> command takes a
++      <type>struct kdbus_cmd_free</type> as argument.
++    </para>
++
++<programlisting>
++struct kdbus_cmd_free {
++  __u64 size;
++  __u64 flags;
++  __u64 return_flags;
++  __u64 offset;
++  struct kdbus_item items[0];
++};
++</programlisting>
++
++    <para>The fields in this struct are described below.</para>
++
++    <variablelist>
++      <varlistentry>
++        <term><varname>size</varname></term>
++        <listitem><para>
++          The overall size of the struct, including its items.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>flags</varname></term>
++        <listitem><para>
++          Currently unused.
++          <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for
++          valid flags. If set, the ioctl will return <errorcode>0</errorcode>,
++          and the <varname>flags</varname> field is set to
++          <constant>0</constant>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>return_flags</varname></term>
++        <listitem><para>
++          Flags returned by the kernel. Currently unused and always set to
++          <constant>0</constant> by the kernel.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>offset</varname></term>
++        <listitem><para>
++          The offset to free, as returned by other ioctls that allocated
++          memory for returned information.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>items</varname></term>
++        <listitem><para>
++          Items to specify further details for the receive command.
++          Currently unused.
++          Unrecognized items are rejected, and the ioctl will fail with
++          <varname>errno</varname> set to <constant>EINVAL</constant>.
++          All items except for
++          <constant>KDBUS_ITEM_NEGOTIATE</constant> (see
++            <citerefentry>
++              <refentrytitle>kdbus.item</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>
++          ) will be rejected.
++        </para></listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>Return value</title>
++    <para>
++      On success, all mentioned ioctl commands return <errorcode>0</errorcode>;
++      on error, <errorcode>-1</errorcode> is returned, and
++      <varname>errno</varname> is set to indicate the error.
++      If the issued ioctl is illegal for the file descriptor used,
++      <varname>errno</varname> will be set to <constant>ENOTTY</constant>.
++    </para>
++
++    <refsect2>
++      <title>
++        <constant>KDBUS_CMD_FREE</constant> may fail with the following
++        errors
++      </title>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>ENXIO</constant></term>
++          <listitem><para>
++            No pool slice found at given offset.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            Invalid flags provided.
++          </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>EINVAL</constant></term>
++          <listitem><para>
++            The offset is valid, but the user is not allowed to free the slice.
++            This happens, for example, if the offset was retrieved with
++            <constant>KDBUS_RECV_PEEK</constant>.
++          </para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>mmap</refentrytitle>
++            <manvolnum>2</manvolnum>
++          </citerefentry>
++        </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>munmap</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++    </simplelist>
++  </refsect1>
++</refentry>
+diff --git a/Documentation/kdbus/kdbus.xml b/Documentation/kdbus/kdbus.xml
+new file mode 100644
+index 0000000..d8e7400
+--- /dev/null
++++ b/Documentation/kdbus/kdbus.xml
+@@ -0,0 +1,1012 @@
++<?xml version='1.0'?> <!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="kdbus">
++
++  <refentryinfo>
++    <title>kdbus</title>
++    <productname>kdbus</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>kdbus</refentrytitle>
++    <manvolnum>7</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>kdbus</refname>
++    <refpurpose>Kernel Message Bus</refpurpose>
++  </refnamediv>
++
++  <refsect1>
++    <title>Synopsis</title>
++    <para>
++      kdbus is an inter-process communication bus system controlled by the
++      kernel. It provides user-space with an API to create buses and send
++      unicast and multicast messages to one, or many, peers connected to the
++      same bus. It does not enforce any layout on the transmitted data, but
++      only provides the transport layer used for message interchange between
++      peers.
++    </para>
++    <para>
++      This set of man-pages gives a comprehensive overview of the kernel-level
++      API, with all ioctl commands, associated structs and bit masks. However,
++      most people will not use this API level directly, but rather let one of
++      the high-level abstraction libraries help them integrate D-Bus
++      functionality into their applications.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>Description</title>
++    <para>
++      kdbus provides a pseudo filesystem called <emphasis>kdbusfs</emphasis>,
++      which is usually mounted on <filename>/sys/fs/kdbus</filename>. Bus
++      primitives can be accessed as files and sub-directories underneath this
++      mount-point. Any advanced operations are done via
++      <function>ioctl()</function> on files created by
++      <emphasis>kdbusfs</emphasis>. Multiple mount-points of
++      <emphasis>kdbusfs</emphasis> are independent of each other. This allows
++      namespacing of kdbus by mounting a new instance of
++      <emphasis>kdbusfs</emphasis> in a new mount-namespace. kdbus calls these
++      mount instances domains and each bus belongs to exactly one domain.
++    </para>
++
++    <para>
++      kdbus was designed as a transport layer for D-Bus, but is in no way
++      limited, nor controlled by the D-Bus protocol specification. The D-Bus
++      protocol is one possible application layer on top of kdbus.
++    </para>
++
++    <para>
++      For the general D-Bus protocol specification, its payload format, its
++      marshaling, and its communication semantics, please refer to the
++      <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html">
++      D-Bus specification</ulink>.
++    </para>
++
++  </refsect1>
++
++  <refsect1>
++    <title>Terminology</title>
++
++    <refsect2>
++      <title>Domain</title>
++      <para>
++        A domain is a <emphasis>kdbusfs</emphasis> mount-point containing all
++        the bus primitives. Each domain is independent, and separate domains
++        do not affect each other.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Bus</title>
++      <para>
++        A bus is a named object inside a domain. Clients exchange messages
++        over a bus. Multiple buses themselves have no connection to each other;
++        messages can only be exchanged on the same bus. The default endpoint of
++        a bus, to which clients establish connections, is the "bus" file
++        /sys/fs/kdbus/&lt;bus name&gt;/bus.
++        Common operating system setups create one "system bus" per system,
++        and one "user bus" for every logged-in user. Applications or services
++        may create their own private buses. The kernel driver does not
++        distinguish between different bus types, they are all handled the same
++        way. See
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Endpoint</title>
++      <para>
++        An endpoint provides a file to talk to a bus. Opening an endpoint
++        creates a new connection to the bus to which the endpoint belongs. All
++        endpoints have unique names and are accessible as files underneath the
++        directory of a bus, e.g., /sys/fs/kdbus/&lt;bus&gt;/&lt;endpoint&gt;
++        Every bus has a default endpoint called "bus".
++        A bus can optionally offer additional endpoints with custom names
++        to provide restricted access to the bus. Custom endpoints carry
++        additional policy which can be used to create sandboxes with
++        locked-down, limited, filtered access to a bus. See
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Connection</title>
++      <para>
++        A connection to a bus is created by opening an endpoint file of a
++        bus. Every ordinary client connection has a unique identifier on the
++        bus and can address messages to every other connection on the same
++        bus by using the peer's connection ID as the destination. See
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Pool</title>
++      <para>
++        Each connection allocates a piece of shmem-backed memory that is
++        used to receive messages and answers to ioctl commands from the kernel.
++        It is never used to send anything to the kernel. In order to access that
++        memory, an application must mmap() it into its address space. See
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Well-known Name</title>
++      <para>
++        A connection can, in addition to its implicit unique connection ID,
++        request the ownership of a textual well-known name. Well-known names are
++        noted in reverse-domain notation, such as com.example.service1. A
++        connection that offers a service on a bus is usually reached by its
++        well-known name. An analogy of connection ID and well-known name is an
++        IP address and a DNS name associated with that address. See
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Message</title>
++      <para>
++        Connections can exchange messages with other connections by addressing
++        the peers with their connection ID or well-known name. A message
++        consists of a message header with information on how to route the
++        message, and the message payload, which is a logical byte stream of
++        arbitrary size. Messages can carry additional file descriptors to be
++        passed from one connection to another, just like passing file
++        descriptors over UNIX domain sockets. Every connection can specify which
++        set of metadata the kernel should attach to the message when it is
++        delivered to the receiving connection. Metadata contains information
++        like: system time stamps, UID, GID, TID, proc-starttime, well-known
++        names, process comm, process exe, process argv, cgroup, capabilities,
++        seclabel, audit session, loginuid and the connection's human-readable
++        name. See
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Item</title>
++      <para>
++        The API of kdbus implements the notion of items, submitted through and
++        returned by most ioctls, and stored inside data structures in the
++        connection's pool. See
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Broadcast, signal, filter, match</title>
++      <para>
++        Signals are messages that a receiver opts in for by installing a blob of
++        bytes, called a 'match'. Signal messages must always carry a
++        counter-part blob, called a 'filter', and signals are only delivered to
++        peers which have a match that white-lists the message's filter. Senders
++        of signal messages can use either a single connection ID as receiver,
++        or the special connection ID
++        <constant>KDBUS_DST_ID_BROADCAST</constant> to potentially send it to
++        all connections of a bus, following the logic described above. See
++        <citerefentry>
++          <refentrytitle>kdbus.match</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        and
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Policy</title>
++      <para>
++        A policy is a set of rules that define which connections can see, talk
++        to, or register a well-known name on the bus. A policy is attached to
++        buses and custom endpoints, and modified by policy holder connections or
++        owners of custom endpoints. See
++        <citerefentry>
++          <refentrytitle>kdbus.policy</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Privileged bus users</title>
++      <para>
++        A user connecting to the bus is considered privileged if it is either
++        the creator of the bus, or if it has the CAP_IPC_OWNER capability flag
++        set. See
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for more details.
++      </para>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>Bus Layout</title>
++
++    <para>
++      A <emphasis>bus</emphasis> provides and defines an environment that peers
++      can connect to for message interchange. A bus is created via the kdbus
++      control interface and can be modified by the bus creator. It applies the
++      policy that control all bus operations. The bus creator itself does not
++      participate as a peer. To establish a peer
++      <emphasis>connection</emphasis>, you have to open one of the
++      <emphasis>endpoints</emphasis> of a bus. Each bus provides a default
++      endpoint, but further endpoints can be created on-demand. Endpoints are
++      used to apply additional policies for all connections on this endpoint.
++      Thus, they provide additional filters to further restrict access of
++      specific connections to the bus.
++    </para>
++
++    <para>
++      Following, you can see an example bus layout:
++    </para>
++
++    <programlisting><![CDATA[
++                                  Bus Creator
++                                       |
++                                       |
++                                    +-----+
++                                    | Bus |
++                                    +-----+
++                                       |
++                    __________________/ \__________________
++                   /                                       \
++                   |                                       |
++             +----------+                             +----------+
++             | Endpoint |                             | Endpoint |
++             +----------+                             +----------+
++         _________/|\_________                   _________/|\_________
++        /          |          \                 /          |          \
++        |          |          |                 |          |          |
++        |          |          |                 |          |          |
++   Connection  Connection  Connection      Connection  Connection  Connection
++    ]]></programlisting>
++
++  </refsect1>
++
++  <refsect1>
++    <title>Data structures and interconnections</title>
++    <programlisting><![CDATA[
++  +--------------------------------------------------------------------------+
++  | Domain (Mount Point)                                                     |
++  | /sys/fs/kdbus/control                                                    |
++  | +----------------------------------------------------------------------+ |
++  | | Bus (System Bus)                                                     | |
++  | | /sys/fs/kdbus/0-system/                                              | |
++  | | +-------------------------------+ +--------------------------------+ | |
++  | | | Endpoint                      | | Endpoint                       | | |
++  | | | /sys/fs/kdbus/0-system/bus    | | /sys/fs/kdbus/0-system/ep.app  | | |
++  | | +-------------------------------+ +--------------------------------+ | |
++  | | +--------------+ +--------------+ +--------------+ +---------------+ | |
++  | | | Connection   | | Connection   | | Connection   | | Connection    | | |
++  | | | :1.22        | | :1.25        | | :1.55        | | :1.81         | | |
++  | | +--------------+ +--------------+ +--------------+ +---------------+ | |
++  | +----------------------------------------------------------------------+ |
++  |                                                                          |
++  | +----------------------------------------------------------------------+ |
++  | | Bus (User Bus for UID 2702)                                          | |
++  | | /sys/fs/kdbus/2702-user/                                             | |
++  | | +-------------------------------+ +--------------------------------+ | |
++  | | | Endpoint                      | | Endpoint                       | | |
++  | | | /sys/fs/kdbus/2702-user/bus   | | /sys/fs/kdbus/2702-user/ep.app | | |
++  | | +-------------------------------+ +--------------------------------+ | |
++  | | +--------------+ +--------------+ +--------------+ +---------------+ | |
++  | | | Connection   | | Connection   | | Connection   | | Connection    | | |
++  | | | :1.22        | | :1.25        | | :1.55        | | :1.81         | | |
++  | | +--------------+ +--------------+ +--------------------------------+ | |
++  | +----------------------------------------------------------------------+ |
++  +--------------------------------------------------------------------------+
++    ]]></programlisting>
++  </refsect1>
++
++  <refsect1>
++    <title>Metadata</title>
++
++    <refsect2>
++      <title>When metadata is collected</title>
++      <para>
++        kdbus records data about the system in certain situations. Such metadata
++        can refer to the currently active process (creds, PIDs, current user
++        groups, process names and its executable path, cgroup membership,
++        capabilities, security label and audit information), connection
++        information (description string, currently owned names) and time stamps.
++      </para>
++      <para>
++        Metadata is collected at the following times.
++      </para>
++
++      <itemizedlist>
++        <listitem><para>
++          When a bus is created (<constant>KDBUS_CMD_MAKE</constant>),
++          information about the calling task is collected. This data is returned
++          by the kernel via the <constant>KDBUS_CMD_BUS_CREATOR_INFO</constant>
++          call.
++        </para></listitem>
++
++        <listitem>
++          <para>
++            When a connection is created (<constant>KDBUS_CMD_HELLO</constant>),
++            information about the calling task is collected. Alternatively, a
++            privileged connection may provide 'faked' information about
++            credentials, PIDs and security labels which will be stored instead.
++            This data is returned by the kernel as information on a connection
++            (<constant>KDBUS_CMD_CONN_INFO</constant>). Only metadata that a
++            connection allowed to be sent (by setting its bit in
++            <varname>attach_flags_send</varname>) will be exported in this way.
++          </para>
++        </listitem>
++
++        <listitem>
++          <para>
++            When a message is sent (<constant>KDBUS_CMD_SEND</constant>),
++            information about the sending task and the sending connection is
++            collected. This metadata will be attached to the message when it
++            arrives in the receiver's pool. If the connection sending the
++            message installed faked credentials (see
++            <citerefentry>
++              <refentrytitle>kdbus.connection</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>),
++            the message will not be augmented by any information about the
++            currently sending task. Note that only metadata that was requested
++            by the receiving connection will be collected and attached to
++            messages.
++          </para>
++        </listitem>
++      </itemizedlist>
++
++      <para>
++        Which metadata items are actually delivered depends on the following
++        sets and masks:
++      </para>
++
++      <itemizedlist>
++        <listitem><para>
++          (a) the system-wide kmod creds mask
++          (module parameter <varname>attach_flags_mask</varname>)
++        </para></listitem>
++
++        <listitem><para>
++          (b) the per-connection send creds mask, set by the connecting client
++        </para></listitem>
++
++        <listitem><para>
++          (c) the per-connection receive creds mask, set by the connecting
++          client
++        </para></listitem>
++
++        <listitem><para>
++          (d) the per-bus minimal creds mask, set by the bus creator
++        </para></listitem>
++
++        <listitem><para>
++          (e) the per-bus owner creds mask, set by the bus creator
++        </para></listitem>
++
++        <listitem><para>
++          (f) the mask specified when querying creds of a bus peer
++        </para></listitem>
++
++        <listitem><para>
++          (g) the mask specified when querying creds of a bus owner
++        </para></listitem>
++      </itemizedlist>
++
++      <para>
++        With the following rules:
++      </para>
++
++      <itemizedlist>
++        <listitem>
++          <para>
++            [1] The creds attached to messages are determined as
++            <constant>a &amp; b &amp; c</constant>.
++          </para>
++        </listitem>
++
++        <listitem>
++          <para>
++            [2] When connecting to a bus (<constant>KDBUS_CMD_HELLO</constant>),
++            and <constant>~b &amp; d != 0</constant>, the call will fail with,
++            <errorcode>-1</errorcode>, and <varname>errno</varname> is set to
++            <constant>ECONNREFUSED</constant>.
++          </para>
++        </listitem>
++
++        <listitem>
++          <para>
++            [3] When querying creds of a bus peer, the creds returned are
++            <constant>a &amp; b &amp; f</constant>.
++          </para>
++        </listitem>
++
++        <listitem>
++          <para>
++            [4] When querying creds of a bus owner, the creds returned are
++            <constant>a &amp; e &amp; g</constant>.
++          </para>
++        </listitem>
++      </itemizedlist>
++
++      <para>
++        Hence, programs might not always get all requested metadata items that
++        it requested. Code must be written so that it can cope with this fact.
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Benefits and heads-up</title>
++      <para>
++        Attaching metadata to messages has two major benefits.
++
++        <itemizedlist>
++          <listitem>
++            <para>
++              Metadata attached to messages is gathered at the moment when the
++              other side calls <constant>KDBUS_CMD_SEND</constant>, or,
++              respectively, then the kernel notification is generated. There is
++              no need for the receiving peer to retrieve information about the
++              task in a second step. This closes a race gap that would otherwise
++              be inherent.
++            </para>
++          </listitem>
++          <listitem>
++            <para>
++              As metadata is delivered along with messages in the same data
++              blob, no extra calls to kernel functions etc. are needed to gather
++              them.
++            </para>
++          </listitem>
++        </itemizedlist>
++
++        Note, however, that collecting metadata does come at a price for
++        performance, so developers should carefully assess which metadata to
++        really opt-in for. For best practice, data that is not needed as part
++        of a message should not be requested by the connection in the first
++        place (see <varname>attach_flags_recv</varname> in
++        <constant>KDBUS_CMD_HELLO</constant>).
++      </para>
++    </refsect2>
++
++    <refsect2>
++      <title>Attach flags for metadata items</title>
++      <para>
++        To let the kernel know which metadata information to attach as items
++        to the aforementioned commands, it uses a bitmask. In those, the
++        following <emphasis>attach flags</emphasis> are currently supported.
++        Both the <varname>attach_flags_recv</varname> and
++        <varname>attach_flags_send</varname> fields of
++        <type>struct kdbus_cmd_hello</type>, as well as the payload of the
++        <constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant> and
++        <constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant> items follow this
++        scheme.
++      </para>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_TIMESTAMP</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_TIMESTAMP</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_CREDS</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_CREDS</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_PIDS</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_PIDS</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_AUXGROUPS</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_AUXGROUPS</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_NAMES</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_OWNED_NAME</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_TID_COMM</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_TID_COMM</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_PID_COMM</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_PID_COMM</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_EXE</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_EXE</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_CMDLINE</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_CMDLINE</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_CGROUP</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_CGROUP</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_CAPS</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_CAPS</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_SECLABEL</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_SECLABEL</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_AUDIT</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_AUDIT</constant>.
++            </para></listitem>
++        </varlistentry>
++
++        <varlistentry>
++          <term><constant>KDBUS_ATTACH_CONN_DESCRIPTION</constant></term>
++            <listitem><para>
++              Requests the attachment of an item of type
++              <constant>KDBUS_ITEM_CONN_DESCRIPTION</constant>.
++            </para></listitem>
++        </varlistentry>
++      </variablelist>
++
++      <para>
++        Please refer to
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++        for detailed information about the layout and payload of items and
++        what metadata should be used to.
++      </para>
++    </refsect2>
++  </refsect1>
++
++  <refsect1>
++    <title>The ioctl interface</title>
++
++    <para>
++      As stated in the 'synopsis' section above, application developers are
++      strongly encouraged to use kdbus through one of the high-level D-Bus
++      abstraction libraries, rather than using the low-level API directly.
++    </para>
++
++    <para>
++      kdbus on the kernel level exposes its functions exclusively through
++      <citerefentry>
++        <refentrytitle>ioctl</refentrytitle>
++        <manvolnum>2</manvolnum>
++      </citerefentry>,
++      employed on file descriptors returned by
++      <citerefentry>
++        <refentrytitle>open</refentrytitle>
++        <manvolnum>2</manvolnum>
++      </citerefentry>
++      on pseudo files exposed by
++      <citerefentry>
++        <refentrytitle>kdbus.fs</refentrytitle>
++        <manvolnum>7</manvolnum>
++      </citerefentry>.
++    </para>
++    <para>
++      Following is a list of all the ioctls, along with the command structs
++      they must be used with.
++    </para>
++
++    <informaltable frame="none">
++      <tgroup cols="3" colsep="1">
++        <thead>
++          <row>
++            <entry>ioctl signature</entry>
++            <entry>command</entry>
++            <entry>transported struct</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><constant>0x40189500</constant></entry>
++            <entry><constant>KDBUS_CMD_BUS_MAKE</constant></entry>
++            <entry><type>struct kdbus_cmd *</type></entry>
++          </row><row>
++            <entry><constant>0x40189510</constant></entry>
++            <entry><constant>KDBUS_CMD_ENDPOINT_MAKE</constant></entry>
++            <entry><type>struct kdbus_cmd *</type></entry>
++          </row><row>
++            <entry><constant>0xc0609580</constant></entry>
++            <entry><constant>KDBUS_CMD_HELLO</constant></entry>
++            <entry><type>struct kdbus_cmd_hello *</type></entry>
++          </row><row>
++            <entry><constant>0x40189582</constant></entry>
++            <entry><constant>KDBUS_CMD_BYEBYE</constant></entry>
++            <entry><type>struct kdbus_cmd *</type></entry>
++          </row><row>
++            <entry><constant>0x40389590</constant></entry>
++            <entry><constant>KDBUS_CMD_SEND</constant></entry>
++            <entry><type>struct kdbus_cmd_send *</type></entry>
++          </row><row>
++            <entry><constant>0x80409591</constant></entry>
++            <entry><constant>KDBUS_CMD_RECV</constant></entry>
++            <entry><type>struct kdbus_cmd_recv *</type></entry>
++          </row><row>
++            <entry><constant>0x40209583</constant></entry>
++            <entry><constant>KDBUS_CMD_FREE</constant></entry>
++            <entry><type>struct kdbus_cmd_free *</type></entry>
++          </row><row>
++            <entry><constant>0x401895a0</constant></entry>
++            <entry><constant>KDBUS_CMD_NAME_ACQUIRE</constant></entry>
++            <entry><type>struct kdbus_cmd *</type></entry>
++          </row><row>
++            <entry><constant>0x401895a1</constant></entry>
++            <entry><constant>KDBUS_CMD_NAME_RELEASE</constant></entry>
++            <entry><type>struct kdbus_cmd *</type></entry>
++          </row><row>
++            <entry><constant>0x80289586</constant></entry>
++            <entry><constant>KDBUS_CMD_LIST</constant></entry>
++            <entry><type>struct kdbus_cmd_list *</type></entry>
++          </row><row>
++            <entry><constant>0x80309584</constant></entry>
++            <entry><constant>KDBUS_CMD_CONN_INFO</constant></entry>
++            <entry><type>struct kdbus_cmd_info *</type></entry>
++          </row><row>
++            <entry><constant>0x40209551</constant></entry>
++            <entry><constant>KDBUS_CMD_UPDATE</constant></entry>
++            <entry><type>struct kdbus_cmd *</type></entry>
++          </row><row>
++            <entry><constant>0x80309585</constant></entry>
++            <entry><constant>KDBUS_CMD_BUS_CREATOR_INFO</constant></entry>
++            <entry><type>struct kdbus_cmd_info *</type></entry>
++          </row><row>
++            <entry><constant>0x40189511</constant></entry>
++            <entry><constant>KDBUS_CMD_ENDPOINT_UPDATE</constant></entry>
++            <entry><type>struct kdbus_cmd *</type></entry>
++          </row><row>
++            <entry><constant>0x402095b0</constant></entry>
++            <entry><constant>KDBUS_CMD_MATCH_ADD</constant></entry>
++            <entry><type>struct kdbus_cmd_match *</type></entry>
++          </row><row>
++            <entry><constant>0x402095b1</constant></entry>
++            <entry><constant>KDBUS_CMD_MATCH_REMOVE</constant></entry>
++            <entry><type>struct kdbus_cmd_match *</type></entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </informaltable>
++
++    <para>
++      Depending on the type of <emphasis>kdbusfs</emphasis> node that was
++      opened and what ioctls have been executed on a file descriptor before,
++      a different sub-set of ioctl commands is allowed.
++    </para>
++
++    <itemizedlist>
++      <listitem>
++        <para>
++          On a file descriptor resulting from opening a
++          <emphasis>control node</emphasis>, only the
++          <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl may be executed.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          On a file descriptor resulting from opening a
++          <emphasis>bus endpoint node</emphasis>, only the
++          <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> and
++          <constant>KDBUS_CMD_HELLO</constant> ioctls may be executed.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          A file descriptor that was used to create a bus
++          (via <constant>KDBUS_CMD_BUS_MAKE</constant>) is called a
++          <emphasis>bus owner</emphasis> file descriptor. The bus will be
++          active as long as the file descriptor is kept open.
++          A bus owner file descriptor can not be used to
++          employ any further ioctls. As soon as
++          <citerefentry>
++            <refentrytitle>close</refentrytitle>
++            <manvolnum>2</manvolnum>
++          </citerefentry>
++          is called on it, the bus will be shut down, along will all associated
++          endpoints and connections. See
++          <citerefentry>
++            <refentrytitle>kdbus.bus</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for more details.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          A file descriptor that was used to create an endpoint
++          (via <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>) is called an
++          <emphasis>endpoint owner</emphasis> file descriptor. The endpoint
++          will be active as long as the file descriptor is kept open.
++          An endpoint owner file descriptor can only be used
++          to update details of an endpoint through the
++          <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant> ioctl. As soon as
++          <citerefentry>
++            <refentrytitle>close</refentrytitle>
++            <manvolnum>2</manvolnum>
++          </citerefentry>
++          is called on it, the endpoint will be removed from the bus, and all
++          connections that are connected to the bus through it are shut down.
++          See
++          <citerefentry>
++            <refentrytitle>kdbus.endpoint</refentrytitle>
++            <manvolnum>7</manvolnum>
++          </citerefentry>
++          for more details.
++        </para>
++      </listitem>
++      <listitem>
++        <para>
++          A file descriptor that was used to create a connection
++          (via <constant>KDBUS_CMD_HELLO</constant>) is called a
++          <emphasis>connection owner</emphasis> file descriptor. The connection
++          will be active as long as the file descriptor is kept open.
++          A connection owner file descriptor may be used to
++          issue any of the following ioctls.
++        </para>
++
++        <itemizedlist>
++          <listitem><para>
++            <constant>KDBUS_CMD_UPDATE</constant> to tweak details of the
++            connection. See
++            <citerefentry>
++              <refentrytitle>kdbus.connection</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_BYEBYE</constant> to shut down a connection
++            without losing messages. See
++            <citerefentry>
++              <refentrytitle>kdbus.connection</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_FREE</constant> to free a slice of memory in
++            the pool. See
++            <citerefentry>
++              <refentrytitle>kdbus.pool</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_CONN_INFO</constant> to retrieve information
++            on other connections on the bus. See
++            <citerefentry>
++              <refentrytitle>kdbus.connection</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_BUS_CREATOR_INFO</constant> to retrieve
++            information on the bus creator. See
++            <citerefentry>
++              <refentrytitle>kdbus.connection</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_LIST</constant> to retrieve a list of
++            currently active well-known names and unique IDs on the bus. See
++            <citerefentry>
++              <refentrytitle>kdbus.name</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_SEND</constant> and
++            <constant>KDBUS_CMD_RECV</constant> to send or receive a message.
++            See
++            <citerefentry>
++              <refentrytitle>kdbus.message</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_NAME_ACQUIRE</constant> and
++            <constant>KDBUS_CMD_NAME_RELEASE</constant> to acquire or release
++            a well-known name on the bus. See
++            <citerefentry>
++              <refentrytitle>kdbus.name</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++
++          <listitem><para>
++            <constant>KDBUS_CMD_MATCH_ADD</constant> and
++            <constant>KDBUS_CMD_MATCH_REMOVE</constant> to add or remove
++            a match for signal messages. See
++            <citerefentry>
++              <refentrytitle>kdbus.match</refentrytitle>
++              <manvolnum>7</manvolnum>
++            </citerefentry>.
++          </para></listitem>
++        </itemizedlist>
++      </listitem>
++    </itemizedlist>
++
++    <para>
++      These ioctls, along with the structs they transport, are explained in
++      detail in the other documents linked to in the "See Also" section below.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <simplelist type="inline">
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.bus</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.connection</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.endpoint</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.fs</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.item</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.message</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.name</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>kdbus.pool</refentrytitle>
++          <manvolnum>7</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>ioctl</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>mmap</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>open</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <citerefentry>
++          <refentrytitle>close</refentrytitle>
++          <manvolnum>2</manvolnum>
++        </citerefentry>
++      </member>
++      <member>
++        <ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>
++      </member>
++    </simplelist>
++  </refsect1>
++
++</refentry>
+diff --git a/Documentation/kdbus/stylesheet.xsl b/Documentation/kdbus/stylesheet.xsl
+new file mode 100644
+index 0000000..52565ea
+--- /dev/null
++++ b/Documentation/kdbus/stylesheet.xsl
+@@ -0,0 +1,16 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
++	<param name="chunk.quietly">1</param>
++	<param name="funcsynopsis.style">ansi</param>
++	<param name="funcsynopsis.tabular.threshold">80</param>
++	<param name="callout.graphics">0</param>
++	<param name="paper.type">A4</param>
++	<param name="generate.section.toc.level">2</param>
++	<param name="use.id.as.filename">1</param>
++	<param name="citerefentry.link">1</param>
++	<strip-space elements="*"/>
++	<template name="generate.citerefentry.link">
++		<value-of select="refentrytitle"/>
++		<text>.html</text>
++	</template>
++</stylesheet>
+diff --git a/MAINTAINERS b/MAINTAINERS
+index d8afd29..02f7668 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -5585,6 +5585,19 @@ S:	Maintained
+ F:	Documentation/kbuild/kconfig-language.txt
+ F:	scripts/kconfig/
+ 
++KDBUS
++M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++M:	Daniel Mack <daniel@zonque.org>
++M:	David Herrmann <dh.herrmann@googlemail.com>
++M:	Djalal Harouni <tixxdz@opendz.org>
++L:	linux-kernel@vger.kernel.org
++S:	Maintained
++F:	ipc/kdbus/*
++F:	samples/kdbus/*
++F:	Documentation/kdbus/*
++F:	include/uapi/linux/kdbus.h
++F:	tools/testing/selftests/kdbus/
++
+ KDUMP
+ M:	Vivek Goyal <vgoyal@redhat.com>
+ M:	Haren Myneni <hbabu@us.ibm.com>
+diff --git a/Makefile b/Makefile
+index f5c8983..a1c8d57 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1343,6 +1343,7 @@ $(help-board-dirs): help-%:
+ %docs: scripts_basic FORCE
+ 	$(Q)$(MAKE) $(build)=scripts build_docproc
+ 	$(Q)$(MAKE) $(build)=Documentation/DocBook $@
++	$(Q)$(MAKE) $(build)=Documentation/kdbus $@
+ 
+ else # KBUILD_EXTMOD
+ 
+diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
+index 1a0006a..4842a98 100644
+--- a/include/uapi/linux/Kbuild
++++ b/include/uapi/linux/Kbuild
+@@ -215,6 +215,7 @@ header-y += ixjuser.h
+ header-y += jffs2.h
+ header-y += joystick.h
+ header-y += kcmp.h
++header-y += kdbus.h
+ header-y += kdev_t.h
+ header-y += kd.h
+ header-y += kernelcapi.h
+diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h
+new file mode 100644
+index 0000000..4fc44cb
+--- /dev/null
++++ b/include/uapi/linux/kdbus.h
+@@ -0,0 +1,984 @@
++/*
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef _UAPI_KDBUS_H_
++#define _UAPI_KDBUS_H_
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++#define KDBUS_IOCTL_MAGIC		0x95
++#define KDBUS_SRC_ID_KERNEL		(0)
++#define KDBUS_DST_ID_NAME		(0)
++#define KDBUS_MATCH_ID_ANY		(~0ULL)
++#define KDBUS_DST_ID_BROADCAST		(~0ULL)
++#define KDBUS_FLAG_NEGOTIATE		(1ULL << 63)
++
++/**
++ * struct kdbus_notify_id_change - name registry change message
++ * @id:			New or former owner of the name
++ * @flags:		flags field from KDBUS_HELLO_*
++ *
++ * Sent from kernel to userspace when the owner or activator of
++ * a well-known name changes.
++ *
++ * Attached to:
++ *   KDBUS_ITEM_ID_ADD
++ *   KDBUS_ITEM_ID_REMOVE
++ */
++struct kdbus_notify_id_change {
++	__u64 id;
++	__u64 flags;
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_notify_name_change - name registry change message
++ * @old_id:		ID and flags of former owner of a name
++ * @new_id:		ID and flags of new owner of a name
++ * @name:		Well-known name
++ *
++ * Sent from kernel to userspace when the owner or activator of
++ * a well-known name changes.
++ *
++ * Attached to:
++ *   KDBUS_ITEM_NAME_ADD
++ *   KDBUS_ITEM_NAME_REMOVE
++ *   KDBUS_ITEM_NAME_CHANGE
++ */
++struct kdbus_notify_name_change {
++	struct kdbus_notify_id_change old_id;
++	struct kdbus_notify_id_change new_id;
++	char name[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_creds - process credentials
++ * @uid:		User ID
++ * @euid:		Effective UID
++ * @suid:		Saved UID
++ * @fsuid:		Filesystem UID
++ * @gid:		Group ID
++ * @egid:		Effective GID
++ * @sgid:		Saved GID
++ * @fsgid:		Filesystem GID
++ *
++ * Attached to:
++ *   KDBUS_ITEM_CREDS
++ */
++struct kdbus_creds {
++	__u64 uid;
++	__u64 euid;
++	__u64 suid;
++	__u64 fsuid;
++	__u64 gid;
++	__u64 egid;
++	__u64 sgid;
++	__u64 fsgid;
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_pids - process identifiers
++ * @pid:		Process ID
++ * @tid:		Thread ID
++ * @ppid:		Parent process ID
++ *
++ * The PID and TID of a process.
++ *
++ * Attached to:
++ *   KDBUS_ITEM_PIDS
++ */
++struct kdbus_pids {
++	__u64 pid;
++	__u64 tid;
++	__u64 ppid;
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_caps - process capabilities
++ * @last_cap:	Highest currently known capability bit
++ * @caps:	Variable number of 32-bit capabilities flags
++ *
++ * Contains a variable number of 32-bit capabilities flags.
++ *
++ * Attached to:
++ *   KDBUS_ITEM_CAPS
++ */
++struct kdbus_caps {
++	__u32 last_cap;
++	__u32 caps[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_audit - audit information
++ * @sessionid:		The audit session ID
++ * @loginuid:		The audit login uid
++ *
++ * Attached to:
++ *   KDBUS_ITEM_AUDIT
++ */
++struct kdbus_audit {
++	__u32 sessionid;
++	__u32 loginuid;
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_timestamp
++ * @seqnum:		Global per-domain message sequence number
++ * @monotonic_ns:	Monotonic timestamp, in nanoseconds
++ * @realtime_ns:	Realtime timestamp, in nanoseconds
++ *
++ * Attached to:
++ *   KDBUS_ITEM_TIMESTAMP
++ */
++struct kdbus_timestamp {
++	__u64 seqnum;
++	__u64 monotonic_ns;
++	__u64 realtime_ns;
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_vec - I/O vector for kdbus payload items
++ * @size:		The size of the vector
++ * @address:		Memory address of data buffer
++ * @offset:		Offset in the in-message payload memory,
++ *			relative to the message head
++ *
++ * Attached to:
++ *   KDBUS_ITEM_PAYLOAD_VEC, KDBUS_ITEM_PAYLOAD_OFF
++ */
++struct kdbus_vec {
++	__u64 size;
++	union {
++		__u64 address;
++		__u64 offset;
++	};
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_bloom_parameter - bus-wide bloom parameters
++ * @size:		Size of the bit field in bytes (m / 8)
++ * @n_hash:		Number of hash functions used (k)
++ */
++struct kdbus_bloom_parameter {
++	__u64 size;
++	__u64 n_hash;
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_bloom_filter - bloom filter containing n elements
++ * @generation:		Generation of the element set in the filter
++ * @data:		Bit field, multiple of 8 bytes
++ */
++struct kdbus_bloom_filter {
++	__u64 generation;
++	__u64 data[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_memfd - a kdbus memfd
++ * @start:		The offset into the memfd where the segment starts
++ * @size:		The size of the memfd segment
++ * @fd:			The file descriptor number
++ * @__pad:		Padding to ensure proper alignment and size
++ *
++ * Attached to:
++ *   KDBUS_ITEM_PAYLOAD_MEMFD
++ */
++struct kdbus_memfd {
++	__u64 start;
++	__u64 size;
++	int fd;
++	__u32 __pad;
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_name - a registered well-known name with its flags
++ * @flags:		Flags from KDBUS_NAME_*
++ * @name:		Well-known name
++ *
++ * Attached to:
++ *   KDBUS_ITEM_OWNED_NAME
++ */
++struct kdbus_name {
++	__u64 flags;
++	char name[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_policy_access_type - permissions of a policy record
++ * @_KDBUS_POLICY_ACCESS_NULL:	Uninitialized/invalid
++ * @KDBUS_POLICY_ACCESS_USER:	Grant access to a uid
++ * @KDBUS_POLICY_ACCESS_GROUP:	Grant access to gid
++ * @KDBUS_POLICY_ACCESS_WORLD:	World-accessible
++ */
++enum kdbus_policy_access_type {
++	_KDBUS_POLICY_ACCESS_NULL,
++	KDBUS_POLICY_ACCESS_USER,
++	KDBUS_POLICY_ACCESS_GROUP,
++	KDBUS_POLICY_ACCESS_WORLD,
++};
++
++/**
++ * enum kdbus_policy_access_flags - mode flags
++ * @KDBUS_POLICY_OWN:		Allow to own a well-known name
++ *				Implies KDBUS_POLICY_TALK and KDBUS_POLICY_SEE
++ * @KDBUS_POLICY_TALK:		Allow communication to a well-known name
++ *				Implies KDBUS_POLICY_SEE
++ * @KDBUS_POLICY_SEE:		Allow to see a well-known name
++ */
++enum kdbus_policy_type {
++	KDBUS_POLICY_SEE	= 0,
++	KDBUS_POLICY_TALK,
++	KDBUS_POLICY_OWN,
++};
++
++/**
++ * struct kdbus_policy_access - policy access item
++ * @type:		One of KDBUS_POLICY_ACCESS_* types
++ * @access:		Access to grant
++ * @id:			For KDBUS_POLICY_ACCESS_USER, the uid
++ *			For KDBUS_POLICY_ACCESS_GROUP, the gid
++ */
++struct kdbus_policy_access {
++	__u64 type;	/* USER, GROUP, WORLD */
++	__u64 access;	/* OWN, TALK, SEE */
++	__u64 id;	/* uid, gid, 0 */
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_attach_flags - flags for metadata attachments
++ * @KDBUS_ATTACH_TIMESTAMP:		Timestamp
++ * @KDBUS_ATTACH_CREDS:			Credentials
++ * @KDBUS_ATTACH_PIDS:			PIDs
++ * @KDBUS_ATTACH_AUXGROUPS:		Auxiliary groups
++ * @KDBUS_ATTACH_NAMES:			Well-known names
++ * @KDBUS_ATTACH_TID_COMM:		The "comm" process identifier of the TID
++ * @KDBUS_ATTACH_PID_COMM:		The "comm" process identifier of the PID
++ * @KDBUS_ATTACH_EXE:			The path of the executable
++ * @KDBUS_ATTACH_CMDLINE:		The process command line
++ * @KDBUS_ATTACH_CGROUP:		The croup membership
++ * @KDBUS_ATTACH_CAPS:			The process capabilities
++ * @KDBUS_ATTACH_SECLABEL:		The security label
++ * @KDBUS_ATTACH_AUDIT:			The audit IDs
++ * @KDBUS_ATTACH_CONN_DESCRIPTION:	The human-readable connection name
++ * @_KDBUS_ATTACH_ALL:			All of the above
++ * @_KDBUS_ATTACH_ANY:			Wildcard match to enable any kind of
++ *					metatdata.
++ */
++enum kdbus_attach_flags {
++	KDBUS_ATTACH_TIMESTAMP		=  1ULL <<  0,
++	KDBUS_ATTACH_CREDS		=  1ULL <<  1,
++	KDBUS_ATTACH_PIDS		=  1ULL <<  2,
++	KDBUS_ATTACH_AUXGROUPS		=  1ULL <<  3,
++	KDBUS_ATTACH_NAMES		=  1ULL <<  4,
++	KDBUS_ATTACH_TID_COMM		=  1ULL <<  5,
++	KDBUS_ATTACH_PID_COMM		=  1ULL <<  6,
++	KDBUS_ATTACH_EXE		=  1ULL <<  7,
++	KDBUS_ATTACH_CMDLINE		=  1ULL <<  8,
++	KDBUS_ATTACH_CGROUP		=  1ULL <<  9,
++	KDBUS_ATTACH_CAPS		=  1ULL << 10,
++	KDBUS_ATTACH_SECLABEL		=  1ULL << 11,
++	KDBUS_ATTACH_AUDIT		=  1ULL << 12,
++	KDBUS_ATTACH_CONN_DESCRIPTION	=  1ULL << 13,
++	_KDBUS_ATTACH_ALL		=  (1ULL << 14) - 1,
++	_KDBUS_ATTACH_ANY		=  ~0ULL
++};
++
++/**
++ * enum kdbus_item_type - item types to chain data in a list
++ * @_KDBUS_ITEM_NULL:			Uninitialized/invalid
++ * @_KDBUS_ITEM_USER_BASE:		Start of user items
++ * @KDBUS_ITEM_NEGOTIATE:		Negotiate supported items
++ * @KDBUS_ITEM_PAYLOAD_VEC:		Vector to data
++ * @KDBUS_ITEM_PAYLOAD_OFF:		Data at returned offset to message head
++ * @KDBUS_ITEM_PAYLOAD_MEMFD:		Data as sealed memfd
++ * @KDBUS_ITEM_FDS:			Attached file descriptors
++ * @KDBUS_ITEM_CANCEL_FD:		FD used to cancel a synchronous
++ *					operation by writing to it from
++ *					userspace
++ * @KDBUS_ITEM_BLOOM_PARAMETER:		Bus-wide bloom parameters, used with
++ *					KDBUS_CMD_BUS_MAKE, carries a
++ *					struct kdbus_bloom_parameter
++ * @KDBUS_ITEM_BLOOM_FILTER:		Bloom filter carried with a message,
++ *					used to match against a bloom mask of a
++ *					connection, carries a struct
++ *					kdbus_bloom_filter
++ * @KDBUS_ITEM_BLOOM_MASK:		Bloom mask used to match against a
++ *					message'sbloom filter
++ * @KDBUS_ITEM_DST_NAME:		Destination's well-known name
++ * @KDBUS_ITEM_MAKE_NAME:		Name of domain, bus, endpoint
++ * @KDBUS_ITEM_ATTACH_FLAGS_SEND:	Attach-flags, used for updating which
++ *					metadata a connection opts in to send
++ * @KDBUS_ITEM_ATTACH_FLAGS_RECV:	Attach-flags, used for updating which
++ *					metadata a connection requests to
++ *					receive for each reeceived message
++ * @KDBUS_ITEM_ID:			Connection ID
++ * @KDBUS_ITEM_NAME:			Well-know name with flags
++ * @_KDBUS_ITEM_ATTACH_BASE:		Start of metadata attach items
++ * @KDBUS_ITEM_TIMESTAMP:		Timestamp
++ * @KDBUS_ITEM_CREDS:			Process credentials
++ * @KDBUS_ITEM_PIDS:			Process identifiers
++ * @KDBUS_ITEM_AUXGROUPS:		Auxiliary process groups
++ * @KDBUS_ITEM_OWNED_NAME:		A name owned by the associated
++ *					connection
++ * @KDBUS_ITEM_TID_COMM:		Thread ID "comm" identifier
++ *					(Don't trust this, see below.)
++ * @KDBUS_ITEM_PID_COMM:		Process ID "comm" identifier
++ *					(Don't trust this, see below.)
++ * @KDBUS_ITEM_EXE:			The path of the executable
++ *					(Don't trust this, see below.)
++ * @KDBUS_ITEM_CMDLINE:			The process command line
++ *					(Don't trust this, see below.)
++ * @KDBUS_ITEM_CGROUP:			The croup membership
++ * @KDBUS_ITEM_CAPS:			The process capabilities
++ * @KDBUS_ITEM_SECLABEL:		The security label
++ * @KDBUS_ITEM_AUDIT:			The audit IDs
++ * @KDBUS_ITEM_CONN_DESCRIPTION:	The connection's human-readable name
++ *					(debugging)
++ * @_KDBUS_ITEM_POLICY_BASE:		Start of policy items
++ * @KDBUS_ITEM_POLICY_ACCESS:		Policy access block
++ * @_KDBUS_ITEM_KERNEL_BASE:		Start of kernel-generated message items
++ * @KDBUS_ITEM_NAME_ADD:		Notification in kdbus_notify_name_change
++ * @KDBUS_ITEM_NAME_REMOVE:		Notification in kdbus_notify_name_change
++ * @KDBUS_ITEM_NAME_CHANGE:		Notification in kdbus_notify_name_change
++ * @KDBUS_ITEM_ID_ADD:			Notification in kdbus_notify_id_change
++ * @KDBUS_ITEM_ID_REMOVE:		Notification in kdbus_notify_id_change
++ * @KDBUS_ITEM_REPLY_TIMEOUT:		Timeout has been reached
++ * @KDBUS_ITEM_REPLY_DEAD:		Destination died
++ *
++ * N.B: The process and thread COMM fields, as well as the CMDLINE and
++ * EXE fields may be altered by unprivileged processes und should
++ * hence *not* used for security decisions. Peers should make use of
++ * these items only for informational purposes, such as generating log
++ * records.
++ */
++enum kdbus_item_type {
++	_KDBUS_ITEM_NULL,
++	_KDBUS_ITEM_USER_BASE,
++	KDBUS_ITEM_NEGOTIATE	= _KDBUS_ITEM_USER_BASE,
++	KDBUS_ITEM_PAYLOAD_VEC,
++	KDBUS_ITEM_PAYLOAD_OFF,
++	KDBUS_ITEM_PAYLOAD_MEMFD,
++	KDBUS_ITEM_FDS,
++	KDBUS_ITEM_CANCEL_FD,
++	KDBUS_ITEM_BLOOM_PARAMETER,
++	KDBUS_ITEM_BLOOM_FILTER,
++	KDBUS_ITEM_BLOOM_MASK,
++	KDBUS_ITEM_DST_NAME,
++	KDBUS_ITEM_MAKE_NAME,
++	KDBUS_ITEM_ATTACH_FLAGS_SEND,
++	KDBUS_ITEM_ATTACH_FLAGS_RECV,
++	KDBUS_ITEM_ID,
++	KDBUS_ITEM_NAME,
++	KDBUS_ITEM_DST_ID,
++
++	/* keep these item types in sync with KDBUS_ATTACH_* flags */
++	_KDBUS_ITEM_ATTACH_BASE	= 0x1000,
++	KDBUS_ITEM_TIMESTAMP	= _KDBUS_ITEM_ATTACH_BASE,
++	KDBUS_ITEM_CREDS,
++	KDBUS_ITEM_PIDS,
++	KDBUS_ITEM_AUXGROUPS,
++	KDBUS_ITEM_OWNED_NAME,
++	KDBUS_ITEM_TID_COMM,
++	KDBUS_ITEM_PID_COMM,
++	KDBUS_ITEM_EXE,
++	KDBUS_ITEM_CMDLINE,
++	KDBUS_ITEM_CGROUP,
++	KDBUS_ITEM_CAPS,
++	KDBUS_ITEM_SECLABEL,
++	KDBUS_ITEM_AUDIT,
++	KDBUS_ITEM_CONN_DESCRIPTION,
++
++	_KDBUS_ITEM_POLICY_BASE	= 0x2000,
++	KDBUS_ITEM_POLICY_ACCESS = _KDBUS_ITEM_POLICY_BASE,
++
++	_KDBUS_ITEM_KERNEL_BASE	= 0x8000,
++	KDBUS_ITEM_NAME_ADD	= _KDBUS_ITEM_KERNEL_BASE,
++	KDBUS_ITEM_NAME_REMOVE,
++	KDBUS_ITEM_NAME_CHANGE,
++	KDBUS_ITEM_ID_ADD,
++	KDBUS_ITEM_ID_REMOVE,
++	KDBUS_ITEM_REPLY_TIMEOUT,
++	KDBUS_ITEM_REPLY_DEAD,
++};
++
++/**
++ * struct kdbus_item - chain of data blocks
++ * @size:		Overall data record size
++ * @type:		Kdbus_item type of data
++ * @data:		Generic bytes
++ * @data32:		Generic 32 bit array
++ * @data64:		Generic 64 bit array
++ * @str:		Generic string
++ * @id:			Connection ID
++ * @vec:		KDBUS_ITEM_PAYLOAD_VEC
++ * @creds:		KDBUS_ITEM_CREDS
++ * @audit:		KDBUS_ITEM_AUDIT
++ * @timestamp:		KDBUS_ITEM_TIMESTAMP
++ * @name:		KDBUS_ITEM_NAME
++ * @bloom_parameter:	KDBUS_ITEM_BLOOM_PARAMETER
++ * @bloom_filter:	KDBUS_ITEM_BLOOM_FILTER
++ * @memfd:		KDBUS_ITEM_PAYLOAD_MEMFD
++ * @name_change:	KDBUS_ITEM_NAME_ADD
++ *			KDBUS_ITEM_NAME_REMOVE
++ *			KDBUS_ITEM_NAME_CHANGE
++ * @id_change:		KDBUS_ITEM_ID_ADD
++ *			KDBUS_ITEM_ID_REMOVE
++ * @policy:		KDBUS_ITEM_POLICY_ACCESS
++ */
++struct kdbus_item {
++	__u64 size;
++	__u64 type;
++	union {
++		__u8 data[0];
++		__u32 data32[0];
++		__u64 data64[0];
++		char str[0];
++
++		__u64 id;
++		struct kdbus_vec vec;
++		struct kdbus_creds creds;
++		struct kdbus_pids pids;
++		struct kdbus_audit audit;
++		struct kdbus_caps caps;
++		struct kdbus_timestamp timestamp;
++		struct kdbus_name name;
++		struct kdbus_bloom_parameter bloom_parameter;
++		struct kdbus_bloom_filter bloom_filter;
++		struct kdbus_memfd memfd;
++		int fds[0];
++		struct kdbus_notify_name_change name_change;
++		struct kdbus_notify_id_change id_change;
++		struct kdbus_policy_access policy_access;
++	};
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_msg_flags - type of message
++ * @KDBUS_MSG_EXPECT_REPLY:	Expect a reply message, used for
++ *				method calls. The userspace-supplied
++ *				cookie identifies the message and the
++ *				respective reply carries the cookie
++ *				in cookie_reply
++ * @KDBUS_MSG_NO_AUTO_START:	Do not start a service if the addressed
++ *				name is not currently active. This flag is
++ *				not looked at by the kernel but only
++ *				serves as hint for userspace implementations.
++ * @KDBUS_MSG_SIGNAL:		Treat this message as signal
++ */
++enum kdbus_msg_flags {
++	KDBUS_MSG_EXPECT_REPLY	= 1ULL << 0,
++	KDBUS_MSG_NO_AUTO_START	= 1ULL << 1,
++	KDBUS_MSG_SIGNAL	= 1ULL << 2,
++};
++
++/**
++ * enum kdbus_payload_type - type of payload carried by message
++ * @KDBUS_PAYLOAD_KERNEL:	Kernel-generated simple message
++ * @KDBUS_PAYLOAD_DBUS:		D-Bus marshalling "DBusDBus"
++ *
++ * Any payload-type is accepted. Common types will get added here once
++ * established.
++ */
++enum kdbus_payload_type {
++	KDBUS_PAYLOAD_KERNEL,
++	KDBUS_PAYLOAD_DBUS	= 0x4442757344427573ULL,
++};
++
++/**
++ * struct kdbus_msg - the representation of a kdbus message
++ * @size:		Total size of the message
++ * @flags:		Message flags (KDBUS_MSG_*), userspace → kernel
++ * @priority:		Message queue priority value
++ * @dst_id:		64-bit ID of the destination connection
++ * @src_id:		64-bit ID of the source connection
++ * @payload_type:	Payload type (KDBUS_PAYLOAD_*)
++ * @cookie:		Userspace-supplied cookie, for the connection
++ *			to identify its messages
++ * @timeout_ns:		The time to wait for a message reply from the peer.
++ *			If there is no reply, and the send command is
++ *			executed asynchronously, a kernel-generated message
++ *			with an attached KDBUS_ITEM_REPLY_TIMEOUT item
++ *			is sent to @src_id. For synchronously executed send
++ *			command, the value denotes the maximum time the call
++ *			blocks to wait for a reply. The timeout is expected in
++ *			nanoseconds and as absolute CLOCK_MONOTONIC value.
++ * @cookie_reply:	A reply to the requesting message with the same
++ *			cookie. The requesting connection can match its
++ *			request and the reply with this value
++ * @items:		A list of kdbus_items containing the message payload
++ */
++struct kdbus_msg {
++	__u64 size;
++	__u64 flags;
++	__s64 priority;
++	__u64 dst_id;
++	__u64 src_id;
++	__u64 payload_type;
++	__u64 cookie;
++	union {
++		__u64 timeout_ns;
++		__u64 cookie_reply;
++	};
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_msg_info - returned message container
++ * @offset:		Offset of kdbus_msg slice in pool
++ * @msg_size:		Copy of the kdbus_msg.size field
++ * @return_flags:	Command return flags, kernel → userspace
++ */
++struct kdbus_msg_info {
++	__u64 offset;
++	__u64 msg_size;
++	__u64 return_flags;
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_send_flags - flags for sending messages
++ * @KDBUS_SEND_SYNC_REPLY:	Wait for destination connection to
++ *				reply to this message. The
++ *				KDBUS_CMD_SEND ioctl() will block
++ *				until the reply is received, and
++ *				reply in struct kdbus_cmd_send will
++ *				yield the offset in the sender's pool
++ *				where the reply can be found.
++ *				This flag is only valid if
++ *				@KDBUS_MSG_EXPECT_REPLY is set as well.
++ */
++enum kdbus_send_flags {
++	KDBUS_SEND_SYNC_REPLY		= 1ULL << 0,
++};
++
++/**
++ * struct kdbus_cmd_send - send message
++ * @size:		Overall size of this structure
++ * @flags:		Flags to change send behavior (KDBUS_SEND_*)
++ * @return_flags:	Command return flags, kernel → userspace
++ * @msg_address:	Storage address of the kdbus_msg to send
++ * @reply:		Storage for message reply if KDBUS_SEND_SYNC_REPLY
++ *			was given
++ * @items:		Additional items for this command
++ */
++struct kdbus_cmd_send {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	__u64 msg_address;
++	struct kdbus_msg_info reply;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_recv_flags - flags for de-queuing messages
++ * @KDBUS_RECV_PEEK:		Return the next queued message without
++ *				actually de-queuing it, and without installing
++ *				any file descriptors or other resources. It is
++ *				usually used to determine the activating
++ *				connection of a bus name.
++ * @KDBUS_RECV_DROP:		Drop and free the next queued message and all
++ *				its resources without actually receiving it.
++ * @KDBUS_RECV_USE_PRIORITY:	Only de-queue messages with the specified or
++ *				higher priority (lowest values); if not set,
++ *				the priority value is ignored.
++ */
++enum kdbus_recv_flags {
++	KDBUS_RECV_PEEK		= 1ULL <<  0,
++	KDBUS_RECV_DROP		= 1ULL <<  1,
++	KDBUS_RECV_USE_PRIORITY	= 1ULL <<  2,
++};
++
++/**
++ * enum kdbus_recv_return_flags - return flags for message receive commands
++ * @KDBUS_RECV_RETURN_INCOMPLETE_FDS:	One or more file descriptors could not
++ *					be installed. These descriptors in
++ *					KDBUS_ITEM_FDS will carry the value -1.
++ * @KDBUS_RECV_RETURN_DROPPED_MSGS:	There have been dropped messages since
++ *					the last time a message was received.
++ *					The 'dropped_msgs' counter contains the
++ *					number of messages dropped pool
++ *					overflows or other missed broadcasts.
++ */
++enum kdbus_recv_return_flags {
++	KDBUS_RECV_RETURN_INCOMPLETE_FDS	= 1ULL <<  0,
++	KDBUS_RECV_RETURN_DROPPED_MSGS		= 1ULL <<  1,
++};
++
++/**
++ * struct kdbus_cmd_recv - struct to de-queue a buffered message
++ * @size:		Overall size of this object
++ * @flags:		KDBUS_RECV_* flags, userspace → kernel
++ * @return_flags:	Command return flags, kernel → userspace
++ * @priority:		Minimum priority of the messages to de-queue. Lowest
++ *			values have the highest priority.
++ * @dropped_msgs:	In case there were any dropped messages since the last
++ *			time a message was received, this will be set to the
++ *			number of lost messages and
++ *			KDBUS_RECV_RETURN_DROPPED_MSGS will be set in
++ *			'return_flags'. This can only happen if the ioctl
++ *			returns 0 or EAGAIN.
++ * @msg:		Return storage for received message.
++ * @items:		Additional items for this command.
++ *
++ * This struct is used with the KDBUS_CMD_RECV ioctl.
++ */
++struct kdbus_cmd_recv {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	__s64 priority;
++	__u64 dropped_msgs;
++	struct kdbus_msg_info msg;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_cmd_free - struct to free a slice of memory in the pool
++ * @size:		Overall size of this structure
++ * @flags:		Flags for the free command, userspace → kernel
++ * @return_flags:	Command return flags, kernel → userspace
++ * @offset:		The offset of the memory slice, as returned by other
++ *			ioctls
++ * @items:		Additional items to modify the behavior
++ *
++ * This struct is used with the KDBUS_CMD_FREE ioctl.
++ */
++struct kdbus_cmd_free {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	__u64 offset;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello
++ * @KDBUS_HELLO_ACCEPT_FD:	The connection allows the reception of
++ *				any passed file descriptors
++ * @KDBUS_HELLO_ACTIVATOR:	Special-purpose connection which registers
++ *				a well-know name for a process to be started
++ *				when traffic arrives
++ * @KDBUS_HELLO_POLICY_HOLDER:	Special-purpose connection which registers
++ *				policy entries for a name. The provided name
++ *				is not activated and not registered with the
++ *				name database, it only allows unprivileged
++ *				connections to acquire a name, talk or discover
++ *				a service
++ * @KDBUS_HELLO_MONITOR:	Special-purpose connection to monitor
++ *				bus traffic
++ */
++enum kdbus_hello_flags {
++	KDBUS_HELLO_ACCEPT_FD		=  1ULL <<  0,
++	KDBUS_HELLO_ACTIVATOR		=  1ULL <<  1,
++	KDBUS_HELLO_POLICY_HOLDER	=  1ULL <<  2,
++	KDBUS_HELLO_MONITOR		=  1ULL <<  3,
++};
++
++/**
++ * struct kdbus_cmd_hello - struct to say hello to kdbus
++ * @size:		The total size of the structure
++ * @flags:		Connection flags (KDBUS_HELLO_*), userspace → kernel
++ * @return_flags:	Command return flags, kernel → userspace
++ * @attach_flags_send:	Mask of metadata to attach to each message sent
++ *			off by this connection (KDBUS_ATTACH_*)
++ * @attach_flags_recv:	Mask of metadata to attach to each message receieved
++ *			by the new connection (KDBUS_ATTACH_*)
++ * @bus_flags:		The flags field copied verbatim from the original
++ *			KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful
++ *			to do negotiation of features of the payload that is
++ *			transferred (kernel → userspace)
++ * @id:			The ID of this connection (kernel → userspace)
++ * @pool_size:		Size of the connection's buffer where the received
++ *			messages are placed
++ * @offset:		Pool offset where items are returned to report
++ *			additional information about the bus and the newly
++ *			created connection.
++ * @items_size:		Size of buffer returned in the pool slice at @offset.
++ * @id128:		Unique 128-bit ID of the bus (kernel → userspace)
++ * @items:		A list of items
++ *
++ * This struct is used with the KDBUS_CMD_HELLO ioctl.
++ */
++struct kdbus_cmd_hello {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	__u64 attach_flags_send;
++	__u64 attach_flags_recv;
++	__u64 bus_flags;
++	__u64 id;
++	__u64 pool_size;
++	__u64 offset;
++	__u64 items_size;
++	__u8 id128[16];
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_info - connection information
++ * @size:		total size of the struct
++ * @id:			64bit object ID
++ * @flags:		object creation flags
++ * @items:		list of items
++ *
++ * Note that the user is responsible for freeing the allocated memory with
++ * the KDBUS_CMD_FREE ioctl.
++ */
++struct kdbus_info {
++	__u64 size;
++	__u64 id;
++	__u64 flags;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_list_flags - what to include into the returned list
++ * @KDBUS_LIST_UNIQUE:		active connections
++ * @KDBUS_LIST_ACTIVATORS:	activator connections
++ * @KDBUS_LIST_NAMES:		known well-known names
++ * @KDBUS_LIST_QUEUED:		queued-up names
++ */
++enum kdbus_list_flags {
++	KDBUS_LIST_UNIQUE		= 1ULL <<  0,
++	KDBUS_LIST_NAMES		= 1ULL <<  1,
++	KDBUS_LIST_ACTIVATORS		= 1ULL <<  2,
++	KDBUS_LIST_QUEUED		= 1ULL <<  3,
++};
++
++/**
++ * struct kdbus_cmd_list - list connections
++ * @size:		overall size of this object
++ * @flags:		flags for the query (KDBUS_LIST_*), userspace → kernel
++ * @return_flags:	command return flags, kernel → userspace
++ * @offset:		Offset in the caller's pool buffer where an array of
++ *			kdbus_info objects is stored.
++ *			The user must use KDBUS_CMD_FREE to free the
++ *			allocated memory.
++ * @list_size:		size of returned list in bytes
++ * @items:		Items for the command. Reserved for future use.
++ *
++ * This structure is used with the KDBUS_CMD_LIST ioctl.
++ */
++struct kdbus_cmd_list {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	__u64 offset;
++	__u64 list_size;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * struct kdbus_cmd_info - struct used for KDBUS_CMD_CONN_INFO ioctl
++ * @size:		The total size of the struct
++ * @flags:		Flags for this ioctl, userspace → kernel
++ * @return_flags:	Command return flags, kernel → userspace
++ * @id:			The 64-bit ID of the connection. If set to zero, passing
++ *			@name is required. kdbus will look up the name to
++ *			determine the ID in this case.
++ * @attach_flags:	Set of attach flags to specify the set of information
++ *			to receive, userspace → kernel
++ * @offset:		Returned offset in the caller's pool buffer where the
++ *			kdbus_info struct result is stored. The user must
++ *			use KDBUS_CMD_FREE to free the allocated memory.
++ * @info_size:		Output buffer to report size of data at @offset.
++ * @items:		The optional item list, containing the
++ *			well-known name to look up as a KDBUS_ITEM_NAME.
++ *			Only needed in case @id is zero.
++ *
++ * On success, the KDBUS_CMD_CONN_INFO ioctl will return 0 and @offset will
++ * tell the user the offset in the connection pool buffer at which to find the
++ * result in a struct kdbus_info.
++ */
++struct kdbus_cmd_info {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	__u64 id;
++	__u64 attach_flags;
++	__u64 offset;
++	__u64 info_size;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_cmd_match_flags - flags to control the KDBUS_CMD_MATCH_ADD ioctl
++ * @KDBUS_MATCH_REPLACE:	If entries with the supplied cookie already
++ *				exists, remove them before installing the new
++ *				matches.
++ */
++enum kdbus_cmd_match_flags {
++	KDBUS_MATCH_REPLACE	= 1ULL <<  0,
++};
++
++/**
++ * struct kdbus_cmd_match - struct to add or remove matches
++ * @size:		The total size of the struct
++ * @flags:		Flags for match command (KDBUS_MATCH_*),
++ *			userspace → kernel
++ * @return_flags:	Command return flags, kernel → userspace
++ * @cookie:		Userspace supplied cookie. When removing, the cookie
++ *			identifies the match to remove
++ * @items:		A list of items for additional information
++ *
++ * This structure is used with the KDBUS_CMD_MATCH_ADD and
++ * KDBUS_CMD_MATCH_REMOVE ioctl.
++ */
++struct kdbus_cmd_match {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	__u64 cookie;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,ENDPOINT}_MAKE
++ * @KDBUS_MAKE_ACCESS_GROUP:	Make the bus or endpoint node group-accessible
++ * @KDBUS_MAKE_ACCESS_WORLD:	Make the bus or endpoint node world-accessible
++ */
++enum kdbus_make_flags {
++	KDBUS_MAKE_ACCESS_GROUP		= 1ULL <<  0,
++	KDBUS_MAKE_ACCESS_WORLD		= 1ULL <<  1,
++};
++
++/**
++ * enum kdbus_name_flags - flags for KDBUS_CMD_NAME_ACQUIRE
++ * @KDBUS_NAME_REPLACE_EXISTING:	Try to replace name of other connections
++ * @KDBUS_NAME_ALLOW_REPLACEMENT:	Allow the replacement of the name
++ * @KDBUS_NAME_QUEUE:			Name should be queued if busy
++ * @KDBUS_NAME_IN_QUEUE:		Name is queued
++ * @KDBUS_NAME_ACTIVATOR:		Name is owned by a activator connection
++ * @KDBUS_NAME_PRIMARY:			Primary owner of the name
++ * @KDBUS_NAME_ACQUIRED:		Name was acquired/queued _now_
++ */
++enum kdbus_name_flags {
++	KDBUS_NAME_REPLACE_EXISTING	= 1ULL <<  0,
++	KDBUS_NAME_ALLOW_REPLACEMENT	= 1ULL <<  1,
++	KDBUS_NAME_QUEUE		= 1ULL <<  2,
++	KDBUS_NAME_IN_QUEUE		= 1ULL <<  3,
++	KDBUS_NAME_ACTIVATOR		= 1ULL <<  4,
++	KDBUS_NAME_PRIMARY		= 1ULL <<  5,
++	KDBUS_NAME_ACQUIRED		= 1ULL <<  6,
++};
++
++/**
++ * struct kdbus_cmd - generic ioctl payload
++ * @size:		Overall size of this structure
++ * @flags:		Flags for this ioctl, userspace → kernel
++ * @return_flags:	Ioctl return flags, kernel → userspace
++ * @items:		Additional items to modify the behavior
++ *
++ * This is a generic ioctl payload object. It's used by all ioctls that only
++ * take flags and items as input.
++ */
++struct kdbus_cmd {
++	__u64 size;
++	__u64 flags;
++	__u64 return_flags;
++	struct kdbus_item items[0];
++} __attribute__((__aligned__(8)));
++
++/**
++ * Ioctl API
++ *
++ * KDBUS_CMD_BUS_MAKE:		After opening the "control" node, this command
++ *				creates a new bus with the specified
++ *				name. The bus is immediately shut down and
++ *				cleaned up when the opened file descriptor is
++ *				closed.
++ *
++ * KDBUS_CMD_ENDPOINT_MAKE:	Creates a new named special endpoint to talk to
++ *				the bus. Such endpoints usually carry a more
++ *				restrictive policy and grant restricted access
++ *				to specific applications.
++ * KDBUS_CMD_ENDPOINT_UPDATE:	Update the properties of a custom enpoint. Used
++ *				to update the policy.
++ *
++ * KDBUS_CMD_HELLO:		By opening the bus node, a connection is
++ *				created. After a HELLO the opened connection
++ *				becomes an active peer on the bus.
++ * KDBUS_CMD_UPDATE:		Update the properties of a connection. Used to
++ *				update the metadata subscription mask and
++ *				policy.
++ * KDBUS_CMD_BYEBYE:		Disconnect a connection. If there are no
++ *				messages queued up in the connection's pool,
++ *				the call succeeds, and the handle is rendered
++ *				unusable. Otherwise, -EBUSY is returned without
++ *				any further side-effects.
++ * KDBUS_CMD_FREE:		Release the allocated memory in the receiver's
++ *				pool.
++ * KDBUS_CMD_CONN_INFO:		Retrieve credentials and properties of the
++ *				initial creator of the connection. The data was
++ *				stored at registration time and does not
++ *				necessarily represent the connected process or
++ *				the actual state of the process.
++ * KDBUS_CMD_BUS_CREATOR_INFO:	Retrieve information of the creator of the bus
++ *				a connection is attached to.
++ *
++ * KDBUS_CMD_SEND:		Send a message and pass data from userspace to
++ *				the kernel.
++ * KDBUS_CMD_RECV:		Receive a message from the kernel which is
++ *				placed in the receiver's pool.
++ *
++ * KDBUS_CMD_NAME_ACQUIRE:	Request a well-known bus name to associate with
++ *				the connection. Well-known names are used to
++ *				address a peer on the bus.
++ * KDBUS_CMD_NAME_RELEASE:	Release a well-known name the connection
++ *				currently owns.
++ * KDBUS_CMD_LIST:		Retrieve the list of all currently registered
++ *				well-known and unique names.
++ *
++ * KDBUS_CMD_MATCH_ADD:		Install a match which broadcast messages should
++ *				be delivered to the connection.
++ * KDBUS_CMD_MATCH_REMOVE:	Remove a current match for broadcast messages.
++ */
++enum kdbus_ioctl_type {
++	/* bus owner (00-0f) */
++	KDBUS_CMD_BUS_MAKE =		_IOW(KDBUS_IOCTL_MAGIC, 0x00,
++					     struct kdbus_cmd),
++
++	/* endpoint owner (10-1f) */
++	KDBUS_CMD_ENDPOINT_MAKE =	_IOW(KDBUS_IOCTL_MAGIC, 0x10,
++					     struct kdbus_cmd),
++	KDBUS_CMD_ENDPOINT_UPDATE =	_IOW(KDBUS_IOCTL_MAGIC, 0x11,
++					     struct kdbus_cmd),
++
++	/* connection owner (80-ff) */
++	KDBUS_CMD_HELLO =		_IOWR(KDBUS_IOCTL_MAGIC, 0x80,
++					      struct kdbus_cmd_hello),
++	KDBUS_CMD_UPDATE =		_IOW(KDBUS_IOCTL_MAGIC, 0x81,
++					     struct kdbus_cmd),
++	KDBUS_CMD_BYEBYE =		_IOW(KDBUS_IOCTL_MAGIC, 0x82,
++					     struct kdbus_cmd),
++	KDBUS_CMD_FREE =		_IOW(KDBUS_IOCTL_MAGIC, 0x83,
++					     struct kdbus_cmd_free),
++	KDBUS_CMD_CONN_INFO =		_IOR(KDBUS_IOCTL_MAGIC, 0x84,
++					     struct kdbus_cmd_info),
++	KDBUS_CMD_BUS_CREATOR_INFO =	_IOR(KDBUS_IOCTL_MAGIC, 0x85,
++					     struct kdbus_cmd_info),
++	KDBUS_CMD_LIST =		_IOR(KDBUS_IOCTL_MAGIC, 0x86,
++					     struct kdbus_cmd_list),
++
++	KDBUS_CMD_SEND =		_IOW(KDBUS_IOCTL_MAGIC, 0x90,
++					     struct kdbus_cmd_send),
++	KDBUS_CMD_RECV =		_IOR(KDBUS_IOCTL_MAGIC, 0x91,
++					     struct kdbus_cmd_recv),
++
++	KDBUS_CMD_NAME_ACQUIRE =	_IOW(KDBUS_IOCTL_MAGIC, 0xa0,
++					     struct kdbus_cmd),
++	KDBUS_CMD_NAME_RELEASE =	_IOW(KDBUS_IOCTL_MAGIC, 0xa1,
++					     struct kdbus_cmd),
++
++	KDBUS_CMD_MATCH_ADD =		_IOW(KDBUS_IOCTL_MAGIC, 0xb0,
++					     struct kdbus_cmd_match),
++	KDBUS_CMD_MATCH_REMOVE =	_IOW(KDBUS_IOCTL_MAGIC, 0xb1,
++					     struct kdbus_cmd_match),
++};
++
++#endif /* _UAPI_KDBUS_H_ */
+diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
+index 7b1425a..ce2ac5a 100644
+--- a/include/uapi/linux/magic.h
++++ b/include/uapi/linux/magic.h
+@@ -76,4 +76,6 @@
+ #define BTRFS_TEST_MAGIC	0x73727279
+ #define NSFS_MAGIC		0x6e736673
+ 
++#define KDBUS_SUPER_MAGIC	0x44427573
++
+ #endif /* __LINUX_MAGIC_H__ */
+diff --git a/init/Kconfig b/init/Kconfig
+index dc24dec..9388071 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -261,6 +261,19 @@ config POSIX_MQUEUE_SYSCTL
+ 	depends on SYSCTL
+ 	default y
+ 
++config KDBUS
++	tristate "kdbus interprocess communication"
++	depends on TMPFS
++	help
++	  D-Bus is a system for low-latency, low-overhead, easy to use
++	  interprocess communication (IPC).
++
++	  See the man-pages and HTML files in Documentation/kdbus/
++	  that are generated by 'make mandocs' and 'make htmldocs'.
++
++	  If you have an ordinary machine, select M here. The module
++	  will be called kdbus.
++
+ config CROSS_MEMORY_ATTACH
+ 	bool "Enable process_vm_readv/writev syscalls"
+ 	depends on MMU
+diff --git a/ipc/Makefile b/ipc/Makefile
+index 86c7300..68ec416 100644
+--- a/ipc/Makefile
++++ b/ipc/Makefile
+@@ -9,4 +9,4 @@ obj_mq-$(CONFIG_COMPAT) += compat_mq.o
+ obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
+ obj-$(CONFIG_IPC_NS) += namespace.o
+ obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
+-
++obj-$(CONFIG_KDBUS) += kdbus/
+diff --git a/ipc/kdbus/Makefile b/ipc/kdbus/Makefile
+new file mode 100644
+index 0000000..66663a1
+--- /dev/null
++++ b/ipc/kdbus/Makefile
+@@ -0,0 +1,33 @@
++#
++# By setting KDBUS_EXT=2, the kdbus module will be built as kdbus2.ko, and
++# KBUILD_MODNAME=kdbus2. This has the effect that all exported objects have
++# different names than usually (kdbus2fs, /sys/fs/kdbus2/) and you can run
++# your test-infrastructure against the kdbus2.ko, while running your system
++# on kdbus.ko.
++#
++# To just build the module, use:
++#     make KDBUS_EXT=2 M=ipc/kdbus
++#
++
++kdbus$(KDBUS_EXT)-y := \
++	bus.o \
++	connection.o \
++	endpoint.o \
++	fs.o \
++	handle.o \
++	item.o \
++	main.o \
++	match.o \
++	message.o \
++	metadata.o \
++	names.o \
++	node.o \
++	notify.o \
++	domain.o \
++	policy.o \
++	pool.o \
++	reply.o \
++	queue.o \
++	util.o
++
++obj-$(CONFIG_KDBUS) += kdbus$(KDBUS_EXT).o
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+new file mode 100644
+index 0000000..a67f825
+--- /dev/null
++++ b/ipc/kdbus/bus.c
+@@ -0,0 +1,514 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/fs.h>
++#include <linux/hashtable.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/random.h>
++#include <linux/sched.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/uio.h>
++
++#include "bus.h"
++#include "notify.h"
++#include "connection.h"
++#include "domain.h"
++#include "endpoint.h"
++#include "handle.h"
++#include "item.h"
++#include "match.h"
++#include "message.h"
++#include "metadata.h"
++#include "names.h"
++#include "policy.h"
++#include "util.h"
++
++static void kdbus_bus_free(struct kdbus_node *node)
++{
++	struct kdbus_bus *bus = container_of(node, struct kdbus_bus, node);
++
++	WARN_ON(!list_empty(&bus->monitors_list));
++	WARN_ON(!hash_empty(bus->conn_hash));
++
++	kdbus_notify_free(bus);
++
++	kdbus_user_unref(bus->creator);
++	kdbus_name_registry_free(bus->name_registry);
++	kdbus_domain_unref(bus->domain);
++	kdbus_policy_db_clear(&bus->policy_db);
++	kdbus_meta_proc_unref(bus->creator_meta);
++	kfree(bus);
++}
++
++static void kdbus_bus_release(struct kdbus_node *node, bool was_active)
++{
++	struct kdbus_bus *bus = container_of(node, struct kdbus_bus, node);
++
++	if (was_active)
++		atomic_dec(&bus->creator->buses);
++}
++
++static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
++				       const char *name,
++				       struct kdbus_bloom_parameter *bloom,
++				       const u64 *pattach_owner,
++				       u64 flags, kuid_t uid, kgid_t gid)
++{
++	struct kdbus_bus *b;
++	u64 attach_owner;
++	int ret;
++
++	if (bloom->size < 8 || bloom->size > KDBUS_BUS_BLOOM_MAX_SIZE ||
++	    !KDBUS_IS_ALIGNED8(bloom->size) || bloom->n_hash < 1)
++		return ERR_PTR(-EINVAL);
++
++	ret = kdbus_sanitize_attach_flags(pattach_owner ? *pattach_owner : 0,
++					  &attach_owner);
++	if (ret < 0)
++		return ERR_PTR(ret);
++
++	ret = kdbus_verify_uid_prefix(name, domain->user_namespace, uid);
++	if (ret < 0)
++		return ERR_PTR(ret);
++
++	b = kzalloc(sizeof(*b), GFP_KERNEL);
++	if (!b)
++		return ERR_PTR(-ENOMEM);
++
++	kdbus_node_init(&b->node, KDBUS_NODE_BUS);
++
++	b->node.free_cb = kdbus_bus_free;
++	b->node.release_cb = kdbus_bus_release;
++	b->node.uid = uid;
++	b->node.gid = gid;
++	b->node.mode = S_IRUSR | S_IXUSR;
++
++	if (flags & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD))
++		b->node.mode |= S_IRGRP | S_IXGRP;
++	if (flags & KDBUS_MAKE_ACCESS_WORLD)
++		b->node.mode |= S_IROTH | S_IXOTH;
++
++	b->id = atomic64_inc_return(&domain->last_id);
++	b->bus_flags = flags;
++	b->attach_flags_owner = attach_owner;
++	generate_random_uuid(b->id128);
++	b->bloom = *bloom;
++	b->domain = kdbus_domain_ref(domain);
++
++	kdbus_policy_db_init(&b->policy_db);
++
++	init_rwsem(&b->conn_rwlock);
++	hash_init(b->conn_hash);
++	INIT_LIST_HEAD(&b->monitors_list);
++
++	INIT_LIST_HEAD(&b->notify_list);
++	spin_lock_init(&b->notify_lock);
++	mutex_init(&b->notify_flush_lock);
++
++	ret = kdbus_node_link(&b->node, &domain->node, name);
++	if (ret < 0)
++		goto exit_unref;
++
++	/* cache the metadata/credentials of the creator */
++	b->creator_meta = kdbus_meta_proc_new();
++	if (IS_ERR(b->creator_meta)) {
++		ret = PTR_ERR(b->creator_meta);
++		b->creator_meta = NULL;
++		goto exit_unref;
++	}
++
++	ret = kdbus_meta_proc_collect(b->creator_meta,
++				      KDBUS_ATTACH_CREDS |
++				      KDBUS_ATTACH_PIDS |
++				      KDBUS_ATTACH_AUXGROUPS |
++				      KDBUS_ATTACH_TID_COMM |
++				      KDBUS_ATTACH_PID_COMM |
++				      KDBUS_ATTACH_EXE |
++				      KDBUS_ATTACH_CMDLINE |
++				      KDBUS_ATTACH_CGROUP |
++				      KDBUS_ATTACH_CAPS |
++				      KDBUS_ATTACH_SECLABEL |
++				      KDBUS_ATTACH_AUDIT);
++	if (ret < 0)
++		goto exit_unref;
++
++	b->name_registry = kdbus_name_registry_new();
++	if (IS_ERR(b->name_registry)) {
++		ret = PTR_ERR(b->name_registry);
++		b->name_registry = NULL;
++		goto exit_unref;
++	}
++
++	/*
++	 * Bus-limits of the creator are accounted on its real UID, just like
++	 * all other per-user limits.
++	 */
++	b->creator = kdbus_user_lookup(domain, current_uid());
++	if (IS_ERR(b->creator)) {
++		ret = PTR_ERR(b->creator);
++		b->creator = NULL;
++		goto exit_unref;
++	}
++
++	return b;
++
++exit_unref:
++	kdbus_node_deactivate(&b->node);
++	kdbus_node_unref(&b->node);
++	return ERR_PTR(ret);
++}
++
++/**
++ * kdbus_bus_ref() - increase the reference counter of a kdbus_bus
++ * @bus:		The bus to reference
++ *
++ * Every user of a bus, except for its creator, must add a reference to the
++ * kdbus_bus using this function.
++ *
++ * Return: the bus itself
++ */
++struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus)
++{
++	if (bus)
++		kdbus_node_ref(&bus->node);
++	return bus;
++}
++
++/**
++ * kdbus_bus_unref() - decrease the reference counter of a kdbus_bus
++ * @bus:		The bus to unref
++ *
++ * Release a reference. If the reference count drops to 0, the bus will be
++ * freed.
++ *
++ * Return: NULL
++ */
++struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus)
++{
++	if (bus)
++		kdbus_node_unref(&bus->node);
++	return NULL;
++}
++
++/**
++ * kdbus_bus_find_conn_by_id() - find a connection with a given id
++ * @bus:		The bus to look for the connection
++ * @id:			The 64-bit connection id
++ *
++ * Looks up a connection with a given id. The returned connection
++ * is ref'ed, and needs to be unref'ed by the user. Returns NULL if
++ * the connection can't be found.
++ */
++struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id)
++{
++	struct kdbus_conn *conn, *found = NULL;
++
++	down_read(&bus->conn_rwlock);
++	hash_for_each_possible(bus->conn_hash, conn, hentry, id)
++		if (conn->id == id) {
++			found = kdbus_conn_ref(conn);
++			break;
++		}
++	up_read(&bus->conn_rwlock);
++
++	return found;
++}
++
++/**
++ * kdbus_bus_broadcast() - send a message to all subscribed connections
++ * @bus:	The bus the connections are connected to
++ * @conn_src:	The source connection, may be %NULL for kernel notifications
++ * @staging:	Staging object containing the message to send
++ *
++ * Send message to all connections that are currently active on the bus.
++ * Connections must still have matches installed in order to let the message
++ * pass.
++ *
++ * The caller must hold the name-registry lock of @bus.
++ */
++void kdbus_bus_broadcast(struct kdbus_bus *bus,
++			 struct kdbus_conn *conn_src,
++			 struct kdbus_staging *staging)
++{
++	struct kdbus_conn *conn_dst;
++	unsigned int i;
++	int ret;
++
++	lockdep_assert_held(&bus->name_registry->rwlock);
++
++	/*
++	 * Make sure broadcast are queued on monitors before we send it out to
++	 * anyone else. Otherwise, connections might react to broadcasts before
++	 * the monitor gets the broadcast queued. In the worst case, the
++	 * monitor sees a reaction to the broadcast before the broadcast itself.
++	 * We don't give ordering guarantees across connections (and monitors
++	 * can re-construct order via sequence numbers), but we should at least
++	 * try to avoid re-ordering for monitors.
++	 */
++	kdbus_bus_eavesdrop(bus, conn_src, staging);
++
++	down_read(&bus->conn_rwlock);
++	hash_for_each(bus->conn_hash, i, conn_dst, hentry) {
++		if (!kdbus_conn_is_ordinary(conn_dst))
++			continue;
++
++		/*
++		 * Check if there is a match for the kmsg object in
++		 * the destination connection match db
++		 */
++		if (!kdbus_match_db_match_msg(conn_dst->match_db, conn_src,
++					      staging))
++			continue;
++
++		if (conn_src) {
++			/*
++			 * Anyone can send broadcasts, as they have no
++			 * destination. But a receiver needs TALK access to
++			 * the sender in order to receive broadcasts.
++			 */
++			if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src))
++				continue;
++		} else {
++			/*
++			 * Check if there is a policy db that prevents the
++			 * destination connection from receiving this kernel
++			 * notification
++			 */
++			if (!kdbus_conn_policy_see_notification(conn_dst, NULL,
++								staging->msg))
++				continue;
++		}
++
++		ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging,
++					      NULL, NULL);
++		if (ret < 0)
++			kdbus_conn_lost_message(conn_dst);
++	}
++	up_read(&bus->conn_rwlock);
++}
++
++/**
++ * kdbus_bus_eavesdrop() - send a message to all subscribed monitors
++ * @bus:	The bus the monitors are connected to
++ * @conn_src:	The source connection, may be %NULL for kernel notifications
++ * @staging:	Staging object containing the message to send
++ *
++ * Send message to all monitors that are currently active on the bus. Monitors
++ * must still have matches installed in order to let the message pass.
++ *
++ * The caller must hold the name-registry lock of @bus.
++ */
++void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
++			 struct kdbus_conn *conn_src,
++			 struct kdbus_staging *staging)
++{
++	struct kdbus_conn *conn_dst;
++	int ret;
++
++	/*
++	 * Monitor connections get all messages; ignore possible errors
++	 * when sending messages to monitor connections.
++	 */
++
++	lockdep_assert_held(&bus->name_registry->rwlock);
++
++	down_read(&bus->conn_rwlock);
++	list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) {
++		ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging,
++					      NULL, NULL);
++		if (ret < 0)
++			kdbus_conn_lost_message(conn_dst);
++	}
++	up_read(&bus->conn_rwlock);
++}
++
++/**
++ * kdbus_cmd_bus_make() - handle KDBUS_CMD_BUS_MAKE
++ * @domain:		domain to operate on
++ * @argp:		command payload
++ *
++ * Return: NULL or newly created bus on success, ERR_PTR on failure.
++ */
++struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain,
++				     void __user *argp)
++{
++	struct kdbus_bus *bus = NULL;
++	struct kdbus_cmd *cmd;
++	struct kdbus_ep *ep = NULL;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true },
++		{ .type = KDBUS_ITEM_BLOOM_PARAMETER, .mandatory = true },
++		{ .type = KDBUS_ITEM_ATTACH_FLAGS_SEND },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_MAKE_ACCESS_GROUP |
++				 KDBUS_MAKE_ACCESS_WORLD,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret < 0)
++		return ERR_PTR(ret);
++	if (ret > 0)
++		return NULL;
++
++	bus = kdbus_bus_new(domain,
++			    argv[1].item->str, &argv[2].item->bloom_parameter,
++			    argv[3].item ? argv[3].item->data64 : NULL,
++			    cmd->flags, current_euid(), current_egid());
++	if (IS_ERR(bus)) {
++		ret = PTR_ERR(bus);
++		bus = NULL;
++		goto exit;
++	}
++
++	if (atomic_inc_return(&bus->creator->buses) > KDBUS_USER_MAX_BUSES) {
++		atomic_dec(&bus->creator->buses);
++		ret = -EMFILE;
++		goto exit;
++	}
++
++	if (!kdbus_node_activate(&bus->node)) {
++		atomic_dec(&bus->creator->buses);
++		ret = -ESHUTDOWN;
++		goto exit;
++	}
++
++	ep = kdbus_ep_new(bus, "bus", cmd->flags, bus->node.uid, bus->node.gid,
++			  false);
++	if (IS_ERR(ep)) {
++		ret = PTR_ERR(ep);
++		ep = NULL;
++		goto exit;
++	}
++
++	if (!kdbus_node_activate(&ep->node)) {
++		ret = -ESHUTDOWN;
++		goto exit;
++	}
++
++	/*
++	 * Drop our own reference, effectively causing the endpoint to be
++	 * deactivated and released when the parent bus is.
++	 */
++	ep = kdbus_ep_unref(ep);
++
++exit:
++	ret = kdbus_args_clear(&args, ret);
++	if (ret < 0) {
++		if (ep) {
++			kdbus_node_deactivate(&ep->node);
++			kdbus_ep_unref(ep);
++		}
++		if (bus) {
++			kdbus_node_deactivate(&bus->node);
++			kdbus_bus_unref(bus);
++		}
++		return ERR_PTR(ret);
++	}
++	return bus;
++}
++
++/**
++ * kdbus_cmd_bus_creator_info() - handle KDBUS_CMD_BUS_CREATOR_INFO
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_cmd_info *cmd;
++	struct kdbus_bus *bus = conn->ep->bus;
++	struct kdbus_pool_slice *slice = NULL;
++	struct kdbus_item *meta_items = NULL;
++	struct kdbus_item_header item_hdr;
++	struct kdbus_info info = {};
++	size_t meta_size, name_len, cnt = 0;
++	struct kvec kvec[6];
++	u64 attach_flags, size = 0;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	ret = kdbus_sanitize_attach_flags(cmd->attach_flags, &attach_flags);
++	if (ret < 0)
++		goto exit;
++
++	attach_flags &= bus->attach_flags_owner;
++
++	ret = kdbus_meta_emit(bus->creator_meta, NULL, NULL, conn,
++			      attach_flags, &meta_items, &meta_size);
++	if (ret < 0)
++		goto exit;
++
++	name_len = strlen(bus->node.name) + 1;
++	info.id = bus->id;
++	info.flags = bus->bus_flags;
++	item_hdr.type = KDBUS_ITEM_MAKE_NAME;
++	item_hdr.size = KDBUS_ITEM_HEADER_SIZE + name_len;
++
++	kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size);
++	kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &size);
++	kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &size);
++	cnt += !!kdbus_kvec_pad(&kvec[cnt], &size);
++	if (meta_size > 0) {
++		kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size);
++		cnt += !!kdbus_kvec_pad(&kvec[cnt], &size);
++	}
++
++	info.size = size;
++
++	slice = kdbus_pool_slice_alloc(conn->pool, size, false);
++	if (IS_ERR(slice)) {
++		ret = PTR_ERR(slice);
++		slice = NULL;
++		goto exit;
++	}
++
++	ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size);
++	if (ret < 0)
++		goto exit;
++
++	kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->info_size);
++
++	if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) ||
++	    kdbus_member_set_user(&cmd->info_size, argp,
++				  typeof(*cmd), info_size))
++		ret = -EFAULT;
++
++exit:
++	kdbus_pool_slice_release(slice);
++	kfree(meta_items);
++	return kdbus_args_clear(&args, ret);
++}
+diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h
+new file mode 100644
+index 0000000..8c2acae
+--- /dev/null
++++ b/ipc/kdbus/bus.h
+@@ -0,0 +1,101 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_BUS_H
++#define __KDBUS_BUS_H
++
++#include <linux/hashtable.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/rwsem.h>
++#include <linux/spinlock.h>
++#include <uapi/linux/kdbus.h>
++
++#include "metadata.h"
++#include "names.h"
++#include "node.h"
++#include "policy.h"
++
++struct kdbus_conn;
++struct kdbus_domain;
++struct kdbus_staging;
++struct kdbus_user;
++
++/**
++ * struct kdbus_bus - bus in a domain
++ * @node:		kdbus_node
++ * @id:			ID of this bus in the domain
++ * @bus_flags:		Simple pass-through flags from userspace to userspace
++ * @attach_flags_owner:	KDBUS_ATTACH_* flags of bus creator that other
++ *			connections can see or query
++ * @id128:		Unique random 128 bit ID of this bus
++ * @bloom:		Bloom parameters
++ * @domain:		Domain of this bus
++ * @creator:		Creator of the bus
++ * @creator_meta:	Meta information about the bus creator
++ * @last_message_id:	Last used message id
++ * @policy_db:		Policy database for this bus
++ * @name_registry:	Name registry of this bus
++ * @conn_rwlock:	Read/Write lock for all lists of child connections
++ * @conn_hash:		Map of connection IDs
++ * @monitors_list:	Connections that monitor this bus
++ * @notify_list:	List of pending kernel-generated messages
++ * @notify_lock:	Notification list lock
++ * @notify_flush_lock:	Notification flushing lock
++ */
++struct kdbus_bus {
++	struct kdbus_node node;
++
++	/* static */
++	u64 id;
++	u64 bus_flags;
++	u64 attach_flags_owner;
++	u8 id128[16];
++	struct kdbus_bloom_parameter bloom;
++	struct kdbus_domain *domain;
++	struct kdbus_user *creator;
++	struct kdbus_meta_proc *creator_meta;
++
++	/* protected by own locks */
++	atomic64_t last_message_id;
++	struct kdbus_policy_db policy_db;
++	struct kdbus_name_registry *name_registry;
++
++	/* protected by conn_rwlock */
++	struct rw_semaphore conn_rwlock;
++	DECLARE_HASHTABLE(conn_hash, 8);
++	struct list_head monitors_list;
++
++	/* protected by notify_lock */
++	struct list_head notify_list;
++	spinlock_t notify_lock;
++	struct mutex notify_flush_lock;
++};
++
++struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus);
++struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus);
++
++struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id);
++void kdbus_bus_broadcast(struct kdbus_bus *bus,
++			 struct kdbus_conn *conn_src,
++			 struct kdbus_staging *staging);
++void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
++			 struct kdbus_conn *conn_src,
++			 struct kdbus_staging *staging);
++
++struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain,
++				     void __user *argp);
++int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp);
++
++#endif
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+new file mode 100644
+index 0000000..ef63d65
+--- /dev/null
++++ b/ipc/kdbus/connection.c
+@@ -0,0 +1,2227 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/audit.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/fs_struct.h>
++#include <linux/hashtable.h>
++#include <linux/idr.h>
++#include <linux/init.h>
++#include <linux/math64.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/path.h>
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/shmem_fs.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/syscalls.h>
++#include <linux/uio.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "endpoint.h"
++#include "handle.h"
++#include "match.h"
++#include "message.h"
++#include "metadata.h"
++#include "names.h"
++#include "domain.h"
++#include "item.h"
++#include "notify.h"
++#include "policy.h"
++#include "pool.h"
++#include "reply.h"
++#include "util.h"
++#include "queue.h"
++
++#define KDBUS_CONN_ACTIVE_BIAS	(INT_MIN + 2)
++#define KDBUS_CONN_ACTIVE_NEW	(INT_MIN + 1)
++
++static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
++					 struct file *file,
++					 struct kdbus_cmd_hello *hello,
++					 const char *name,
++					 const struct kdbus_creds *creds,
++					 const struct kdbus_pids *pids,
++					 const char *seclabel,
++					 const char *conn_description)
++{
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	static struct lock_class_key __key;
++#endif
++	struct kdbus_pool_slice *slice = NULL;
++	struct kdbus_bus *bus = ep->bus;
++	struct kdbus_conn *conn;
++	u64 attach_flags_send;
++	u64 attach_flags_recv;
++	u64 items_size = 0;
++	bool is_policy_holder;
++	bool is_activator;
++	bool is_monitor;
++	bool privileged;
++	bool owner;
++	struct kvec kvec;
++	int ret;
++
++	struct {
++		u64 size;
++		u64 type;
++		struct kdbus_bloom_parameter bloom;
++	} bloom_item;
++
++	privileged = kdbus_ep_is_privileged(ep, file);
++	owner = kdbus_ep_is_owner(ep, file);
++
++	is_monitor = hello->flags & KDBUS_HELLO_MONITOR;
++	is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR;
++	is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER;
++
++	if (!hello->pool_size || !IS_ALIGNED(hello->pool_size, PAGE_SIZE))
++		return ERR_PTR(-EINVAL);
++	if (is_monitor + is_activator + is_policy_holder > 1)
++		return ERR_PTR(-EINVAL);
++	if (name && !is_activator && !is_policy_holder)
++		return ERR_PTR(-EINVAL);
++	if (!name && (is_activator || is_policy_holder))
++		return ERR_PTR(-EINVAL);
++	if (name && !kdbus_name_is_valid(name, true))
++		return ERR_PTR(-EINVAL);
++	if (is_monitor && ep->user)
++		return ERR_PTR(-EOPNOTSUPP);
++	if (!owner && (is_activator || is_policy_holder || is_monitor))
++		return ERR_PTR(-EPERM);
++	if (!owner && (creds || pids || seclabel))
++		return ERR_PTR(-EPERM);
++
++	ret = kdbus_sanitize_attach_flags(hello->attach_flags_send,
++					  &attach_flags_send);
++	if (ret < 0)
++		return ERR_PTR(ret);
++
++	ret = kdbus_sanitize_attach_flags(hello->attach_flags_recv,
++					  &attach_flags_recv);
++	if (ret < 0)
++		return ERR_PTR(ret);
++
++	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
++	if (!conn)
++		return ERR_PTR(-ENOMEM);
++
++	kref_init(&conn->kref);
++	atomic_set(&conn->active, KDBUS_CONN_ACTIVE_NEW);
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	lockdep_init_map(&conn->dep_map, "s_active", &__key, 0);
++#endif
++	mutex_init(&conn->lock);
++	INIT_LIST_HEAD(&conn->names_list);
++	INIT_LIST_HEAD(&conn->reply_list);
++	atomic_set(&conn->request_count, 0);
++	atomic_set(&conn->lost_count, 0);
++	INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work);
++	conn->cred = get_cred(file->f_cred);
++	conn->pid = get_pid(task_pid(current));
++	get_fs_root(current->fs, &conn->root_path);
++	init_waitqueue_head(&conn->wait);
++	kdbus_queue_init(&conn->queue);
++	conn->privileged = privileged;
++	conn->owner = owner;
++	conn->ep = kdbus_ep_ref(ep);
++	conn->id = atomic64_inc_return(&bus->domain->last_id);
++	conn->flags = hello->flags;
++	atomic64_set(&conn->attach_flags_send, attach_flags_send);
++	atomic64_set(&conn->attach_flags_recv, attach_flags_recv);
++	INIT_LIST_HEAD(&conn->monitor_entry);
++
++	if (conn_description) {
++		conn->description = kstrdup(conn_description, GFP_KERNEL);
++		if (!conn->description) {
++			ret = -ENOMEM;
++			goto exit_unref;
++		}
++	}
++
++	conn->pool = kdbus_pool_new(conn->description, hello->pool_size);
++	if (IS_ERR(conn->pool)) {
++		ret = PTR_ERR(conn->pool);
++		conn->pool = NULL;
++		goto exit_unref;
++	}
++
++	conn->match_db = kdbus_match_db_new();
++	if (IS_ERR(conn->match_db)) {
++		ret = PTR_ERR(conn->match_db);
++		conn->match_db = NULL;
++		goto exit_unref;
++	}
++
++	/* return properties of this connection to the caller */
++	hello->bus_flags = bus->bus_flags;
++	hello->id = conn->id;
++
++	BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128));
++	memcpy(hello->id128, bus->id128, sizeof(hello->id128));
++
++	/* privileged processes can impersonate somebody else */
++	if (creds || pids || seclabel) {
++		conn->meta_fake = kdbus_meta_fake_new();
++		if (IS_ERR(conn->meta_fake)) {
++			ret = PTR_ERR(conn->meta_fake);
++			conn->meta_fake = NULL;
++			goto exit_unref;
++		}
++
++		ret = kdbus_meta_fake_collect(conn->meta_fake,
++					      creds, pids, seclabel);
++		if (ret < 0)
++			goto exit_unref;
++	} else {
++		conn->meta_proc = kdbus_meta_proc_new();
++		if (IS_ERR(conn->meta_proc)) {
++			ret = PTR_ERR(conn->meta_proc);
++			conn->meta_proc = NULL;
++			goto exit_unref;
++		}
++
++		ret = kdbus_meta_proc_collect(conn->meta_proc,
++					      KDBUS_ATTACH_CREDS |
++					      KDBUS_ATTACH_PIDS |
++					      KDBUS_ATTACH_AUXGROUPS |
++					      KDBUS_ATTACH_TID_COMM |
++					      KDBUS_ATTACH_PID_COMM |
++					      KDBUS_ATTACH_EXE |
++					      KDBUS_ATTACH_CMDLINE |
++					      KDBUS_ATTACH_CGROUP |
++					      KDBUS_ATTACH_CAPS |
++					      KDBUS_ATTACH_SECLABEL |
++					      KDBUS_ATTACH_AUDIT);
++		if (ret < 0)
++			goto exit_unref;
++	}
++
++	/*
++	 * Account the connection against the current user (UID), or for
++	 * custom endpoints use the anonymous user assigned to the endpoint.
++	 * Note that limits are always accounted against the real UID, not
++	 * the effective UID (cred->user always points to the accounting of
++	 * cred->uid, not cred->euid).
++	 * In case the caller is privileged, we allow changing the accounting
++	 * to the faked user.
++	 */
++	if (ep->user) {
++		conn->user = kdbus_user_ref(ep->user);
++	} else {
++		kuid_t uid;
++
++		if (conn->meta_fake && uid_valid(conn->meta_fake->uid) &&
++		    conn->privileged)
++			uid = conn->meta_fake->uid;
++		else
++			uid = conn->cred->uid;
++
++		conn->user = kdbus_user_lookup(ep->bus->domain, uid);
++		if (IS_ERR(conn->user)) {
++			ret = PTR_ERR(conn->user);
++			conn->user = NULL;
++			goto exit_unref;
++		}
++	}
++
++	if (atomic_inc_return(&conn->user->connections) > KDBUS_USER_MAX_CONN) {
++		/* decremented by destructor as conn->user is valid */
++		ret = -EMFILE;
++		goto exit_unref;
++	}
++
++	bloom_item.size = sizeof(bloom_item);
++	bloom_item.type = KDBUS_ITEM_BLOOM_PARAMETER;
++	bloom_item.bloom = bus->bloom;
++	kdbus_kvec_set(&kvec, &bloom_item, bloom_item.size, &items_size);
++
++	slice = kdbus_pool_slice_alloc(conn->pool, items_size, false);
++	if (IS_ERR(slice)) {
++		ret = PTR_ERR(slice);
++		slice = NULL;
++		goto exit_unref;
++	}
++
++	ret = kdbus_pool_slice_copy_kvec(slice, 0, &kvec, 1, items_size);
++	if (ret < 0)
++		goto exit_unref;
++
++	kdbus_pool_slice_publish(slice, &hello->offset, &hello->items_size);
++	kdbus_pool_slice_release(slice);
++
++	return conn;
++
++exit_unref:
++	kdbus_pool_slice_release(slice);
++	kdbus_conn_unref(conn);
++	return ERR_PTR(ret);
++}
++
++static void __kdbus_conn_free(struct kref *kref)
++{
++	struct kdbus_conn *conn = container_of(kref, struct kdbus_conn, kref);
++
++	WARN_ON(kdbus_conn_active(conn));
++	WARN_ON(delayed_work_pending(&conn->work));
++	WARN_ON(!list_empty(&conn->queue.msg_list));
++	WARN_ON(!list_empty(&conn->names_list));
++	WARN_ON(!list_empty(&conn->reply_list));
++
++	if (conn->user) {
++		atomic_dec(&conn->user->connections);
++		kdbus_user_unref(conn->user);
++	}
++
++	kdbus_meta_fake_free(conn->meta_fake);
++	kdbus_meta_proc_unref(conn->meta_proc);
++	kdbus_match_db_free(conn->match_db);
++	kdbus_pool_free(conn->pool);
++	kdbus_ep_unref(conn->ep);
++	path_put(&conn->root_path);
++	put_pid(conn->pid);
++	put_cred(conn->cred);
++	kfree(conn->description);
++	kfree(conn->quota);
++	kfree(conn);
++}
++
++/**
++ * kdbus_conn_ref() - take a connection reference
++ * @conn:		Connection, may be %NULL
++ *
++ * Return: the connection itself
++ */
++struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn)
++{
++	if (conn)
++		kref_get(&conn->kref);
++	return conn;
++}
++
++/**
++ * kdbus_conn_unref() - drop a connection reference
++ * @conn:		Connection (may be NULL)
++ *
++ * When the last reference is dropped, the connection's internal structure
++ * is freed.
++ *
++ * Return: NULL
++ */
++struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn)
++{
++	if (conn)
++		kref_put(&conn->kref, __kdbus_conn_free);
++	return NULL;
++}
++
++/**
++ * kdbus_conn_active() - connection is not disconnected
++ * @conn:		Connection to check
++ *
++ * Return true if the connection was not disconnected, yet. Note that a
++ * connection might be disconnected asynchronously, unless you hold the
++ * connection lock. If that's not suitable for you, see kdbus_conn_acquire() to
++ * suppress connection shutdown for a short period.
++ *
++ * Return: true if the connection is still active
++ */
++bool kdbus_conn_active(const struct kdbus_conn *conn)
++{
++	return atomic_read(&conn->active) >= 0;
++}
++
++/**
++ * kdbus_conn_acquire() - acquire an active connection reference
++ * @conn:		Connection
++ *
++ * Users can close a connection via KDBUS_BYEBYE (or by destroying the
++ * endpoint/bus/...) at any time. Whenever this happens, we should deny any
++ * user-visible action on this connection and signal ECONNRESET instead.
++ * To avoid testing for connection availability everytime you take the
++ * connection-lock, you can acquire a connection for short periods.
++ *
++ * By calling kdbus_conn_acquire(), you gain an "active reference" to the
++ * connection. You must also hold a regular reference at any time! As long as
++ * you hold the active-ref, the connection will not be shut down. However, if
++ * the connection was shut down, you can never acquire an active-ref again.
++ *
++ * kdbus_conn_disconnect() disables the connection and then waits for all active
++ * references to be dropped. It will also wake up any pending operation.
++ * However, you must not sleep for an indefinite period while holding an
++ * active-reference. Otherwise, kdbus_conn_disconnect() might stall. If you need
++ * to sleep for an indefinite period, either release the reference and try to
++ * acquire it again after waking up, or make kdbus_conn_disconnect() wake up
++ * your wait-queue.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_conn_acquire(struct kdbus_conn *conn)
++{
++	if (!atomic_inc_unless_negative(&conn->active))
++		return -ECONNRESET;
++
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	rwsem_acquire_read(&conn->dep_map, 0, 1, _RET_IP_);
++#endif
++
++	return 0;
++}
++
++/**
++ * kdbus_conn_release() - release an active connection reference
++ * @conn:		Connection
++ *
++ * This releases an active reference that has been acquired via
++ * kdbus_conn_acquire(). If the connection was already disabled and this is the
++ * last active-ref that is dropped, the disconnect-waiter will be woken up and
++ * properly close the connection.
++ */
++void kdbus_conn_release(struct kdbus_conn *conn)
++{
++	int v;
++
++	if (!conn)
++		return;
++
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	rwsem_release(&conn->dep_map, 1, _RET_IP_);
++#endif
++
++	v = atomic_dec_return(&conn->active);
++	if (v != KDBUS_CONN_ACTIVE_BIAS)
++		return;
++
++	wake_up_all(&conn->wait);
++}
++
++static int kdbus_conn_connect(struct kdbus_conn *conn, const char *name)
++{
++	struct kdbus_ep *ep = conn->ep;
++	struct kdbus_bus *bus = ep->bus;
++	int ret;
++
++	if (WARN_ON(atomic_read(&conn->active) != KDBUS_CONN_ACTIVE_NEW))
++		return -EALREADY;
++
++	/* make sure the ep-node is active while we add our connection */
++	if (!kdbus_node_acquire(&ep->node))
++		return -ESHUTDOWN;
++
++	/* lock order: domain -> bus -> ep -> names -> conn */
++	mutex_lock(&ep->lock);
++	down_write(&bus->conn_rwlock);
++
++	/* link into monitor list */
++	if (kdbus_conn_is_monitor(conn))
++		list_add_tail(&conn->monitor_entry, &bus->monitors_list);
++
++	/* link into bus and endpoint */
++	list_add_tail(&conn->ep_entry, &ep->conn_list);
++	hash_add(bus->conn_hash, &conn->hentry, conn->id);
++
++	/* enable lookups and acquire active ref */
++	atomic_set(&conn->active, 1);
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	rwsem_acquire_read(&conn->dep_map, 0, 1, _RET_IP_);
++#endif
++
++	up_write(&bus->conn_rwlock);
++	mutex_unlock(&ep->lock);
++
++	kdbus_node_release(&ep->node);
++
++	/*
++	 * Notify subscribers about the new active connection, unless it is
++	 * a monitor. Monitors are invisible on the bus, can't be addressed
++	 * directly, and won't cause any notifications.
++	 */
++	if (!kdbus_conn_is_monitor(conn)) {
++		ret = kdbus_notify_id_change(bus, KDBUS_ITEM_ID_ADD,
++					     conn->id, conn->flags);
++		if (ret < 0)
++			goto exit_disconnect;
++	}
++
++	if (kdbus_conn_is_activator(conn)) {
++		u64 flags = KDBUS_NAME_ACTIVATOR;
++
++		if (WARN_ON(!name)) {
++			ret = -EINVAL;
++			goto exit_disconnect;
++		}
++
++		ret = kdbus_name_acquire(bus->name_registry, conn, name,
++					 flags, NULL);
++		if (ret < 0)
++			goto exit_disconnect;
++	}
++
++	kdbus_conn_release(conn);
++	kdbus_notify_flush(bus);
++	return 0;
++
++exit_disconnect:
++	kdbus_conn_release(conn);
++	kdbus_conn_disconnect(conn, false);
++	return ret;
++}
++
++/**
++ * kdbus_conn_disconnect() - disconnect a connection
++ * @conn:		The connection to disconnect
++ * @ensure_queue_empty:	Flag to indicate if the call should fail in
++ *			case the connection's message list is not
++ *			empty
++ *
++ * If @ensure_msg_list_empty is true, and the connection has pending messages,
++ * -EBUSY is returned.
++ *
++ * Return: 0 on success, negative errno on failure
++ */
++int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty)
++{
++	struct kdbus_queue_entry *entry, *tmp;
++	struct kdbus_bus *bus = conn->ep->bus;
++	struct kdbus_reply *r, *r_tmp;
++	struct kdbus_conn *c;
++	int i, v;
++
++	mutex_lock(&conn->lock);
++	v = atomic_read(&conn->active);
++	if (v == KDBUS_CONN_ACTIVE_NEW) {
++		/* was never connected */
++		mutex_unlock(&conn->lock);
++		return 0;
++	}
++	if (v < 0) {
++		/* already dead */
++		mutex_unlock(&conn->lock);
++		return -ECONNRESET;
++	}
++	if (ensure_queue_empty && !list_empty(&conn->queue.msg_list)) {
++		/* still busy */
++		mutex_unlock(&conn->lock);
++		return -EBUSY;
++	}
++
++	atomic_add(KDBUS_CONN_ACTIVE_BIAS, &conn->active);
++	mutex_unlock(&conn->lock);
++
++	wake_up_interruptible(&conn->wait);
++
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	rwsem_acquire(&conn->dep_map, 0, 0, _RET_IP_);
++	if (atomic_read(&conn->active) != KDBUS_CONN_ACTIVE_BIAS)
++		lock_contended(&conn->dep_map, _RET_IP_);
++#endif
++
++	wait_event(conn->wait,
++		   atomic_read(&conn->active) == KDBUS_CONN_ACTIVE_BIAS);
++
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	lock_acquired(&conn->dep_map, _RET_IP_);
++	rwsem_release(&conn->dep_map, 1, _RET_IP_);
++#endif
++
++	cancel_delayed_work_sync(&conn->work);
++	kdbus_policy_remove_owner(&conn->ep->bus->policy_db, conn);
++
++	/* lock order: domain -> bus -> ep -> names -> conn */
++	mutex_lock(&conn->ep->lock);
++	down_write(&bus->conn_rwlock);
++
++	/* remove from bus and endpoint */
++	hash_del(&conn->hentry);
++	list_del(&conn->monitor_entry);
++	list_del(&conn->ep_entry);
++
++	up_write(&bus->conn_rwlock);
++	mutex_unlock(&conn->ep->lock);
++
++	/*
++	 * Remove all names associated with this connection; this possibly
++	 * moves queued messages back to the activator connection.
++	 */
++	kdbus_name_release_all(bus->name_registry, conn);
++
++	/* if we die while other connections wait for our reply, notify them */
++	mutex_lock(&conn->lock);
++	list_for_each_entry_safe(entry, tmp, &conn->queue.msg_list, entry) {
++		if (entry->reply)
++			kdbus_notify_reply_dead(bus,
++						entry->reply->reply_dst->id,
++						entry->reply->cookie);
++		kdbus_queue_entry_free(entry);
++	}
++
++	list_for_each_entry_safe(r, r_tmp, &conn->reply_list, entry)
++		kdbus_reply_unlink(r);
++	mutex_unlock(&conn->lock);
++
++	/* lock order: domain -> bus -> ep -> names -> conn */
++	down_read(&bus->conn_rwlock);
++	hash_for_each(bus->conn_hash, i, c, hentry) {
++		mutex_lock(&c->lock);
++		list_for_each_entry_safe(r, r_tmp, &c->reply_list, entry) {
++			if (r->reply_src != conn)
++				continue;
++
++			if (r->sync)
++				kdbus_sync_reply_wakeup(r, -EPIPE);
++			else
++				/* send a 'connection dead' notification */
++				kdbus_notify_reply_dead(bus, c->id, r->cookie);
++
++			kdbus_reply_unlink(r);
++		}
++		mutex_unlock(&c->lock);
++	}
++	up_read(&bus->conn_rwlock);
++
++	if (!kdbus_conn_is_monitor(conn))
++		kdbus_notify_id_change(bus, KDBUS_ITEM_ID_REMOVE,
++				       conn->id, conn->flags);
++
++	kdbus_notify_flush(bus);
++
++	return 0;
++}
++
++/**
++ * kdbus_conn_has_name() - check if a connection owns a name
++ * @conn:		Connection
++ * @name:		Well-know name to check for
++ *
++ * The caller must hold the registry lock of conn->ep->bus.
++ *
++ * Return: true if the name is currently owned by the connection
++ */
++bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name)
++{
++	struct kdbus_name_owner *owner;
++
++	lockdep_assert_held(&conn->ep->bus->name_registry->rwlock);
++
++	list_for_each_entry(owner, &conn->names_list, conn_entry)
++		if (!(owner->flags & KDBUS_NAME_IN_QUEUE) &&
++		    !strcmp(name, owner->name->name))
++			return true;
++
++	return false;
++}
++
++struct kdbus_quota {
++	u32 memory;
++	u16 msgs;
++	u8 fds;
++};
++
++/**
++ * kdbus_conn_quota_inc() - increase quota accounting
++ * @c:		connection owning the quota tracking
++ * @u:		user to account for (or NULL for kernel accounting)
++ * @memory:	size of memory to account for
++ * @fds:	number of FDs to account for
++ *
++ * This call manages the quotas on resource @c. That is, it's used if other
++ * users want to use the resources of connection @c, which so far only concerns
++ * the receive queue of the destination.
++ *
++ * This increases the quota-accounting for user @u by @memory bytes and @fds
++ * file descriptors. If the user has already reached the quota limits, this call
++ * will not do any accounting but return a negative error code indicating the
++ * failure.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u,
++			 size_t memory, size_t fds)
++{
++	struct kdbus_quota *quota;
++	size_t available, accounted;
++	unsigned int id;
++
++	/*
++	 * Pool Layout:
++	 * 50% of a pool is always owned by the connection. It is reserved for
++	 * kernel queries, handling received messages and other tasks that are
++	 * under control of the pool owner. The other 50% of the pool are used
++	 * as incoming queue.
++	 * As we optionally support user-space based policies, we need fair
++	 * allocation schemes. Furthermore, resource utilization should be
++	 * maximized, so only minimal resources stay reserved. However, we need
++	 * to adapt to a dynamic number of users, as we cannot know how many
++	 * users will talk to a connection. Therefore, the current allocation
++	 * works like this:
++	 * We limit the number of bytes in a destination's pool per sending
++	 * user. The space available for a user is 33% of the unused pool space
++	 * (whereas the space used by the user itself is also treated as
++	 * 'unused'). This way, we favor users coming first, but keep enough
++	 * pool space available for any following users. Given that messages are
++	 * dequeued in FIFO order, this should balance nicely if the number of
++	 * users grows. At the same time, this algorithm guarantees that the
++	 * space available to a connection is reduced dynamically, the more
++	 * concurrent users talk to a connection.
++	 */
++
++	/* per user-accounting is expensive, so we keep state small */
++	BUILD_BUG_ON(sizeof(quota->memory) != 4);
++	BUILD_BUG_ON(sizeof(quota->msgs) != 2);
++	BUILD_BUG_ON(sizeof(quota->fds) != 1);
++	BUILD_BUG_ON(KDBUS_CONN_MAX_MSGS > U16_MAX);
++	BUILD_BUG_ON(KDBUS_CONN_MAX_FDS_PER_USER > U8_MAX);
++
++	id = u ? u->id : KDBUS_USER_KERNEL_ID;
++	if (id >= c->n_quota) {
++		unsigned int users;
++
++		users = max(KDBUS_ALIGN8(id) + 8, id);
++		quota = krealloc(c->quota, users * sizeof(*quota),
++				 GFP_KERNEL | __GFP_ZERO);
++		if (!quota)
++			return -ENOMEM;
++
++		c->n_quota = users;
++		c->quota = quota;
++	}
++
++	quota = &c->quota[id];
++	kdbus_pool_accounted(c->pool, &available, &accounted);
++
++	/* half the pool is _always_ reserved for the pool owner */
++	available /= 2;
++
++	/*
++	 * Pool owner slices are un-accounted slices; they can claim more
++	 * than 50% of the queue. However, the slices we're dealing with here
++	 * belong to the incoming queue, hence they are 'accounted' slices
++	 * to which the 50%-limit applies.
++	 */
++	if (available < accounted)
++		return -ENOBUFS;
++
++	/* 1/3 of the remaining space (including your own memory) */
++	available = (available - accounted + quota->memory) / 3;
++
++	if (available < quota->memory ||
++	    available - quota->memory < memory ||
++	    quota->memory + memory > U32_MAX)
++		return -ENOBUFS;
++	if (quota->msgs >= KDBUS_CONN_MAX_MSGS)
++		return -ENOBUFS;
++	if (quota->fds + fds < quota->fds ||
++	    quota->fds + fds > KDBUS_CONN_MAX_FDS_PER_USER)
++		return -EMFILE;
++
++	quota->memory += memory;
++	quota->fds += fds;
++	++quota->msgs;
++	return 0;
++}
++
++/**
++ * kdbus_conn_quota_dec() - decrease quota accounting
++ * @c:		connection owning the quota tracking
++ * @u:		user which was accounted for (or NULL for kernel accounting)
++ * @memory:	size of memory which was accounted for
++ * @fds:	number of FDs which were accounted for
++ *
++ * This does the reverse of kdbus_conn_quota_inc(). You have to release any
++ * accounted resources that you called kdbus_conn_quota_inc() for. However, you
++ * must not call kdbus_conn_quota_dec() if the accounting failed (that is,
++ * kdbus_conn_quota_inc() failed).
++ */
++void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u,
++			  size_t memory, size_t fds)
++{
++	struct kdbus_quota *quota;
++	unsigned int id;
++
++	id = u ? u->id : KDBUS_USER_KERNEL_ID;
++	if (WARN_ON(id >= c->n_quota))
++		return;
++
++	quota = &c->quota[id];
++
++	if (!WARN_ON(quota->msgs == 0))
++		--quota->msgs;
++	if (!WARN_ON(quota->memory < memory))
++		quota->memory -= memory;
++	if (!WARN_ON(quota->fds < fds))
++		quota->fds -= fds;
++}
++
++/**
++ * kdbus_conn_lost_message() - handle lost messages
++ * @c:		connection that lost a message
++ *
++ * kdbus is reliable. That means, we try hard to never lose messages. However,
++ * memory is limited, so we cannot rely on transmissions to never fail.
++ * Therefore, we use quota-limits to let callers know if their unicast message
++ * cannot be transmitted to a peer. This works fine for unicasts, but for
++ * broadcasts we cannot make the caller handle the transmission failure.
++ * Instead, we must let the destination know that it couldn't receive a
++ * broadcast.
++ * As this is an unlikely scenario, we keep it simple. A single lost-counter
++ * remembers the number of lost messages since the last call to RECV. The next
++ * message retrieval will notify the connection that it lost messages since the
++ * last message retrieval and thus should resync its state.
++ */
++void kdbus_conn_lost_message(struct kdbus_conn *c)
++{
++	if (atomic_inc_return(&c->lost_count) == 1)
++		wake_up_interruptible(&c->wait);
++}
++
++/* Callers should take the conn_dst lock */
++static struct kdbus_queue_entry *
++kdbus_conn_entry_make(struct kdbus_conn *conn_src,
++		      struct kdbus_conn *conn_dst,
++		      struct kdbus_staging *staging)
++{
++	/* The remote connection was disconnected */
++	if (!kdbus_conn_active(conn_dst))
++		return ERR_PTR(-ECONNRESET);
++
++	/*
++	 * If the connection does not accept file descriptors but the message
++	 * has some attached, refuse it.
++	 *
++	 * If this is a monitor connection, accept the message. In that
++	 * case, all file descriptors will be set to -1 at receive time.
++	 */
++	if (!kdbus_conn_is_monitor(conn_dst) &&
++	    !(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) &&
++	    staging->gaps && staging->gaps->n_fds > 0)
++		return ERR_PTR(-ECOMM);
++
++	return kdbus_queue_entry_new(conn_src, conn_dst, staging);
++}
++
++/*
++ * Synchronously responding to a message, allocate a queue entry
++ * and attach it to the reply tracking object.
++ * The connection's queue will never get to see it.
++ */
++static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
++					struct kdbus_staging *staging,
++					struct kdbus_reply *reply_wake)
++{
++	struct kdbus_queue_entry *entry;
++	int remote_ret, ret = 0;
++
++	mutex_lock(&reply_wake->reply_dst->lock);
++
++	/*
++	 * If we are still waiting then proceed, allocate a queue
++	 * entry and attach it to the reply object
++	 */
++	if (reply_wake->waiting) {
++		entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst,
++					      staging);
++		if (IS_ERR(entry))
++			ret = PTR_ERR(entry);
++		else
++			/* Attach the entry to the reply object */
++			reply_wake->queue_entry = entry;
++	} else {
++		ret = -ECONNRESET;
++	}
++
++	/*
++	 * Update the reply object and wake up remote peer only
++	 * on appropriate return codes
++	 *
++	 * * -ECOMM: if the replying connection failed with -ECOMM
++	 *           then wakeup remote peer with -EREMOTEIO
++	 *
++	 *           We do this to differenciate between -ECOMM errors
++	 *           from the original sender perspective:
++	 *           -ECOMM error during the sync send and
++	 *           -ECOMM error during the sync reply, this last
++	 *           one is rewritten to -EREMOTEIO
++	 *
++	 * * Wake up on all other return codes.
++	 */
++	remote_ret = ret;
++
++	if (ret == -ECOMM)
++		remote_ret = -EREMOTEIO;
++
++	kdbus_sync_reply_wakeup(reply_wake, remote_ret);
++	kdbus_reply_unlink(reply_wake);
++	mutex_unlock(&reply_wake->reply_dst->lock);
++
++	return ret;
++}
++
++/**
++ * kdbus_conn_entry_insert() - enqueue a message into the receiver's pool
++ * @conn_src:		The sending connection
++ * @conn_dst:		The connection to queue into
++ * @staging:		Message to send
++ * @reply:		The reply tracker to attach to the queue entry
++ * @name:		Destination name this msg is sent to, or NULL
++ *
++ * Return: 0 on success. negative error otherwise.
++ */
++int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
++			    struct kdbus_conn *conn_dst,
++			    struct kdbus_staging *staging,
++			    struct kdbus_reply *reply,
++			    const struct kdbus_name_entry *name)
++{
++	struct kdbus_queue_entry *entry;
++	int ret;
++
++	kdbus_conn_lock2(conn_src, conn_dst);
++
++	entry = kdbus_conn_entry_make(conn_src, conn_dst, staging);
++	if (IS_ERR(entry)) {
++		ret = PTR_ERR(entry);
++		goto exit_unlock;
++	}
++
++	if (reply) {
++		kdbus_reply_link(reply);
++		if (!reply->sync)
++			schedule_delayed_work(&conn_src->work, 0);
++	}
++
++	/*
++	 * Record the sequence number of the registered name; it will
++	 * be remembered by the queue, in case messages addressed to a
++	 * name need to be moved from or to an activator.
++	 */
++	if (name)
++		entry->dst_name_id = name->name_id;
++
++	kdbus_queue_entry_enqueue(entry, reply);
++	wake_up_interruptible(&conn_dst->wait);
++
++	ret = 0;
++
++exit_unlock:
++	kdbus_conn_unlock2(conn_src, conn_dst);
++	return ret;
++}
++
++static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src,
++				 struct kdbus_cmd_send *cmd_send,
++				 struct file *ioctl_file,
++				 struct file *cancel_fd,
++				 struct kdbus_reply *reply_wait,
++				 ktime_t expire)
++{
++	struct kdbus_queue_entry *entry;
++	struct poll_wqueues pwq = {};
++	int ret;
++
++	if (WARN_ON(!reply_wait))
++		return -EIO;
++
++	/*
++	 * Block until the reply arrives. reply_wait is left untouched
++	 * by the timeout scans that might be conducted for other,
++	 * asynchronous replies of conn_src.
++	 */
++
++	poll_initwait(&pwq);
++	poll_wait(ioctl_file, &conn_src->wait, &pwq.pt);
++
++	for (;;) {
++		/*
++		 * Any of the following conditions will stop our synchronously
++		 * blocking SEND command:
++		 *
++		 * a) The origin sender closed its connection
++		 * b) The remote peer answered, setting reply_wait->waiting = 0
++		 * c) The cancel FD was written to
++		 * d) A signal was received
++		 * e) The specified timeout was reached, and none of the above
++		 *    conditions kicked in.
++		 */
++
++		/*
++		 * We have already acquired an active reference when
++		 * entering here, but another thread may call
++		 * KDBUS_CMD_BYEBYE which does not acquire an active
++		 * reference, therefore kdbus_conn_disconnect() will
++		 * not wait for us.
++		 */
++		if (!kdbus_conn_active(conn_src)) {
++			ret = -ECONNRESET;
++			break;
++		}
++
++		/*
++		 * After the replying peer unset the waiting variable
++		 * it will wake up us.
++		 */
++		if (!reply_wait->waiting) {
++			ret = reply_wait->err;
++			break;
++		}
++
++		if (cancel_fd) {
++			unsigned int r;
++
++			r = cancel_fd->f_op->poll(cancel_fd, &pwq.pt);
++			if (r & POLLIN) {
++				ret = -ECANCELED;
++				break;
++			}
++		}
++
++		if (signal_pending(current)) {
++			ret = -EINTR;
++			break;
++		}
++
++		if (!poll_schedule_timeout(&pwq, TASK_INTERRUPTIBLE,
++					   &expire, 0)) {
++			ret = -ETIMEDOUT;
++			break;
++		}
++
++		/*
++		 * Reset the poll worker func, so the waitqueues are not
++		 * added to the poll table again. We just reuse what we've
++		 * collected earlier for further iterations.
++		 */
++		init_poll_funcptr(&pwq.pt, NULL);
++	}
++
++	poll_freewait(&pwq);
++
++	if (ret == -EINTR) {
++		/*
++		 * Interrupted system call. Unref the reply object, and pass
++		 * the return value down the chain. Mark the reply as
++		 * interrupted, so the cleanup work can remove it, but do not
++		 * unlink it from the list. Once the syscall restarts, we'll
++		 * pick it up and wait on it again.
++		 */
++		mutex_lock(&conn_src->lock);
++		reply_wait->interrupted = true;
++		schedule_delayed_work(&conn_src->work, 0);
++		mutex_unlock(&conn_src->lock);
++
++		return -ERESTARTSYS;
++	}
++
++	mutex_lock(&conn_src->lock);
++	reply_wait->waiting = false;
++	entry = reply_wait->queue_entry;
++	if (entry) {
++		ret = kdbus_queue_entry_install(entry,
++						&cmd_send->reply.return_flags,
++						true);
++		kdbus_pool_slice_publish(entry->slice, &cmd_send->reply.offset,
++					 &cmd_send->reply.msg_size);
++		kdbus_queue_entry_free(entry);
++	}
++	kdbus_reply_unlink(reply_wait);
++	mutex_unlock(&conn_src->lock);
++
++	return ret;
++}
++
++static int kdbus_pin_dst(struct kdbus_bus *bus,
++			 struct kdbus_staging *staging,
++			 struct kdbus_name_entry **out_name,
++			 struct kdbus_conn **out_dst)
++{
++	const struct kdbus_msg *msg = staging->msg;
++	struct kdbus_name_owner *owner = NULL;
++	struct kdbus_name_entry *name = NULL;
++	struct kdbus_conn *dst = NULL;
++	int ret;
++
++	lockdep_assert_held(&bus->name_registry->rwlock);
++
++	if (!staging->dst_name) {
++		dst = kdbus_bus_find_conn_by_id(bus, msg->dst_id);
++		if (!dst)
++			return -ENXIO;
++
++		if (!kdbus_conn_is_ordinary(dst)) {
++			ret = -ENXIO;
++			goto error;
++		}
++	} else {
++		name = kdbus_name_lookup_unlocked(bus->name_registry,
++						  staging->dst_name);
++		if (name)
++			owner = kdbus_name_get_owner(name);
++		if (!owner)
++			return -ESRCH;
++
++		/*
++		 * If both a name and a connection ID are given as destination
++		 * of a message, check that the currently owning connection of
++		 * the name matches the specified ID.
++		 * This way, we allow userspace to send the message to a
++		 * specific connection by ID only if the connection currently
++		 * owns the given name.
++		 */
++		if (msg->dst_id != KDBUS_DST_ID_NAME &&
++		    msg->dst_id != owner->conn->id)
++			return -EREMCHG;
++
++		if ((msg->flags & KDBUS_MSG_NO_AUTO_START) &&
++		    kdbus_conn_is_activator(owner->conn))
++			return -EADDRNOTAVAIL;
++
++		dst = kdbus_conn_ref(owner->conn);
++	}
++
++	*out_name = name;
++	*out_dst = dst;
++	return 0;
++
++error:
++	kdbus_conn_unref(dst);
++	return ret;
++}
++
++static int kdbus_conn_reply(struct kdbus_conn *src,
++			    struct kdbus_staging *staging)
++{
++	const struct kdbus_msg *msg = staging->msg;
++	struct kdbus_name_entry *name = NULL;
++	struct kdbus_reply *reply, *wake = NULL;
++	struct kdbus_conn *dst = NULL;
++	struct kdbus_bus *bus = src->ep->bus;
++	int ret;
++
++	if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) ||
++	    WARN_ON(msg->flags & KDBUS_MSG_EXPECT_REPLY) ||
++	    WARN_ON(msg->flags & KDBUS_MSG_SIGNAL))
++		return -EINVAL;
++
++	/* name-registry must be locked for lookup *and* collecting data */
++	down_read(&bus->name_registry->rwlock);
++
++	/* find and pin destination */
++
++	ret = kdbus_pin_dst(bus, staging, &name, &dst);
++	if (ret < 0)
++		goto exit;
++
++	mutex_lock(&dst->lock);
++	reply = kdbus_reply_find(src, dst, msg->cookie_reply);
++	if (reply) {
++		if (reply->sync)
++			wake = kdbus_reply_ref(reply);
++		kdbus_reply_unlink(reply);
++	}
++	mutex_unlock(&dst->lock);
++
++	if (!reply) {
++		ret = -EBADSLT;
++		goto exit;
++	}
++
++	/* send message */
++
++	kdbus_bus_eavesdrop(bus, src, staging);
++
++	if (wake)
++		ret = kdbus_conn_entry_sync_attach(dst, staging, wake);
++	else
++		ret = kdbus_conn_entry_insert(src, dst, staging, NULL, name);
++
++exit:
++	up_read(&bus->name_registry->rwlock);
++	kdbus_reply_unref(wake);
++	kdbus_conn_unref(dst);
++	return ret;
++}
++
++static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
++					   struct kdbus_staging *staging,
++					   ktime_t exp)
++{
++	const struct kdbus_msg *msg = staging->msg;
++	struct kdbus_name_entry *name = NULL;
++	struct kdbus_reply *wait = NULL;
++	struct kdbus_conn *dst = NULL;
++	struct kdbus_bus *bus = src->ep->bus;
++	int ret;
++
++	if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) ||
++	    WARN_ON(msg->flags & KDBUS_MSG_SIGNAL) ||
++	    WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY)))
++		return ERR_PTR(-EINVAL);
++
++	/* resume previous wait-context, if available */
++
++	mutex_lock(&src->lock);
++	wait = kdbus_reply_find(NULL, src, msg->cookie);
++	if (wait) {
++		if (wait->interrupted) {
++			kdbus_reply_ref(wait);
++			wait->interrupted = false;
++		} else {
++			wait = NULL;
++		}
++	}
++	mutex_unlock(&src->lock);
++
++	if (wait)
++		return wait;
++
++	if (ktime_compare(ktime_get(), exp) >= 0)
++		return ERR_PTR(-ETIMEDOUT);
++
++	/* name-registry must be locked for lookup *and* collecting data */
++	down_read(&bus->name_registry->rwlock);
++
++	/* find and pin destination */
++
++	ret = kdbus_pin_dst(bus, staging, &name, &dst);
++	if (ret < 0)
++		goto exit;
++
++	if (!kdbus_conn_policy_talk(src, current_cred(), dst)) {
++		ret = -EPERM;
++		goto exit;
++	}
++
++	wait = kdbus_reply_new(dst, src, msg, name, true);
++	if (IS_ERR(wait)) {
++		ret = PTR_ERR(wait);
++		wait = NULL;
++		goto exit;
++	}
++
++	/* send message */
++
++	kdbus_bus_eavesdrop(bus, src, staging);
++
++	ret = kdbus_conn_entry_insert(src, dst, staging, wait, name);
++	if (ret < 0)
++		goto exit;
++
++	ret = 0;
++
++exit:
++	up_read(&bus->name_registry->rwlock);
++	if (ret < 0) {
++		kdbus_reply_unref(wait);
++		wait = ERR_PTR(ret);
++	}
++	kdbus_conn_unref(dst);
++	return wait;
++}
++
++static int kdbus_conn_unicast(struct kdbus_conn *src,
++			      struct kdbus_staging *staging)
++{
++	const struct kdbus_msg *msg = staging->msg;
++	struct kdbus_name_entry *name = NULL;
++	struct kdbus_reply *wait = NULL;
++	struct kdbus_conn *dst = NULL;
++	struct kdbus_bus *bus = src->ep->bus;
++	bool is_signal = (msg->flags & KDBUS_MSG_SIGNAL);
++	int ret = 0;
++
++	if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) ||
++	    WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY) &&
++		    msg->cookie_reply != 0))
++		return -EINVAL;
++
++	/* name-registry must be locked for lookup *and* collecting data */
++	down_read(&bus->name_registry->rwlock);
++
++	/* find and pin destination */
++
++	ret = kdbus_pin_dst(bus, staging, &name, &dst);
++	if (ret < 0)
++		goto exit;
++
++	if (is_signal) {
++		/* like broadcasts we eavesdrop even if the msg is dropped */
++		kdbus_bus_eavesdrop(bus, src, staging);
++
++		/* drop silently if peer is not interested or not privileged */
++		if (!kdbus_match_db_match_msg(dst->match_db, src, staging) ||
++		    !kdbus_conn_policy_talk(dst, NULL, src))
++			goto exit;
++	} else if (!kdbus_conn_policy_talk(src, current_cred(), dst)) {
++		ret = -EPERM;
++		goto exit;
++	} else if (msg->flags & KDBUS_MSG_EXPECT_REPLY) {
++		wait = kdbus_reply_new(dst, src, msg, name, false);
++		if (IS_ERR(wait)) {
++			ret = PTR_ERR(wait);
++			wait = NULL;
++			goto exit;
++		}
++	}
++
++	/* send message */
++
++	if (!is_signal)
++		kdbus_bus_eavesdrop(bus, src, staging);
++
++	ret = kdbus_conn_entry_insert(src, dst, staging, wait, name);
++	if (ret < 0 && !is_signal)
++		goto exit;
++
++	/* signals are treated like broadcasts, recv-errors are ignored */
++	ret = 0;
++
++exit:
++	up_read(&bus->name_registry->rwlock);
++	kdbus_reply_unref(wait);
++	kdbus_conn_unref(dst);
++	return ret;
++}
++
++/**
++ * kdbus_conn_move_messages() - move messages from one connection to another
++ * @conn_dst:		Connection to copy to
++ * @conn_src:		Connection to copy from
++ * @name_id:		Filter for the sequence number of the registered
++ *			name, 0 means no filtering.
++ *
++ * Move all messages from one connection to another. This is used when
++ * an implementer connection is taking over/giving back a well-known name
++ * from/to an activator connection.
++ */
++void kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
++			      struct kdbus_conn *conn_src,
++			      u64 name_id)
++{
++	struct kdbus_queue_entry *e, *e_tmp;
++	struct kdbus_reply *r, *r_tmp;
++	struct kdbus_bus *bus;
++	struct kdbus_conn *c;
++	LIST_HEAD(msg_list);
++	int i, ret = 0;
++
++	if (WARN_ON(conn_src == conn_dst))
++		return;
++
++	bus = conn_src->ep->bus;
++
++	/* lock order: domain -> bus -> ep -> names -> conn */
++	down_read(&bus->conn_rwlock);
++	hash_for_each(bus->conn_hash, i, c, hentry) {
++		if (c == conn_src || c == conn_dst)
++			continue;
++
++		mutex_lock(&c->lock);
++		list_for_each_entry_safe(r, r_tmp, &c->reply_list, entry) {
++			if (r->reply_src != conn_src)
++				continue;
++
++			/* filter messages for a specific name */
++			if (name_id > 0 && r->name_id != name_id)
++				continue;
++
++			kdbus_conn_unref(r->reply_src);
++			r->reply_src = kdbus_conn_ref(conn_dst);
++		}
++		mutex_unlock(&c->lock);
++	}
++	up_read(&bus->conn_rwlock);
++
++	kdbus_conn_lock2(conn_src, conn_dst);
++	list_for_each_entry_safe(e, e_tmp, &conn_src->queue.msg_list, entry) {
++		/* filter messages for a specific name */
++		if (name_id > 0 && e->dst_name_id != name_id)
++			continue;
++
++		if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) &&
++		    e->gaps && e->gaps->n_fds > 0) {
++			kdbus_conn_lost_message(conn_dst);
++			kdbus_queue_entry_free(e);
++			continue;
++		}
++
++		ret = kdbus_queue_entry_move(e, conn_dst);
++		if (ret < 0) {
++			kdbus_conn_lost_message(conn_dst);
++			kdbus_queue_entry_free(e);
++			continue;
++		}
++	}
++	kdbus_conn_unlock2(conn_src, conn_dst);
++
++	/* wake up poll() */
++	wake_up_interruptible(&conn_dst->wait);
++}
++
++/* query the policy-database for all names of @whom */
++static bool kdbus_conn_policy_query_all(struct kdbus_conn *conn,
++					const struct cred *conn_creds,
++					struct kdbus_policy_db *db,
++					struct kdbus_conn *whom,
++					unsigned int access)
++{
++	struct kdbus_name_owner *owner;
++	bool pass = false;
++	int res;
++
++	lockdep_assert_held(&conn->ep->bus->name_registry->rwlock);
++
++	down_read(&db->entries_rwlock);
++	mutex_lock(&whom->lock);
++
++	list_for_each_entry(owner, &whom->names_list, conn_entry) {
++		if (owner->flags & KDBUS_NAME_IN_QUEUE)
++			continue;
++
++		res = kdbus_policy_query_unlocked(db,
++					conn_creds ? : conn->cred,
++					owner->name->name,
++					kdbus_strhash(owner->name->name));
++		if (res >= (int)access) {
++			pass = true;
++			break;
++		}
++	}
++
++	mutex_unlock(&whom->lock);
++	up_read(&db->entries_rwlock);
++
++	return pass;
++}
++
++/**
++ * kdbus_conn_policy_own_name() - verify a connection can own the given name
++ * @conn:		Connection
++ * @conn_creds:		Credentials of @conn to use for policy check
++ * @name:		Name
++ *
++ * This verifies that @conn is allowed to acquire the well-known name @name.
++ *
++ * Return: true if allowed, false if not.
++ */
++bool kdbus_conn_policy_own_name(struct kdbus_conn *conn,
++				const struct cred *conn_creds,
++				const char *name)
++{
++	unsigned int hash = kdbus_strhash(name);
++	int res;
++
++	if (!conn_creds)
++		conn_creds = conn->cred;
++
++	if (conn->ep->user) {
++		res = kdbus_policy_query(&conn->ep->policy_db, conn_creds,
++					 name, hash);
++		if (res < KDBUS_POLICY_OWN)
++			return false;
++	}
++
++	if (conn->owner)
++		return true;
++
++	res = kdbus_policy_query(&conn->ep->bus->policy_db, conn_creds,
++				 name, hash);
++	return res >= KDBUS_POLICY_OWN;
++}
++
++/**
++ * kdbus_conn_policy_talk() - verify a connection can talk to a given peer
++ * @conn:		Connection that tries to talk
++ * @conn_creds:		Credentials of @conn to use for policy check
++ * @to:			Connection that is talked to
++ *
++ * This verifies that @conn is allowed to talk to @to.
++ *
++ * Return: true if allowed, false if not.
++ */
++bool kdbus_conn_policy_talk(struct kdbus_conn *conn,
++			    const struct cred *conn_creds,
++			    struct kdbus_conn *to)
++{
++	if (!conn_creds)
++		conn_creds = conn->cred;
++
++	if (conn->ep->user &&
++	    !kdbus_conn_policy_query_all(conn, conn_creds, &conn->ep->policy_db,
++					 to, KDBUS_POLICY_TALK))
++		return false;
++
++	if (conn->owner)
++		return true;
++	if (uid_eq(conn_creds->euid, to->cred->uid))
++		return true;
++
++	return kdbus_conn_policy_query_all(conn, conn_creds,
++					   &conn->ep->bus->policy_db, to,
++					   KDBUS_POLICY_TALK);
++}
++
++/**
++ * kdbus_conn_policy_see_name_unlocked() - verify a connection can see a given
++ *					   name
++ * @conn:		Connection
++ * @conn_creds:		Credentials of @conn to use for policy check
++ * @name:		Name
++ *
++ * This verifies that @conn is allowed to see the well-known name @name. Caller
++ * must hold policy-lock.
++ *
++ * Return: true if allowed, false if not.
++ */
++bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn,
++					 const struct cred *conn_creds,
++					 const char *name)
++{
++	int res;
++
++	/*
++	 * By default, all names are visible on a bus. SEE policies can only be
++	 * installed on custom endpoints, where by default no name is visible.
++	 */
++	if (!conn->ep->user)
++		return true;
++
++	res = kdbus_policy_query_unlocked(&conn->ep->policy_db,
++					  conn_creds ? : conn->cred,
++					  name, kdbus_strhash(name));
++	return res >= KDBUS_POLICY_SEE;
++}
++
++static bool kdbus_conn_policy_see_name(struct kdbus_conn *conn,
++				       const struct cred *conn_creds,
++				       const char *name)
++{
++	bool res;
++
++	down_read(&conn->ep->policy_db.entries_rwlock);
++	res = kdbus_conn_policy_see_name_unlocked(conn, conn_creds, name);
++	up_read(&conn->ep->policy_db.entries_rwlock);
++
++	return res;
++}
++
++static bool kdbus_conn_policy_see(struct kdbus_conn *conn,
++				  const struct cred *conn_creds,
++				  struct kdbus_conn *whom)
++{
++	/*
++	 * By default, all names are visible on a bus, so a connection can
++	 * always see other connections. SEE policies can only be installed on
++	 * custom endpoints, where by default no name is visible and we hide
++	 * peers from each other, unless you see at least _one_ name of the
++	 * peer.
++	 */
++	return !conn->ep->user ||
++	       kdbus_conn_policy_query_all(conn, conn_creds,
++					   &conn->ep->policy_db, whom,
++					   KDBUS_POLICY_SEE);
++}
++
++/**
++ * kdbus_conn_policy_see_notification() - verify a connection is allowed to
++ *					  receive a given kernel notification
++ * @conn:		Connection
++ * @conn_creds:		Credentials of @conn to use for policy check
++ * @msg:		Notification message
++ *
++ * This checks whether @conn is allowed to see the kernel notification.
++ *
++ * Return: true if allowed, false if not.
++ */
++bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
++					const struct cred *conn_creds,
++					const struct kdbus_msg *msg)
++{
++	/*
++	 * Depending on the notification type, broadcasted kernel notifications
++	 * have to be filtered:
++	 *
++	 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}: This notification is forwarded
++	 *     to a peer if, and only if, that peer can see the name this
++	 *     notification is for.
++	 *
++	 * KDBUS_ITEM_ID_{ADD,REMOVE}: Notifications for ID changes are
++	 *     broadcast to everyone, to allow tracking peers.
++	 */
++
++	switch (msg->items[0].type) {
++	case KDBUS_ITEM_NAME_ADD:
++	case KDBUS_ITEM_NAME_REMOVE:
++	case KDBUS_ITEM_NAME_CHANGE:
++		return kdbus_conn_policy_see_name(conn, conn_creds,
++					msg->items[0].name_change.name);
++
++	case KDBUS_ITEM_ID_ADD:
++	case KDBUS_ITEM_ID_REMOVE:
++		return true;
++
++	default:
++		WARN(1, "Invalid type for notification broadcast: %llu\n",
++		     (unsigned long long)msg->items[0].type);
++		return false;
++	}
++}
++
++/**
++ * kdbus_cmd_hello() - handle KDBUS_CMD_HELLO
++ * @ep:			Endpoint to operate on
++ * @file:		File this connection is opened on
++ * @argp:		Command payload
++ *
++ * Return: NULL or newly created connection on success, ERR_PTR on failure.
++ */
++struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file,
++				   void __user *argp)
++{
++	struct kdbus_cmd_hello *cmd;
++	struct kdbus_conn *c = NULL;
++	const char *item_name;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_NAME },
++		{ .type = KDBUS_ITEM_CREDS },
++		{ .type = KDBUS_ITEM_PIDS },
++		{ .type = KDBUS_ITEM_SECLABEL },
++		{ .type = KDBUS_ITEM_CONN_DESCRIPTION },
++		{ .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_HELLO_ACCEPT_FD |
++				 KDBUS_HELLO_ACTIVATOR |
++				 KDBUS_HELLO_POLICY_HOLDER |
++				 KDBUS_HELLO_MONITOR,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret < 0)
++		return ERR_PTR(ret);
++	if (ret > 0)
++		return NULL;
++
++	item_name = argv[1].item ? argv[1].item->str : NULL;
++
++	c = kdbus_conn_new(ep, file, cmd, item_name,
++			   argv[2].item ? &argv[2].item->creds : NULL,
++			   argv[3].item ? &argv[3].item->pids : NULL,
++			   argv[4].item ? argv[4].item->str : NULL,
++			   argv[5].item ? argv[5].item->str : NULL);
++	if (IS_ERR(c)) {
++		ret = PTR_ERR(c);
++		c = NULL;
++		goto exit;
++	}
++
++	ret = kdbus_conn_connect(c, item_name);
++	if (ret < 0)
++		goto exit;
++
++	if (kdbus_conn_is_activator(c) || kdbus_conn_is_policy_holder(c)) {
++		ret = kdbus_conn_acquire(c);
++		if (ret < 0)
++			goto exit;
++
++		ret = kdbus_policy_set(&c->ep->bus->policy_db, args.items,
++				       args.items_size, 1,
++				       kdbus_conn_is_policy_holder(c), c);
++		kdbus_conn_release(c);
++		if (ret < 0)
++			goto exit;
++	}
++
++	if (copy_to_user(argp, cmd, sizeof(*cmd)))
++		ret = -EFAULT;
++
++exit:
++	ret = kdbus_args_clear(&args, ret);
++	if (ret < 0) {
++		if (c) {
++			kdbus_conn_disconnect(c, false);
++			kdbus_conn_unref(c);
++		}
++		return ERR_PTR(ret);
++	}
++	return c;
++}
++
++/**
++ * kdbus_cmd_byebye_unlocked() - handle KDBUS_CMD_BYEBYE
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * The caller must not hold any active reference to @conn or this will deadlock.
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_cmd *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn))
++		return -EOPNOTSUPP;
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	ret = kdbus_conn_disconnect(conn, true);
++	return kdbus_args_clear(&args, ret);
++}
++
++/**
++ * kdbus_cmd_conn_info() - handle KDBUS_CMD_CONN_INFO
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_meta_conn *conn_meta = NULL;
++	struct kdbus_pool_slice *slice = NULL;
++	struct kdbus_name_entry *entry = NULL;
++	struct kdbus_name_owner *owner = NULL;
++	struct kdbus_conn *owner_conn = NULL;
++	struct kdbus_item *meta_items = NULL;
++	struct kdbus_info info = {};
++	struct kdbus_cmd_info *cmd;
++	struct kdbus_bus *bus = conn->ep->bus;
++	struct kvec kvec[3];
++	size_t meta_size, cnt = 0;
++	const char *name;
++	u64 attach_flags, size = 0;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_NAME },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	/* registry must be held throughout lookup *and* collecting data */
++	down_read(&bus->name_registry->rwlock);
++
++	ret = kdbus_sanitize_attach_flags(cmd->attach_flags, &attach_flags);
++	if (ret < 0)
++		goto exit;
++
++	name = argv[1].item ? argv[1].item->str : NULL;
++
++	if (name) {
++		entry = kdbus_name_lookup_unlocked(bus->name_registry, name);
++		if (entry)
++			owner = kdbus_name_get_owner(entry);
++		if (!owner ||
++		    !kdbus_conn_policy_see_name(conn, current_cred(), name) ||
++		    (cmd->id != 0 && owner->conn->id != cmd->id)) {
++			/* pretend a name doesn't exist if you cannot see it */
++			ret = -ESRCH;
++			goto exit;
++		}
++
++		owner_conn = kdbus_conn_ref(owner->conn);
++	} else if (cmd->id > 0) {
++		owner_conn = kdbus_bus_find_conn_by_id(bus, cmd->id);
++		if (!owner_conn || !kdbus_conn_policy_see(conn, current_cred(),
++							  owner_conn)) {
++			/* pretend an id doesn't exist if you cannot see it */
++			ret = -ENXIO;
++			goto exit;
++		}
++	} else {
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	attach_flags &= atomic64_read(&owner_conn->attach_flags_send);
++
++	conn_meta = kdbus_meta_conn_new();
++	if (IS_ERR(conn_meta)) {
++		ret = PTR_ERR(conn_meta);
++		conn_meta = NULL;
++		goto exit;
++	}
++
++	ret = kdbus_meta_conn_collect(conn_meta, owner_conn, 0, attach_flags);
++	if (ret < 0)
++		goto exit;
++
++	ret = kdbus_meta_emit(owner_conn->meta_proc, owner_conn->meta_fake,
++			      conn_meta, conn, attach_flags,
++			      &meta_items, &meta_size);
++	if (ret < 0)
++		goto exit;
++
++	info.id = owner_conn->id;
++	info.flags = owner_conn->flags;
++
++	kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size);
++	if (meta_size > 0) {
++		kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size);
++		cnt += !!kdbus_kvec_pad(&kvec[cnt], &size);
++	}
++
++	info.size = size;
++
++	slice = kdbus_pool_slice_alloc(conn->pool, size, false);
++	if (IS_ERR(slice)) {
++		ret = PTR_ERR(slice);
++		slice = NULL;
++		goto exit;
++	}
++
++	ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size);
++	if (ret < 0)
++		goto exit;
++
++	kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->info_size);
++
++	if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) ||
++	    kdbus_member_set_user(&cmd->info_size, argp,
++				  typeof(*cmd), info_size)) {
++		ret = -EFAULT;
++		goto exit;
++	}
++
++	ret = 0;
++
++exit:
++	up_read(&bus->name_registry->rwlock);
++	kdbus_pool_slice_release(slice);
++	kfree(meta_items);
++	kdbus_meta_conn_unref(conn_meta);
++	kdbus_conn_unref(owner_conn);
++	return kdbus_args_clear(&args, ret);
++}
++
++/**
++ * kdbus_cmd_update() - handle KDBUS_CMD_UPDATE
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_item *item_policy;
++	u64 *item_attach_send = NULL;
++	u64 *item_attach_recv = NULL;
++	struct kdbus_cmd *cmd;
++	u64 attach_send;
++	u64 attach_recv;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_ATTACH_FLAGS_SEND },
++		{ .type = KDBUS_ITEM_ATTACH_FLAGS_RECV },
++		{ .type = KDBUS_ITEM_NAME, .multiple = true },
++		{ .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	item_attach_send = argv[1].item ? &argv[1].item->data64[0] : NULL;
++	item_attach_recv = argv[2].item ? &argv[2].item->data64[0] : NULL;
++	item_policy = argv[3].item ? : argv[4].item;
++
++	if (item_attach_send) {
++		if (!kdbus_conn_is_ordinary(conn) &&
++		    !kdbus_conn_is_monitor(conn)) {
++			ret = -EOPNOTSUPP;
++			goto exit;
++		}
++
++		ret = kdbus_sanitize_attach_flags(*item_attach_send,
++						  &attach_send);
++		if (ret < 0)
++			goto exit;
++	}
++
++	if (item_attach_recv) {
++		if (!kdbus_conn_is_ordinary(conn) &&
++		    !kdbus_conn_is_monitor(conn) &&
++		    !kdbus_conn_is_activator(conn)) {
++			ret = -EOPNOTSUPP;
++			goto exit;
++		}
++
++		ret = kdbus_sanitize_attach_flags(*item_attach_recv,
++						  &attach_recv);
++		if (ret < 0)
++			goto exit;
++	}
++
++	if (item_policy && !kdbus_conn_is_policy_holder(conn)) {
++		ret = -EOPNOTSUPP;
++		goto exit;
++	}
++
++	/* now that we verified the input, update the connection */
++
++	if (item_policy) {
++		ret = kdbus_policy_set(&conn->ep->bus->policy_db, cmd->items,
++				       KDBUS_ITEMS_SIZE(cmd, items),
++				       1, true, conn);
++		if (ret < 0)
++			goto exit;
++	}
++
++	if (item_attach_send)
++		atomic64_set(&conn->attach_flags_send, attach_send);
++
++	if (item_attach_recv)
++		atomic64_set(&conn->attach_flags_recv, attach_recv);
++
++exit:
++	return kdbus_args_clear(&args, ret);
++}
++
++/**
++ * kdbus_cmd_send() - handle KDBUS_CMD_SEND
++ * @conn:		connection to operate on
++ * @f:			file this command was called on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
++{
++	struct kdbus_cmd_send *cmd;
++	struct kdbus_staging *staging = NULL;
++	struct kdbus_msg *msg = NULL;
++	struct file *cancel_fd = NULL;
++	int ret, ret2;
++
++	/* command arguments */
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_CANCEL_FD },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_SEND_SYNC_REPLY,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	/* message arguments */
++	struct kdbus_arg msg_argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_PAYLOAD_VEC, .multiple = true },
++		{ .type = KDBUS_ITEM_PAYLOAD_MEMFD, .multiple = true },
++		{ .type = KDBUS_ITEM_FDS },
++		{ .type = KDBUS_ITEM_BLOOM_FILTER },
++		{ .type = KDBUS_ITEM_DST_NAME },
++	};
++	struct kdbus_args msg_args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_MSG_EXPECT_REPLY |
++				 KDBUS_MSG_NO_AUTO_START |
++				 KDBUS_MSG_SIGNAL,
++		.argv = msg_argv,
++		.argc = ARRAY_SIZE(msg_argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn))
++		return -EOPNOTSUPP;
++
++	/* make sure to parse both, @cmd and @msg on negotiation */
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret < 0)
++		goto exit;
++	else if (ret > 0 && !cmd->msg_address) /* negotiation without msg */
++		goto exit;
++
++	ret2 = kdbus_args_parse_msg(&msg_args, KDBUS_PTR(cmd->msg_address),
++				    &msg);
++	if (ret2 < 0) { /* cannot parse message */
++		ret = ret2;
++		goto exit;
++	} else if (ret2 > 0 && !ret) { /* msg-negot implies cmd-negot */
++		ret = -EINVAL;
++		goto exit;
++	} else if (ret > 0) { /* negotiation */
++		goto exit;
++	}
++
++	/* here we parsed both, @cmd and @msg, and neither wants negotiation */
++
++	cmd->reply.return_flags = 0;
++	kdbus_pool_publish_empty(conn->pool, &cmd->reply.offset,
++				 &cmd->reply.msg_size);
++
++	if (argv[1].item) {
++		cancel_fd = fget(argv[1].item->fds[0]);
++		if (!cancel_fd) {
++			ret = -EBADF;
++			goto exit;
++		}
++
++		if (!cancel_fd->f_op->poll) {
++			ret = -EINVAL;
++			goto exit;
++		}
++	}
++
++	/* patch-in the source of this message */
++	if (msg->src_id > 0 && msg->src_id != conn->id) {
++		ret = -EINVAL;
++		goto exit;
++	}
++	msg->src_id = conn->id;
++
++	staging = kdbus_staging_new_user(conn->ep->bus, cmd, msg);
++	if (IS_ERR(staging)) {
++		ret = PTR_ERR(staging);
++		staging = NULL;
++		goto exit;
++	}
++
++	if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
++		down_read(&conn->ep->bus->name_registry->rwlock);
++		kdbus_bus_broadcast(conn->ep->bus, conn, staging);
++		up_read(&conn->ep->bus->name_registry->rwlock);
++	} else if (cmd->flags & KDBUS_SEND_SYNC_REPLY) {
++		struct kdbus_reply *r;
++		ktime_t exp;
++
++		exp = ns_to_ktime(msg->timeout_ns);
++		r = kdbus_conn_call(conn, staging, exp);
++		if (IS_ERR(r)) {
++			ret = PTR_ERR(r);
++			goto exit;
++		}
++
++		ret = kdbus_conn_wait_reply(conn, cmd, f, cancel_fd, r, exp);
++		kdbus_reply_unref(r);
++		if (ret < 0)
++			goto exit;
++	} else if ((msg->flags & KDBUS_MSG_EXPECT_REPLY) ||
++		   msg->cookie_reply == 0) {
++		ret = kdbus_conn_unicast(conn, staging);
++		if (ret < 0)
++			goto exit;
++	} else {
++		ret = kdbus_conn_reply(conn, staging);
++		if (ret < 0)
++			goto exit;
++	}
++
++	if (kdbus_member_set_user(&cmd->reply, argp, typeof(*cmd), reply))
++		ret = -EFAULT;
++
++exit:
++	if (cancel_fd)
++		fput(cancel_fd);
++	kdbus_staging_free(staging);
++	ret = kdbus_args_clear(&msg_args, ret);
++	return kdbus_args_clear(&args, ret);
++}
++
++/**
++ * kdbus_cmd_recv() - handle KDBUS_CMD_RECV
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_queue_entry *entry;
++	struct kdbus_cmd_recv *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_RECV_PEEK |
++				 KDBUS_RECV_DROP |
++				 KDBUS_RECV_USE_PRIORITY,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn) &&
++	    !kdbus_conn_is_monitor(conn) &&
++	    !kdbus_conn_is_activator(conn))
++		return -EOPNOTSUPP;
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	cmd->dropped_msgs = 0;
++	cmd->msg.return_flags = 0;
++	kdbus_pool_publish_empty(conn->pool, &cmd->msg.offset,
++				 &cmd->msg.msg_size);
++
++	/* DROP+priority is not realiably, so prevent it */
++	if ((cmd->flags & KDBUS_RECV_DROP) &&
++	    (cmd->flags & KDBUS_RECV_USE_PRIORITY)) {
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	mutex_lock(&conn->lock);
++
++	entry = kdbus_queue_peek(&conn->queue, cmd->priority,
++				 cmd->flags & KDBUS_RECV_USE_PRIORITY);
++	if (!entry) {
++		mutex_unlock(&conn->lock);
++		ret = -EAGAIN;
++	} else if (cmd->flags & KDBUS_RECV_DROP) {
++		struct kdbus_reply *reply = kdbus_reply_ref(entry->reply);
++
++		kdbus_queue_entry_free(entry);
++
++		mutex_unlock(&conn->lock);
++
++		if (reply) {
++			mutex_lock(&reply->reply_dst->lock);
++			if (!list_empty(&reply->entry)) {
++				kdbus_reply_unlink(reply);
++				if (reply->sync)
++					kdbus_sync_reply_wakeup(reply, -EPIPE);
++				else
++					kdbus_notify_reply_dead(conn->ep->bus,
++							reply->reply_dst->id,
++							reply->cookie);
++			}
++			mutex_unlock(&reply->reply_dst->lock);
++			kdbus_notify_flush(conn->ep->bus);
++		}
++
++		kdbus_reply_unref(reply);
++	} else {
++		bool install_fds;
++
++		/*
++		 * PEEK just returns the location of the next message. Do not
++		 * install FDs nor memfds nor anything else. The only
++		 * information of interest should be the message header and
++		 * metadata. Any FD numbers in the payload is undefined for
++		 * PEEK'ed messages.
++		 * Also make sure to never install fds into a connection that
++		 * has refused to receive any. Ordinary connections will not get
++		 * messages with FDs queued (the receiver will get -ECOMM), but
++		 * eavesdroppers might.
++		 */
++		install_fds = (conn->flags & KDBUS_HELLO_ACCEPT_FD) &&
++			      !(cmd->flags & KDBUS_RECV_PEEK);
++
++		ret = kdbus_queue_entry_install(entry,
++						&cmd->msg.return_flags,
++						install_fds);
++		if (ret < 0) {
++			mutex_unlock(&conn->lock);
++			goto exit;
++		}
++
++		kdbus_pool_slice_publish(entry->slice, &cmd->msg.offset,
++					 &cmd->msg.msg_size);
++
++		if (!(cmd->flags & KDBUS_RECV_PEEK))
++			kdbus_queue_entry_free(entry);
++
++		mutex_unlock(&conn->lock);
++	}
++
++	cmd->dropped_msgs = atomic_xchg(&conn->lost_count, 0);
++	if (cmd->dropped_msgs > 0)
++		cmd->return_flags |= KDBUS_RECV_RETURN_DROPPED_MSGS;
++
++	if (kdbus_member_set_user(&cmd->msg, argp, typeof(*cmd), msg) ||
++	    kdbus_member_set_user(&cmd->dropped_msgs, argp, typeof(*cmd),
++				  dropped_msgs))
++		ret = -EFAULT;
++
++exit:
++	return kdbus_args_clear(&args, ret);
++}
++
++/**
++ * kdbus_cmd_free() - handle KDBUS_CMD_FREE
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_cmd_free *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn) &&
++	    !kdbus_conn_is_monitor(conn) &&
++	    !kdbus_conn_is_activator(conn))
++		return -EOPNOTSUPP;
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	ret = kdbus_pool_release_offset(conn->pool, cmd->offset);
++
++	return kdbus_args_clear(&args, ret);
++}
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+new file mode 100644
+index 0000000..1ad0820
+--- /dev/null
++++ b/ipc/kdbus/connection.h
+@@ -0,0 +1,260 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_CONNECTION_H
++#define __KDBUS_CONNECTION_H
++
++#include <linux/atomic.h>
++#include <linux/kref.h>
++#include <linux/lockdep.h>
++#include <linux/path.h>
++
++#include "limits.h"
++#include "metadata.h"
++#include "pool.h"
++#include "queue.h"
++#include "util.h"
++
++#define KDBUS_HELLO_SPECIAL_CONN	(KDBUS_HELLO_ACTIVATOR | \
++					 KDBUS_HELLO_POLICY_HOLDER | \
++					 KDBUS_HELLO_MONITOR)
++
++struct kdbus_name_entry;
++struct kdbus_quota;
++struct kdbus_staging;
++
++/**
++ * struct kdbus_conn - connection to a bus
++ * @kref:		Reference count
++ * @active:		Active references to the connection
++ * @id:			Connection ID
++ * @flags:		KDBUS_HELLO_* flags
++ * @attach_flags_send:	KDBUS_ATTACH_* flags for sending
++ * @attach_flags_recv:	KDBUS_ATTACH_* flags for receiving
++ * @description:	Human-readable connection description, used for
++ *			debugging. This field is only set when the
++ *			connection is created.
++ * @ep:			The endpoint this connection belongs to
++ * @lock:		Connection data lock
++ * @hentry:		Entry in ID <-> connection map
++ * @ep_entry:		Entry in endpoint
++ * @monitor_entry:	Entry in monitor, if the connection is a monitor
++ * @reply_list:		List of connections this connection should
++ *			reply to
++ * @work:		Delayed work to handle timeouts
++ *			activator for
++ * @match_db:		Subscription filter to broadcast messages
++ * @meta_proc:		Process metadata of connection creator, or NULL
++ * @meta_fake:		Faked metadata, or NULL
++ * @pool:		The user's buffer to receive messages
++ * @user:		Owner of the connection
++ * @cred:		The credentials of the connection at creation time
++ * @pid:		Pid at creation time
++ * @root_path:		Root path at creation time
++ * @request_count:	Number of pending requests issued by this
++ *			connection that are waiting for replies from
++ *			other peers
++ * @lost_count:		Number of lost broadcast messages
++ * @wait:		Wake up this endpoint
++ * @queue:		The message queue associated with this connection
++ * @quota:		Array of per-user quota indexed by user->id
++ * @n_quota:		Number of elements in quota array
++ * @names_list:		List of well-known names
++ * @name_count:		Number of owned well-known names
++ * @privileged:		Whether this connection is privileged on the domain
++ * @owner:		Owned by the same user as the bus owner
++ */
++struct kdbus_conn {
++	struct kref kref;
++	atomic_t active;
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++	struct lockdep_map dep_map;
++#endif
++	u64 id;
++	u64 flags;
++	atomic64_t attach_flags_send;
++	atomic64_t attach_flags_recv;
++	const char *description;
++	struct kdbus_ep *ep;
++	struct mutex lock;
++	struct hlist_node hentry;
++	struct list_head ep_entry;
++	struct list_head monitor_entry;
++	struct list_head reply_list;
++	struct delayed_work work;
++	struct kdbus_match_db *match_db;
++	struct kdbus_meta_proc *meta_proc;
++	struct kdbus_meta_fake *meta_fake;
++	struct kdbus_pool *pool;
++	struct kdbus_user *user;
++	const struct cred *cred;
++	struct pid *pid;
++	struct path root_path;
++	atomic_t request_count;
++	atomic_t lost_count;
++	wait_queue_head_t wait;
++	struct kdbus_queue queue;
++
++	struct kdbus_quota *quota;
++	unsigned int n_quota;
++
++	/* protected by registry->rwlock */
++	struct list_head names_list;
++	unsigned int name_count;
++
++	bool privileged:1;
++	bool owner:1;
++};
++
++struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn);
++struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn);
++bool kdbus_conn_active(const struct kdbus_conn *conn);
++int kdbus_conn_acquire(struct kdbus_conn *conn);
++void kdbus_conn_release(struct kdbus_conn *conn);
++int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty);
++bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name);
++int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u,
++			 size_t memory, size_t fds);
++void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u,
++			  size_t memory, size_t fds);
++void kdbus_conn_lost_message(struct kdbus_conn *c);
++int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
++			    struct kdbus_conn *conn_dst,
++			    struct kdbus_staging *staging,
++			    struct kdbus_reply *reply,
++			    const struct kdbus_name_entry *name);
++void kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
++			      struct kdbus_conn *conn_src,
++			      u64 name_id);
++
++/* policy */
++bool kdbus_conn_policy_own_name(struct kdbus_conn *conn,
++				const struct cred *conn_creds,
++				const char *name);
++bool kdbus_conn_policy_talk(struct kdbus_conn *conn,
++			    const struct cred *conn_creds,
++			    struct kdbus_conn *to);
++bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn,
++					 const struct cred *curr_creds,
++					 const char *name);
++bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
++					const struct cred *curr_creds,
++					const struct kdbus_msg *msg);
++
++/* command dispatcher */
++struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file,
++				   void __user *argp);
++int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp);
++int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp);
++int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp);
++int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp);
++int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp);
++int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp);
++
++/**
++ * kdbus_conn_is_ordinary() - Check if connection is ordinary
++ * @conn:		The connection to check
++ *
++ * Return: Non-zero if the connection is an ordinary connection
++ */
++static inline int kdbus_conn_is_ordinary(const struct kdbus_conn *conn)
++{
++	return !(conn->flags & KDBUS_HELLO_SPECIAL_CONN);
++}
++
++/**
++ * kdbus_conn_is_activator() - Check if connection is an activator
++ * @conn:		The connection to check
++ *
++ * Return: Non-zero if the connection is an activator
++ */
++static inline int kdbus_conn_is_activator(const struct kdbus_conn *conn)
++{
++	return conn->flags & KDBUS_HELLO_ACTIVATOR;
++}
++
++/**
++ * kdbus_conn_is_policy_holder() - Check if connection is a policy holder
++ * @conn:		The connection to check
++ *
++ * Return: Non-zero if the connection is a policy holder
++ */
++static inline int kdbus_conn_is_policy_holder(const struct kdbus_conn *conn)
++{
++	return conn->flags & KDBUS_HELLO_POLICY_HOLDER;
++}
++
++/**
++ * kdbus_conn_is_monitor() - Check if connection is a monitor
++ * @conn:		The connection to check
++ *
++ * Return: Non-zero if the connection is a monitor
++ */
++static inline int kdbus_conn_is_monitor(const struct kdbus_conn *conn)
++{
++	return conn->flags & KDBUS_HELLO_MONITOR;
++}
++
++/**
++ * kdbus_conn_lock2() - Lock two connections
++ * @a:		connection A to lock or NULL
++ * @b:		connection B to lock or NULL
++ *
++ * Lock two connections at once. As we need to have a stable locking order, we
++ * always lock the connection with lower memory address first.
++ */
++static inline void kdbus_conn_lock2(struct kdbus_conn *a, struct kdbus_conn *b)
++{
++	if (a < b) {
++		if (a)
++			mutex_lock(&a->lock);
++		if (b && b != a)
++			mutex_lock_nested(&b->lock, !!a);
++	} else {
++		if (b)
++			mutex_lock(&b->lock);
++		if (a && a != b)
++			mutex_lock_nested(&a->lock, !!b);
++	}
++}
++
++/**
++ * kdbus_conn_unlock2() - Unlock two connections
++ * @a:		connection A to unlock or NULL
++ * @b:		connection B to unlock or NULL
++ *
++ * Unlock two connections at once. See kdbus_conn_lock2().
++ */
++static inline void kdbus_conn_unlock2(struct kdbus_conn *a,
++				      struct kdbus_conn *b)
++{
++	if (a)
++		mutex_unlock(&a->lock);
++	if (b && b != a)
++		mutex_unlock(&b->lock);
++}
++
++/**
++ * kdbus_conn_assert_active() - lockdep assert on active lock
++ * @conn:	connection that shall be active
++ *
++ * This verifies via lockdep that the caller holds an active reference to the
++ * given connection.
++ */
++static inline void kdbus_conn_assert_active(struct kdbus_conn *conn)
++{
++	lockdep_assert_held(conn);
++}
++
++#endif
+diff --git a/ipc/kdbus/domain.c b/ipc/kdbus/domain.c
+new file mode 100644
+index 0000000..ac9f760
+--- /dev/null
++++ b/ipc/kdbus/domain.c
+@@ -0,0 +1,296 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/fs.h>
++#include <linux/idr.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#include "bus.h"
++#include "domain.h"
++#include "handle.h"
++#include "item.h"
++#include "limits.h"
++#include "util.h"
++
++static void kdbus_domain_control_free(struct kdbus_node *node)
++{
++	kfree(node);
++}
++
++static struct kdbus_node *kdbus_domain_control_new(struct kdbus_domain *domain,
++						   unsigned int access)
++{
++	struct kdbus_node *node;
++	int ret;
++
++	node = kzalloc(sizeof(*node), GFP_KERNEL);
++	if (!node)
++		return ERR_PTR(-ENOMEM);
++
++	kdbus_node_init(node, KDBUS_NODE_CONTROL);
++
++	node->free_cb = kdbus_domain_control_free;
++	node->mode = domain->node.mode;
++	node->mode = S_IRUSR | S_IWUSR;
++	if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD))
++		node->mode |= S_IRGRP | S_IWGRP;
++	if (access & KDBUS_MAKE_ACCESS_WORLD)
++		node->mode |= S_IROTH | S_IWOTH;
++
++	ret = kdbus_node_link(node, &domain->node, "control");
++	if (ret < 0)
++		goto exit_free;
++
++	return node;
++
++exit_free:
++	kdbus_node_deactivate(node);
++	kdbus_node_unref(node);
++	return ERR_PTR(ret);
++}
++
++static void kdbus_domain_free(struct kdbus_node *node)
++{
++	struct kdbus_domain *domain =
++		container_of(node, struct kdbus_domain, node);
++
++	put_user_ns(domain->user_namespace);
++	ida_destroy(&domain->user_ida);
++	idr_destroy(&domain->user_idr);
++	kfree(domain);
++}
++
++/**
++ * kdbus_domain_new() - create a new domain
++ * @access:		The access mode for this node (KDBUS_MAKE_ACCESS_*)
++ *
++ * Return: a new kdbus_domain on success, ERR_PTR on failure
++ */
++struct kdbus_domain *kdbus_domain_new(unsigned int access)
++{
++	struct kdbus_domain *d;
++	int ret;
++
++	d = kzalloc(sizeof(*d), GFP_KERNEL);
++	if (!d)
++		return ERR_PTR(-ENOMEM);
++
++	kdbus_node_init(&d->node, KDBUS_NODE_DOMAIN);
++
++	d->node.free_cb = kdbus_domain_free;
++	d->node.mode = S_IRUSR | S_IXUSR;
++	if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD))
++		d->node.mode |= S_IRGRP | S_IXGRP;
++	if (access & KDBUS_MAKE_ACCESS_WORLD)
++		d->node.mode |= S_IROTH | S_IXOTH;
++
++	mutex_init(&d->lock);
++	idr_init(&d->user_idr);
++	ida_init(&d->user_ida);
++
++	/* Pin user namespace so we can guarantee domain-unique bus * names. */
++	d->user_namespace = get_user_ns(current_user_ns());
++
++	ret = kdbus_node_link(&d->node, NULL, NULL);
++	if (ret < 0)
++		goto exit_unref;
++
++	return d;
++
++exit_unref:
++	kdbus_node_deactivate(&d->node);
++	kdbus_node_unref(&d->node);
++	return ERR_PTR(ret);
++}
++
++/**
++ * kdbus_domain_ref() - take a domain reference
++ * @domain:		Domain
++ *
++ * Return: the domain itself
++ */
++struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain)
++{
++	if (domain)
++		kdbus_node_ref(&domain->node);
++	return domain;
++}
++
++/**
++ * kdbus_domain_unref() - drop a domain reference
++ * @domain:		Domain
++ *
++ * When the last reference is dropped, the domain internal structure
++ * is freed.
++ *
++ * Return: NULL
++ */
++struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain)
++{
++	if (domain)
++		kdbus_node_unref(&domain->node);
++	return NULL;
++}
++
++/**
++ * kdbus_domain_populate() - populate static domain nodes
++ * @domain:	domain to populate
++ * @access:	KDBUS_MAKE_ACCESS_* access restrictions for new nodes
++ *
++ * Allocate and activate static sub-nodes of the given domain. This will fail if
++ * you call it on a non-active node or if the domain was already populated.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_domain_populate(struct kdbus_domain *domain, unsigned int access)
++{
++	struct kdbus_node *control;
++
++	/*
++	 * Create a control-node for this domain. We drop our own reference
++	 * immediately, effectively causing the node to be deactivated and
++	 * released when the parent domain is.
++	 */
++	control = kdbus_domain_control_new(domain, access);
++	if (IS_ERR(control))
++		return PTR_ERR(control);
++
++	kdbus_node_activate(control);
++	kdbus_node_unref(control);
++	return 0;
++}
++
++/**
++ * kdbus_user_lookup() - lookup a kdbus_user object
++ * @domain:		domain of the user
++ * @uid:		uid of the user; INVALID_UID for an anon user
++ *
++ * Lookup the kdbus user accounting object for the given domain. If INVALID_UID
++ * is passed, a new anonymous user is created which is private to the caller.
++ *
++ * Return: The user object is returned, ERR_PTR on failure.
++ */
++struct kdbus_user *kdbus_user_lookup(struct kdbus_domain *domain, kuid_t uid)
++{
++	struct kdbus_user *u = NULL, *old = NULL;
++	int ret;
++
++	mutex_lock(&domain->lock);
++
++	if (uid_valid(uid)) {
++		old = idr_find(&domain->user_idr, __kuid_val(uid));
++		/*
++		 * If the object is about to be destroyed, ignore it and
++		 * replace the slot in the IDR later on.
++		 */
++		if (old && kref_get_unless_zero(&old->kref)) {
++			mutex_unlock(&domain->lock);
++			return old;
++		}
++	}
++
++	u = kzalloc(sizeof(*u), GFP_KERNEL);
++	if (!u) {
++		ret = -ENOMEM;
++		goto exit;
++	}
++
++	kref_init(&u->kref);
++	u->domain = kdbus_domain_ref(domain);
++	u->uid = uid;
++	atomic_set(&u->buses, 0);
++	atomic_set(&u->connections, 0);
++
++	if (uid_valid(uid)) {
++		if (old) {
++			idr_replace(&domain->user_idr, u, __kuid_val(uid));
++			old->uid = INVALID_UID; /* mark old as removed */
++		} else {
++			ret = idr_alloc(&domain->user_idr, u, __kuid_val(uid),
++					__kuid_val(uid) + 1, GFP_KERNEL);
++			if (ret < 0)
++				goto exit;
++		}
++	}
++
++	/*
++	 * Allocate the smallest possible index for this user; used
++	 * in arrays for accounting user quota in receiver queues.
++	 */
++	ret = ida_simple_get(&domain->user_ida, 1, 0, GFP_KERNEL);
++	if (ret < 0)
++		goto exit;
++
++	u->id = ret;
++	mutex_unlock(&domain->lock);
++	return u;
++
++exit:
++	if (u) {
++		if (uid_valid(u->uid))
++			idr_remove(&domain->user_idr, __kuid_val(u->uid));
++		kdbus_domain_unref(u->domain);
++		kfree(u);
++	}
++	mutex_unlock(&domain->lock);
++	return ERR_PTR(ret);
++}
++
++static void __kdbus_user_free(struct kref *kref)
++{
++	struct kdbus_user *user = container_of(kref, struct kdbus_user, kref);
++
++	WARN_ON(atomic_read(&user->buses) > 0);
++	WARN_ON(atomic_read(&user->connections) > 0);
++
++	mutex_lock(&user->domain->lock);
++	ida_simple_remove(&user->domain->user_ida, user->id);
++	if (uid_valid(user->uid))
++		idr_remove(&user->domain->user_idr, __kuid_val(user->uid));
++	mutex_unlock(&user->domain->lock);
++
++	kdbus_domain_unref(user->domain);
++	kfree(user);
++}
++
++/**
++ * kdbus_user_ref() - take a user reference
++ * @u:		User
++ *
++ * Return: @u is returned
++ */
++struct kdbus_user *kdbus_user_ref(struct kdbus_user *u)
++{
++	if (u)
++		kref_get(&u->kref);
++	return u;
++}
++
++/**
++ * kdbus_user_unref() - drop a user reference
++ * @u:		User
++ *
++ * Return: NULL
++ */
++struct kdbus_user *kdbus_user_unref(struct kdbus_user *u)
++{
++	if (u)
++		kref_put(&u->kref, __kdbus_user_free);
++	return NULL;
++}
+diff --git a/ipc/kdbus/domain.h b/ipc/kdbus/domain.h
+new file mode 100644
+index 0000000..447a2bd
+--- /dev/null
++++ b/ipc/kdbus/domain.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_DOMAIN_H
++#define __KDBUS_DOMAIN_H
++
++#include <linux/fs.h>
++#include <linux/idr.h>
++#include <linux/kref.h>
++#include <linux/user_namespace.h>
++
++#include "node.h"
++
++/**
++ * struct kdbus_domain - domain for buses
++ * @node:		Underlying API node
++ * @lock:		Domain data lock
++ * @last_id:		Last used object id
++ * @user_idr:		Set of all users indexed by UID
++ * @user_ida:		Set of all users to compute small indices
++ * @user_namespace:	User namespace, pinned at creation time
++ * @dentry:		Root dentry of VFS mount (don't use outside of kdbusfs)
++ */
++struct kdbus_domain {
++	struct kdbus_node node;
++	struct mutex lock;
++	atomic64_t last_id;
++	struct idr user_idr;
++	struct ida user_ida;
++	struct user_namespace *user_namespace;
++	struct dentry *dentry;
++};
++
++/**
++ * struct kdbus_user - resource accounting for users
++ * @kref:		Reference counter
++ * @domain:		Domain of the user
++ * @id:			Index of this user
++ * @uid:		UID of the user
++ * @buses:		Number of buses the user has created
++ * @connections:	Number of connections the user has created
++ */
++struct kdbus_user {
++	struct kref kref;
++	struct kdbus_domain *domain;
++	unsigned int id;
++	kuid_t uid;
++	atomic_t buses;
++	atomic_t connections;
++};
++
++#define kdbus_domain_from_node(_node) \
++	container_of((_node), struct kdbus_domain, node)
++
++struct kdbus_domain *kdbus_domain_new(unsigned int access);
++struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain);
++struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain);
++int kdbus_domain_populate(struct kdbus_domain *domain, unsigned int access);
++
++#define KDBUS_USER_KERNEL_ID 0 /* ID 0 is reserved for kernel accounting */
++
++struct kdbus_user *kdbus_user_lookup(struct kdbus_domain *domain, kuid_t uid);
++struct kdbus_user *kdbus_user_ref(struct kdbus_user *u);
++struct kdbus_user *kdbus_user_unref(struct kdbus_user *u);
++
++#endif
+diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c
+new file mode 100644
+index 0000000..44e7a20
+--- /dev/null
++++ b/ipc/kdbus/endpoint.c
+@@ -0,0 +1,303 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/fs.h>
++#include <linux/idr.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/uio.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "domain.h"
++#include "endpoint.h"
++#include "handle.h"
++#include "item.h"
++#include "message.h"
++#include "policy.h"
++
++static void kdbus_ep_free(struct kdbus_node *node)
++{
++	struct kdbus_ep *ep = container_of(node, struct kdbus_ep, node);
++
++	WARN_ON(!list_empty(&ep->conn_list));
++
++	kdbus_policy_db_clear(&ep->policy_db);
++	kdbus_bus_unref(ep->bus);
++	kdbus_user_unref(ep->user);
++	kfree(ep);
++}
++
++static void kdbus_ep_release(struct kdbus_node *node, bool was_active)
++{
++	struct kdbus_ep *ep = container_of(node, struct kdbus_ep, node);
++
++	/* disconnect all connections to this endpoint */
++	for (;;) {
++		struct kdbus_conn *conn;
++
++		mutex_lock(&ep->lock);
++		conn = list_first_entry_or_null(&ep->conn_list,
++						struct kdbus_conn,
++						ep_entry);
++		if (!conn) {
++			mutex_unlock(&ep->lock);
++			break;
++		}
++
++		/* take reference, release lock, disconnect without lock */
++		kdbus_conn_ref(conn);
++		mutex_unlock(&ep->lock);
++
++		kdbus_conn_disconnect(conn, false);
++		kdbus_conn_unref(conn);
++	}
++}
++
++/**
++ * kdbus_ep_new() - create a new endpoint
++ * @bus:		The bus this endpoint will be created for
++ * @name:		The name of the endpoint
++ * @access:		The access flags for this node (KDBUS_MAKE_ACCESS_*)
++ * @uid:		The uid of the node
++ * @gid:		The gid of the node
++ * @is_custom:		Whether this is a custom endpoint
++ *
++ * This function will create a new endpoint with the given
++ * name and properties for a given bus.
++ *
++ * Return: a new kdbus_ep on success, ERR_PTR on failure.
++ */
++struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name,
++			      unsigned int access, kuid_t uid, kgid_t gid,
++			      bool is_custom)
++{
++	struct kdbus_ep *e;
++	int ret;
++
++	/*
++	 * Validate only custom endpoints names, default endpoints
++	 * with a "bus" name are created when the bus is created
++	 */
++	if (is_custom) {
++		ret = kdbus_verify_uid_prefix(name, bus->domain->user_namespace,
++					      uid);
++		if (ret < 0)
++			return ERR_PTR(ret);
++	}
++
++	e = kzalloc(sizeof(*e), GFP_KERNEL);
++	if (!e)
++		return ERR_PTR(-ENOMEM);
++
++	kdbus_node_init(&e->node, KDBUS_NODE_ENDPOINT);
++
++	e->node.free_cb = kdbus_ep_free;
++	e->node.release_cb = kdbus_ep_release;
++	e->node.uid = uid;
++	e->node.gid = gid;
++	e->node.mode = S_IRUSR | S_IWUSR;
++	if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD))
++		e->node.mode |= S_IRGRP | S_IWGRP;
++	if (access & KDBUS_MAKE_ACCESS_WORLD)
++		e->node.mode |= S_IROTH | S_IWOTH;
++
++	mutex_init(&e->lock);
++	INIT_LIST_HEAD(&e->conn_list);
++	kdbus_policy_db_init(&e->policy_db);
++	e->bus = kdbus_bus_ref(bus);
++
++	ret = kdbus_node_link(&e->node, &bus->node, name);
++	if (ret < 0)
++		goto exit_unref;
++
++	/*
++	 * Transactions on custom endpoints are never accounted on the global
++	 * user limits. Instead, for each custom endpoint, we create a custom,
++	 * unique user, which all transactions are accounted on. Regardless of
++	 * the user using that endpoint, it is always accounted on the same
++	 * user-object. This budget is not shared with ordinary users on
++	 * non-custom endpoints.
++	 */
++	if (is_custom) {
++		e->user = kdbus_user_lookup(bus->domain, INVALID_UID);
++		if (IS_ERR(e->user)) {
++			ret = PTR_ERR(e->user);
++			e->user = NULL;
++			goto exit_unref;
++		}
++	}
++
++	return e;
++
++exit_unref:
++	kdbus_node_deactivate(&e->node);
++	kdbus_node_unref(&e->node);
++	return ERR_PTR(ret);
++}
++
++/**
++ * kdbus_ep_ref() - increase the reference counter of a kdbus_ep
++ * @ep:			The endpoint to reference
++ *
++ * Every user of an endpoint, except for its creator, must add a reference to
++ * the kdbus_ep instance using this function.
++ *
++ * Return: the ep itself
++ */
++struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep)
++{
++	if (ep)
++		kdbus_node_ref(&ep->node);
++	return ep;
++}
++
++/**
++ * kdbus_ep_unref() - decrease the reference counter of a kdbus_ep
++ * @ep:		The ep to unref
++ *
++ * Release a reference. If the reference count drops to 0, the ep will be
++ * freed.
++ *
++ * Return: NULL
++ */
++struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep)
++{
++	if (ep)
++		kdbus_node_unref(&ep->node);
++	return NULL;
++}
++
++/**
++ * kdbus_ep_is_privileged() - check whether a file is privileged
++ * @ep:		endpoint to operate on
++ * @file:	file to test
++ *
++ * Return: True if @file is privileged in the domain of @ep.
++ */
++bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file)
++{
++	return !ep->user &&
++		file_ns_capable(file, ep->bus->domain->user_namespace,
++				CAP_IPC_OWNER);
++}
++
++/**
++ * kdbus_ep_is_owner() - check whether a file should be treated as bus owner
++ * @ep:		endpoint to operate on
++ * @file:	file to test
++ *
++ * Return: True if @file should be treated as bus owner on @ep
++ */
++bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file)
++{
++	return !ep->user &&
++		(uid_eq(file->f_cred->euid, ep->bus->node.uid) ||
++		 kdbus_ep_is_privileged(ep, file));
++}
++
++/**
++ * kdbus_cmd_ep_make() - handle KDBUS_CMD_ENDPOINT_MAKE
++ * @bus:		bus to operate on
++ * @argp:		command payload
++ *
++ * Return: NULL or newly created endpoint on success, ERR_PTR on failure.
++ */
++struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp)
++{
++	const char *item_make_name;
++	struct kdbus_ep *ep = NULL;
++	struct kdbus_cmd *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_MAKE_ACCESS_GROUP |
++				 KDBUS_MAKE_ACCESS_WORLD,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret < 0)
++		return ERR_PTR(ret);
++	if (ret > 0)
++		return NULL;
++
++	item_make_name = argv[1].item->str;
++
++	ep = kdbus_ep_new(bus, item_make_name, cmd->flags,
++			  current_euid(), current_egid(), true);
++	if (IS_ERR(ep)) {
++		ret = PTR_ERR(ep);
++		ep = NULL;
++		goto exit;
++	}
++
++	if (!kdbus_node_activate(&ep->node)) {
++		ret = -ESHUTDOWN;
++		goto exit;
++	}
++
++exit:
++	ret = kdbus_args_clear(&args, ret);
++	if (ret < 0) {
++		if (ep) {
++			kdbus_node_deactivate(&ep->node);
++			kdbus_ep_unref(ep);
++		}
++		return ERR_PTR(ret);
++	}
++	return ep;
++}
++
++/**
++ * kdbus_cmd_ep_update() - handle KDBUS_CMD_ENDPOINT_UPDATE
++ * @ep:			endpoint to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp)
++{
++	struct kdbus_cmd *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_NAME, .multiple = true },
++		{ .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	ret = kdbus_policy_set(&ep->policy_db, args.items, args.items_size,
++			       0, true, ep);
++	return kdbus_args_clear(&args, ret);
++}
+diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h
+new file mode 100644
+index 0000000..e0da59f
+--- /dev/null
++++ b/ipc/kdbus/endpoint.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_ENDPOINT_H
++#define __KDBUS_ENDPOINT_H
++
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/uidgid.h>
++#include "node.h"
++#include "policy.h"
++
++struct kdbus_bus;
++struct kdbus_user;
++
++/**
++ * struct kdbus_ep - endpoint to access a bus
++ * @node:		The kdbus node
++ * @lock:		Endpoint data lock
++ * @bus:		Bus behind this endpoint
++ * @user:		Custom enpoints account against an anonymous user
++ * @policy_db:		Uploaded policy
++ * @conn_list:		Connections of this endpoint
++ *
++ * An endpoint offers access to a bus; the default endpoint node name is "bus".
++ * Additional custom endpoints to the same bus can be created and they can
++ * carry their own policies/filters.
++ */
++struct kdbus_ep {
++	struct kdbus_node node;
++	struct mutex lock;
++
++	/* static */
++	struct kdbus_bus *bus;
++	struct kdbus_user *user;
++
++	/* protected by own locks */
++	struct kdbus_policy_db policy_db;
++
++	/* protected by ep->lock */
++	struct list_head conn_list;
++};
++
++#define kdbus_ep_from_node(_node) \
++	container_of((_node), struct kdbus_ep, node)
++
++struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name,
++			      unsigned int access, kuid_t uid, kgid_t gid,
++			      bool policy);
++struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep);
++struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep);
++
++bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file);
++bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file);
++
++struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp);
++int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp);
++
++#endif
+diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c
+new file mode 100644
+index 0000000..09c4809
+--- /dev/null
++++ b/ipc/kdbus/fs.c
+@@ -0,0 +1,508 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/dcache.h>
++#include <linux/fs.h>
++#include <linux/fsnotify.h>
++#include <linux/init.h>
++#include <linux/ipc_namespace.h>
++#include <linux/magic.h>
++#include <linux/module.h>
++#include <linux/mount.h>
++#include <linux/mutex.h>
++#include <linux/namei.h>
++#include <linux/pagemap.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++
++#include "bus.h"
++#include "domain.h"
++#include "endpoint.h"
++#include "fs.h"
++#include "handle.h"
++#include "node.h"
++
++#define kdbus_node_from_dentry(_dentry) \
++	((struct kdbus_node *)(_dentry)->d_fsdata)
++
++static struct inode *fs_inode_get(struct super_block *sb,
++				  struct kdbus_node *node);
++
++/*
++ * Directory Management
++ */
++
++static inline unsigned char kdbus_dt_type(struct kdbus_node *node)
++{
++	switch (node->type) {
++	case KDBUS_NODE_DOMAIN:
++	case KDBUS_NODE_BUS:
++		return DT_DIR;
++	case KDBUS_NODE_CONTROL:
++	case KDBUS_NODE_ENDPOINT:
++		return DT_REG;
++	}
++
++	return DT_UNKNOWN;
++}
++
++static int fs_dir_fop_iterate(struct file *file, struct dir_context *ctx)
++{
++	struct dentry *dentry = file->f_path.dentry;
++	struct kdbus_node *parent = kdbus_node_from_dentry(dentry);
++	struct kdbus_node *old, *next = file->private_data;
++
++	/*
++	 * kdbusfs directory iterator (modelled after sysfs/kernfs)
++	 * When iterating kdbusfs directories, we iterate all children of the
++	 * parent kdbus_node object. We use ctx->pos to store the hash of the
++	 * child and file->private_data to store a reference to the next node
++	 * object. If ctx->pos is not modified via llseek while you iterate a
++	 * directory, then we use the file->private_data node pointer to
++	 * directly access the next node in the tree.
++	 * However, if you directly seek on the directory, we have to find the
++	 * closest node to that position and cannot use our node pointer. This
++	 * means iterating the rb-tree to find the closest match and start over
++	 * from there.
++	 * Note that hash values are not necessarily unique. Therefore, llseek
++	 * is not guaranteed to seek to the same node that you got when you
++	 * retrieved the position. Seeking to 0, 1, 2 and >=INT_MAX is safe,
++	 * though. We could use the inode-number as position, but this would
++	 * require another rb-tree for fast access. Kernfs and others already
++	 * ignore those conflicts, so we should be fine, too.
++	 */
++
++	if (!dir_emit_dots(file, ctx))
++		return 0;
++
++	/* acquire @next; if deactivated, or seek detected, find next node */
++	old = next;
++	if (next && ctx->pos == next->hash) {
++		if (kdbus_node_acquire(next))
++			kdbus_node_ref(next);
++		else
++			next = kdbus_node_next_child(parent, next);
++	} else {
++		next = kdbus_node_find_closest(parent, ctx->pos);
++	}
++	kdbus_node_unref(old);
++
++	while (next) {
++		/* emit @next */
++		file->private_data = next;
++		ctx->pos = next->hash;
++
++		kdbus_node_release(next);
++
++		if (!dir_emit(ctx, next->name, strlen(next->name), next->id,
++			      kdbus_dt_type(next)))
++			return 0;
++
++		/* find next node after @next */
++		old = next;
++		next = kdbus_node_next_child(parent, next);
++		kdbus_node_unref(old);
++	}
++
++	file->private_data = NULL;
++	ctx->pos = INT_MAX;
++
++	return 0;
++}
++
++static loff_t fs_dir_fop_llseek(struct file *file, loff_t offset, int whence)
++{
++	struct inode *inode = file_inode(file);
++	loff_t ret;
++
++	/* protect f_off against fop_iterate */
++	mutex_lock(&inode->i_mutex);
++	ret = generic_file_llseek(file, offset, whence);
++	mutex_unlock(&inode->i_mutex);
++
++	return ret;
++}
++
++static int fs_dir_fop_release(struct inode *inode, struct file *file)
++{
++	kdbus_node_unref(file->private_data);
++	return 0;
++}
++
++static const struct file_operations fs_dir_fops = {
++	.read		= generic_read_dir,
++	.iterate	= fs_dir_fop_iterate,
++	.llseek		= fs_dir_fop_llseek,
++	.release	= fs_dir_fop_release,
++};
++
++static struct dentry *fs_dir_iop_lookup(struct inode *dir,
++					struct dentry *dentry,
++					unsigned int flags)
++{
++	struct dentry *dnew = NULL;
++	struct kdbus_node *parent;
++	struct kdbus_node *node;
++	struct inode *inode;
++
++	parent = kdbus_node_from_dentry(dentry->d_parent);
++	if (!kdbus_node_acquire(parent))
++		return NULL;
++
++	/* returns reference to _acquired_ child node */
++	node = kdbus_node_find_child(parent, dentry->d_name.name);
++	if (node) {
++		dentry->d_fsdata = node;
++		inode = fs_inode_get(dir->i_sb, node);
++		if (IS_ERR(inode))
++			dnew = ERR_CAST(inode);
++		else
++			dnew = d_splice_alias(inode, dentry);
++
++		kdbus_node_release(node);
++	}
++
++	kdbus_node_release(parent);
++	return dnew;
++}
++
++static const struct inode_operations fs_dir_iops = {
++	.permission	= generic_permission,
++	.lookup		= fs_dir_iop_lookup,
++};
++
++/*
++ * Inode Management
++ */
++
++static const struct inode_operations fs_inode_iops = {
++	.permission	= generic_permission,
++};
++
++static struct inode *fs_inode_get(struct super_block *sb,
++				  struct kdbus_node *node)
++{
++	struct inode *inode;
++
++	inode = iget_locked(sb, node->id);
++	if (!inode)
++		return ERR_PTR(-ENOMEM);
++	if (!(inode->i_state & I_NEW))
++		return inode;
++
++	inode->i_private = kdbus_node_ref(node);
++	inode->i_mapping->a_ops = &empty_aops;
++	inode->i_mode = node->mode & S_IALLUGO;
++	inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
++	inode->i_uid = node->uid;
++	inode->i_gid = node->gid;
++
++	switch (node->type) {
++	case KDBUS_NODE_DOMAIN:
++	case KDBUS_NODE_BUS:
++		inode->i_mode |= S_IFDIR;
++		inode->i_op = &fs_dir_iops;
++		inode->i_fop = &fs_dir_fops;
++		set_nlink(inode, 2);
++		break;
++	case KDBUS_NODE_CONTROL:
++	case KDBUS_NODE_ENDPOINT:
++		inode->i_mode |= S_IFREG;
++		inode->i_op = &fs_inode_iops;
++		inode->i_fop = &kdbus_handle_ops;
++		break;
++	}
++
++	unlock_new_inode(inode);
++
++	return inode;
++}
++
++/*
++ * Superblock Management
++ */
++
++static int fs_super_dop_revalidate(struct dentry *dentry, unsigned int flags)
++{
++	struct kdbus_node *node;
++
++	/* Force lookup on negatives */
++	if (!dentry->d_inode)
++		return 0;
++
++	node = kdbus_node_from_dentry(dentry);
++
++	/* see whether the node has been removed */
++	if (!kdbus_node_is_active(node))
++		return 0;
++
++	return 1;
++}
++
++static void fs_super_dop_release(struct dentry *dentry)
++{
++	kdbus_node_unref(dentry->d_fsdata);
++}
++
++static const struct dentry_operations fs_super_dops = {
++	.d_revalidate	= fs_super_dop_revalidate,
++	.d_release	= fs_super_dop_release,
++};
++
++static void fs_super_sop_evict_inode(struct inode *inode)
++{
++	struct kdbus_node *node = kdbus_node_from_inode(inode);
++
++	truncate_inode_pages_final(&inode->i_data);
++	clear_inode(inode);
++	kdbus_node_unref(node);
++}
++
++static const struct super_operations fs_super_sops = {
++	.statfs		= simple_statfs,
++	.drop_inode	= generic_delete_inode,
++	.evict_inode	= fs_super_sop_evict_inode,
++};
++
++static int fs_super_fill(struct super_block *sb)
++{
++	struct kdbus_domain *domain = sb->s_fs_info;
++	struct inode *inode;
++	int ret;
++
++	sb->s_blocksize = PAGE_CACHE_SIZE;
++	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
++	sb->s_magic = KDBUS_SUPER_MAGIC;
++	sb->s_maxbytes = MAX_LFS_FILESIZE;
++	sb->s_op = &fs_super_sops;
++	sb->s_time_gran = 1;
++
++	inode = fs_inode_get(sb, &domain->node);
++	if (IS_ERR(inode))
++		return PTR_ERR(inode);
++
++	sb->s_root = d_make_root(inode);
++	if (!sb->s_root) {
++		/* d_make_root iput()s the inode on failure */
++		return -ENOMEM;
++	}
++
++	/* sb holds domain reference */
++	sb->s_root->d_fsdata = &domain->node;
++	sb->s_d_op = &fs_super_dops;
++
++	/* sb holds root reference */
++	domain->dentry = sb->s_root;
++
++	if (!kdbus_node_activate(&domain->node))
++		return -ESHUTDOWN;
++
++	ret = kdbus_domain_populate(domain, KDBUS_MAKE_ACCESS_WORLD);
++	if (ret < 0)
++		return ret;
++
++	sb->s_flags |= MS_ACTIVE;
++	return 0;
++}
++
++static void fs_super_kill(struct super_block *sb)
++{
++	struct kdbus_domain *domain = sb->s_fs_info;
++
++	if (domain) {
++		kdbus_node_deactivate(&domain->node);
++		domain->dentry = NULL;
++	}
++
++	kill_anon_super(sb);
++	kdbus_domain_unref(domain);
++}
++
++static int fs_super_set(struct super_block *sb, void *data)
++{
++	int ret;
++
++	ret = set_anon_super(sb, data);
++	if (!ret)
++		sb->s_fs_info = data;
++
++	return ret;
++}
++
++static struct dentry *fs_super_mount(struct file_system_type *fs_type,
++				     int flags, const char *dev_name,
++				     void *data)
++{
++	struct kdbus_domain *domain;
++	struct super_block *sb;
++	int ret;
++
++	domain = kdbus_domain_new(KDBUS_MAKE_ACCESS_WORLD);
++	if (IS_ERR(domain))
++		return ERR_CAST(domain);
++
++	sb = sget(fs_type, NULL, fs_super_set, flags, domain);
++	if (IS_ERR(sb)) {
++		kdbus_node_deactivate(&domain->node);
++		kdbus_domain_unref(domain);
++		return ERR_CAST(sb);
++	}
++
++	WARN_ON(sb->s_fs_info != domain);
++	WARN_ON(sb->s_root);
++
++	ret = fs_super_fill(sb);
++	if (ret < 0) {
++		/* calls into ->kill_sb() when done */
++		deactivate_locked_super(sb);
++		return ERR_PTR(ret);
++	}
++
++	return dget(sb->s_root);
++}
++
++static struct file_system_type fs_type = {
++	.name		= KBUILD_MODNAME "fs",
++	.owner		= THIS_MODULE,
++	.mount		= fs_super_mount,
++	.kill_sb	= fs_super_kill,
++	.fs_flags	= FS_USERNS_MOUNT,
++};
++
++/**
++ * kdbus_fs_init() - register kdbus filesystem
++ *
++ * This registers a filesystem with the VFS layer. The filesystem is called
++ * `KBUILD_MODNAME "fs"', which usually resolves to `kdbusfs'. The nameing
++ * scheme allows to set KBUILD_MODNAME to "kdbus2" and you will get an
++ * independent filesystem for developers.
++ *
++ * Each mount of the kdbusfs filesystem has an kdbus_domain attached.
++ * Operations on this mount will only affect the attached domain. On each mount
++ * a new domain is automatically created and used for this mount exclusively.
++ * If you want to share a domain across multiple mounts, you need to bind-mount
++ * it.
++ *
++ * Mounts of kdbusfs (with a different domain each) are unrelated to each other
++ * and will never have any effect on any domain but their own.
++ *
++ * Return: 0 on success, negative error otherwise.
++ */
++int kdbus_fs_init(void)
++{
++	return register_filesystem(&fs_type);
++}
++
++/**
++ * kdbus_fs_exit() - unregister kdbus filesystem
++ *
++ * This does the reverse to kdbus_fs_init(). It unregisters the kdbusfs
++ * filesystem from VFS and cleans up any allocated resources.
++ */
++void kdbus_fs_exit(void)
++{
++	unregister_filesystem(&fs_type);
++}
++
++/* acquire domain of @node, making sure all ancestors are active */
++static struct kdbus_domain *fs_acquire_domain(struct kdbus_node *node)
++{
++	struct kdbus_domain *domain;
++	struct kdbus_node *iter;
++
++	/* caller must guarantee that @node is linked */
++	for (iter = node; iter->parent; iter = iter->parent)
++		if (!kdbus_node_is_active(iter->parent))
++			return NULL;
++
++	/* root nodes are always domains */
++	if (WARN_ON(iter->type != KDBUS_NODE_DOMAIN))
++		return NULL;
++
++	domain = kdbus_domain_from_node(iter);
++	if (!kdbus_node_acquire(&domain->node))
++		return NULL;
++
++	return domain;
++}
++
++/**
++ * kdbus_fs_flush() - flush dcache entries of a node
++ * @node:		Node to flush entries of
++ *
++ * This flushes all VFS filesystem cache entries for a node and all its
++ * children. This should be called whenever a node is destroyed during
++ * runtime. It will flush the cache entries so the linked objects can be
++ * deallocated.
++ *
++ * This is a no-op if you call it on active nodes (they really should stay in
++ * cache) or on nodes with deactivated parents (flushing the parent is enough).
++ * Furthermore, there is no need to call it on nodes whose lifetime is bound to
++ * their parents'. In those cases, the parent-flush will always also flush the
++ * children.
++ */
++void kdbus_fs_flush(struct kdbus_node *node)
++{
++	struct dentry *dentry, *parent_dentry = NULL;
++	struct kdbus_domain *domain;
++	struct qstr name;
++
++	/* active nodes should remain in cache */
++	if (!kdbus_node_is_deactivated(node))
++		return;
++
++	/* nodes that were never linked were never instantiated */
++	if (!node->parent)
++		return;
++
++	/* acquire domain and verify all ancestors are active */
++	domain = fs_acquire_domain(node);
++	if (!domain)
++		return;
++
++	switch (node->type) {
++	case KDBUS_NODE_ENDPOINT:
++		if (WARN_ON(!node->parent || !node->parent->name))
++			goto exit;
++
++		name.name = node->parent->name;
++		name.len = strlen(node->parent->name);
++		parent_dentry = d_hash_and_lookup(domain->dentry, &name);
++		if (IS_ERR_OR_NULL(parent_dentry))
++			goto exit;
++
++		/* fallthrough */
++	case KDBUS_NODE_BUS:
++		if (WARN_ON(!node->name))
++			goto exit;
++
++		name.name = node->name;
++		name.len = strlen(node->name);
++		dentry = d_hash_and_lookup(parent_dentry ? : domain->dentry,
++					   &name);
++		if (!IS_ERR_OR_NULL(dentry)) {
++			d_invalidate(dentry);
++			dput(dentry);
++		}
++
++		dput(parent_dentry);
++		break;
++
++	default:
++		/* all other types are bound to their parent lifetime */
++		break;
++	}
++
++exit:
++	kdbus_node_release(&domain->node);
++}
+diff --git a/ipc/kdbus/fs.h b/ipc/kdbus/fs.h
+new file mode 100644
+index 0000000..62f7d6a
+--- /dev/null
++++ b/ipc/kdbus/fs.h
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUSFS_H
++#define __KDBUSFS_H
++
++#include <linux/kernel.h>
++
++struct kdbus_node;
++
++int kdbus_fs_init(void);
++void kdbus_fs_exit(void);
++void kdbus_fs_flush(struct kdbus_node *node);
++
++#define kdbus_node_from_inode(_inode) \
++	((struct kdbus_node *)(_inode)->i_private)
++
++#endif
+diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c
+new file mode 100644
+index 0000000..fc60932
+--- /dev/null
++++ b/ipc/kdbus/handle.c
+@@ -0,0 +1,691 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/idr.h>
++#include <linux/init.h>
++#include <linux/kdev_t.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/poll.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/syscalls.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "endpoint.h"
++#include "fs.h"
++#include "handle.h"
++#include "item.h"
++#include "match.h"
++#include "message.h"
++#include "names.h"
++#include "domain.h"
++#include "policy.h"
++
++static int kdbus_args_verify(struct kdbus_args *args)
++{
++	struct kdbus_item *item;
++	size_t i;
++	int ret;
++
++	KDBUS_ITEMS_FOREACH(item, args->items, args->items_size) {
++		struct kdbus_arg *arg = NULL;
++
++		if (!KDBUS_ITEM_VALID(item, args->items, args->items_size))
++			return -EINVAL;
++
++		for (i = 0; i < args->argc; ++i)
++			if (args->argv[i].type == item->type)
++				break;
++		if (i >= args->argc)
++			return -EINVAL;
++
++		arg = &args->argv[i];
++
++		ret = kdbus_item_validate(item);
++		if (ret < 0)
++			return ret;
++
++		if (arg->item && !arg->multiple)
++			return -EINVAL;
++
++		arg->item = item;
++	}
++
++	if (!KDBUS_ITEMS_END(item, args->items, args->items_size))
++		return -EINVAL;
++
++	return 0;
++}
++
++static int kdbus_args_negotiate(struct kdbus_args *args)
++{
++	struct kdbus_item __user *user;
++	struct kdbus_item *negotiation;
++	size_t i, j, num;
++
++	/*
++	 * If KDBUS_FLAG_NEGOTIATE is set, we overwrite the flags field with
++	 * the set of supported flags. Furthermore, if an KDBUS_ITEM_NEGOTIATE
++	 * item is passed, we iterate its payload (array of u64, each set to an
++	 * item type) and clear all unsupported item-types to 0.
++	 * The caller might do this recursively, if other flags or objects are
++	 * embedded in the payload itself.
++	 */
++
++	if (args->cmd->flags & KDBUS_FLAG_NEGOTIATE) {
++		if (put_user(args->allowed_flags & ~KDBUS_FLAG_NEGOTIATE,
++			     &args->user->flags))
++			return -EFAULT;
++	}
++
++	if (args->argc < 1 || args->argv[0].type != KDBUS_ITEM_NEGOTIATE ||
++	    !args->argv[0].item)
++		return 0;
++
++	negotiation = args->argv[0].item;
++	user = (struct kdbus_item __user *)
++		((u8 __user *)args->user +
++		 ((u8 *)negotiation - (u8 *)args->cmd));
++	num = KDBUS_ITEM_PAYLOAD_SIZE(negotiation) / sizeof(u64);
++
++	for (i = 0; i < num; ++i) {
++		for (j = 0; j < args->argc; ++j)
++			if (negotiation->data64[i] == args->argv[j].type)
++				break;
++
++		if (j < args->argc)
++			continue;
++
++		/* this item is not supported, clear it out */
++		negotiation->data64[i] = 0;
++		if (put_user(negotiation->data64[i], &user->data64[i]))
++			return -EFAULT;
++	}
++
++	return 0;
++}
++
++/**
++ * __kdbus_args_parse() - parse payload of kdbus command
++ * @args:		object to parse data into
++ * @is_cmd:		whether this is a command or msg payload
++ * @argp:		user-space location of command payload to parse
++ * @type_size:		overall size of command payload to parse
++ * @items_offset:	offset of items array in command payload
++ * @out:		output variable to store pointer to copied payload
++ *
++ * This parses the ioctl payload at user-space location @argp into @args. @args
++ * must be pre-initialized by the caller to reflect the supported flags and
++ * items of this command. This parser will then copy the command payload into
++ * kernel-space, verify correctness and consistency and cache pointers to parsed
++ * items and other data in @args.
++ *
++ * If this function succeeded, you must call kdbus_args_clear() to release
++ * allocated resources before destroying @args.
++ *
++ * This can also be used to import kdbus_msg objects. In that case, @is_cmd must
++ * be set to 'false' and the 'return_flags' field will not be touched (as it
++ * doesn't exist on kdbus_msg).
++ *
++ * Return: On failure a negative error code is returned. Otherwise, 1 is
++ * returned if negotiation was requested, 0 if not.
++ */
++int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp,
++		       size_t type_size, size_t items_offset, void **out)
++{
++	u64 user_size;
++	int ret, i;
++
++	ret = kdbus_copy_from_user(&user_size, argp, sizeof(user_size));
++	if (ret < 0)
++		return ret;
++
++	if (user_size < type_size)
++		return -EINVAL;
++	if (user_size > KDBUS_CMD_MAX_SIZE)
++		return -EMSGSIZE;
++
++	if (user_size <= sizeof(args->cmd_buf)) {
++		if (copy_from_user(args->cmd_buf, argp, user_size))
++			return -EFAULT;
++		args->cmd = (void*)args->cmd_buf;
++	} else {
++		args->cmd = memdup_user(argp, user_size);
++		if (IS_ERR(args->cmd))
++			return PTR_ERR(args->cmd);
++	}
++
++	if (args->cmd->size != user_size) {
++		ret = -EINVAL;
++		goto error;
++	}
++
++	if (is_cmd)
++		args->cmd->return_flags = 0;
++	args->user = argp;
++	args->items = (void *)((u8 *)args->cmd + items_offset);
++	args->items_size = args->cmd->size - items_offset;
++	args->is_cmd = is_cmd;
++
++	if (args->cmd->flags & ~args->allowed_flags) {
++		ret = -EINVAL;
++		goto error;
++	}
++
++	ret = kdbus_args_verify(args);
++	if (ret < 0)
++		goto error;
++
++	ret = kdbus_args_negotiate(args);
++	if (ret < 0)
++		goto error;
++
++	/* mandatory items must be given (but not on negotiation) */
++	if (!(args->cmd->flags & KDBUS_FLAG_NEGOTIATE)) {
++		for (i = 0; i < args->argc; ++i)
++			if (args->argv[i].mandatory && !args->argv[i].item) {
++				ret = -EINVAL;
++				goto error;
++			}
++	}
++
++	*out = args->cmd;
++	return !!(args->cmd->flags & KDBUS_FLAG_NEGOTIATE);
++
++error:
++	return kdbus_args_clear(args, ret);
++}
++
++/**
++ * kdbus_args_clear() - release allocated command resources
++ * @args:	object to release resources of
++ * @ret:	return value of this command
++ *
++ * This frees all allocated resources on @args and copies the command result
++ * flags into user-space. @ret is usually returned unchanged by this function,
++ * so it can be used in the final 'return' statement of the command handler.
++ *
++ * Return: -EFAULT if return values cannot be copied into user-space, otherwise
++ *         @ret is returned unchanged.
++ */
++int kdbus_args_clear(struct kdbus_args *args, int ret)
++{
++	if (!args)
++		return ret;
++
++	if (!IS_ERR_OR_NULL(args->cmd)) {
++		if (args->is_cmd && put_user(args->cmd->return_flags,
++					     &args->user->return_flags))
++			ret = -EFAULT;
++		if (args->cmd != (void*)args->cmd_buf)
++			kfree(args->cmd);
++		args->cmd = NULL;
++	}
++
++	return ret;
++}
++
++/**
++ * enum kdbus_handle_type - type an handle can be of
++ * @KDBUS_HANDLE_NONE:		no type set, yet
++ * @KDBUS_HANDLE_BUS_OWNER:	bus owner
++ * @KDBUS_HANDLE_EP_OWNER:	endpoint owner
++ * @KDBUS_HANDLE_CONNECTED:	endpoint connection after HELLO
++ */
++enum kdbus_handle_type {
++	KDBUS_HANDLE_NONE,
++	KDBUS_HANDLE_BUS_OWNER,
++	KDBUS_HANDLE_EP_OWNER,
++	KDBUS_HANDLE_CONNECTED,
++};
++
++/**
++ * struct kdbus_handle - handle to the kdbus system
++ * @lock:		handle lock
++ * @type:		type of this handle (KDBUS_HANDLE_*)
++ * @bus_owner:		bus this handle owns
++ * @ep_owner:		endpoint this handle owns
++ * @conn:		connection this handle owns
++ */
++struct kdbus_handle {
++	struct mutex lock;
++
++	enum kdbus_handle_type type;
++	union {
++		struct kdbus_bus *bus_owner;
++		struct kdbus_ep *ep_owner;
++		struct kdbus_conn *conn;
++	};
++};
++
++static int kdbus_handle_open(struct inode *inode, struct file *file)
++{
++	struct kdbus_handle *handle;
++	struct kdbus_node *node;
++	int ret;
++
++	node = kdbus_node_from_inode(inode);
++	if (!kdbus_node_acquire(node))
++		return -ESHUTDOWN;
++
++	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
++	if (!handle) {
++		ret = -ENOMEM;
++		goto exit;
++	}
++
++	mutex_init(&handle->lock);
++	handle->type = KDBUS_HANDLE_NONE;
++
++	file->private_data = handle;
++	ret = 0;
++
++exit:
++	kdbus_node_release(node);
++	return ret;
++}
++
++static int kdbus_handle_release(struct inode *inode, struct file *file)
++{
++	struct kdbus_handle *handle = file->private_data;
++
++	switch (handle->type) {
++	case KDBUS_HANDLE_BUS_OWNER:
++		if (handle->bus_owner) {
++			kdbus_node_deactivate(&handle->bus_owner->node);
++			kdbus_bus_unref(handle->bus_owner);
++		}
++		break;
++	case KDBUS_HANDLE_EP_OWNER:
++		if (handle->ep_owner) {
++			kdbus_node_deactivate(&handle->ep_owner->node);
++			kdbus_ep_unref(handle->ep_owner);
++		}
++		break;
++	case KDBUS_HANDLE_CONNECTED:
++		kdbus_conn_disconnect(handle->conn, false);
++		kdbus_conn_unref(handle->conn);
++		break;
++	case KDBUS_HANDLE_NONE:
++		/* nothing to clean up */
++		break;
++	}
++
++	kfree(handle);
++
++	return 0;
++}
++
++static long kdbus_handle_ioctl_control(struct file *file, unsigned int cmd,
++				       void __user *argp)
++{
++	struct kdbus_handle *handle = file->private_data;
++	struct kdbus_node *node = file_inode(file)->i_private;
++	struct kdbus_domain *domain;
++	int ret = 0;
++
++	if (!kdbus_node_acquire(node))
++		return -ESHUTDOWN;
++
++	/*
++	 * The parent of control-nodes is always a domain, make sure to pin it
++	 * so the parent is actually valid.
++	 */
++	domain = kdbus_domain_from_node(node->parent);
++	if (!kdbus_node_acquire(&domain->node)) {
++		kdbus_node_release(node);
++		return -ESHUTDOWN;
++	}
++
++	switch (cmd) {
++	case KDBUS_CMD_BUS_MAKE: {
++		struct kdbus_bus *bus;
++
++		bus = kdbus_cmd_bus_make(domain, argp);
++		if (IS_ERR_OR_NULL(bus)) {
++			ret = PTR_ERR_OR_ZERO(bus);
++			break;
++		}
++
++		handle->bus_owner = bus;
++		ret = KDBUS_HANDLE_BUS_OWNER;
++		break;
++	}
++
++	default:
++		ret = -EBADFD;
++		break;
++	}
++
++	kdbus_node_release(&domain->node);
++	kdbus_node_release(node);
++	return ret;
++}
++
++static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
++				  void __user *buf)
++{
++	struct kdbus_handle *handle = file->private_data;
++	struct kdbus_node *node = file_inode(file)->i_private;
++	struct kdbus_ep *ep, *file_ep = kdbus_ep_from_node(node);
++	struct kdbus_bus *bus = file_ep->bus;
++	struct kdbus_conn *conn;
++	int ret = 0;
++
++	if (!kdbus_node_acquire(node))
++		return -ESHUTDOWN;
++
++	switch (cmd) {
++	case KDBUS_CMD_ENDPOINT_MAKE: {
++		/* creating custom endpoints is a privileged operation */
++		if (!kdbus_ep_is_owner(file_ep, file)) {
++			ret = -EPERM;
++			break;
++		}
++
++		ep = kdbus_cmd_ep_make(bus, buf);
++		if (IS_ERR_OR_NULL(ep)) {
++			ret = PTR_ERR_OR_ZERO(ep);
++			break;
++		}
++
++		handle->ep_owner = ep;
++		ret = KDBUS_HANDLE_EP_OWNER;
++		break;
++	}
++
++	case KDBUS_CMD_HELLO:
++		conn = kdbus_cmd_hello(file_ep, file, buf);
++		if (IS_ERR_OR_NULL(conn)) {
++			ret = PTR_ERR_OR_ZERO(conn);
++			break;
++		}
++
++		handle->conn = conn;
++		ret = KDBUS_HANDLE_CONNECTED;
++		break;
++
++	default:
++		ret = -EBADFD;
++		break;
++	}
++
++	kdbus_node_release(node);
++	return ret;
++}
++
++static long kdbus_handle_ioctl_ep_owner(struct file *file, unsigned int command,
++					void __user *buf)
++{
++	struct kdbus_handle *handle = file->private_data;
++	struct kdbus_ep *ep = handle->ep_owner;
++	int ret;
++
++	if (!kdbus_node_acquire(&ep->node))
++		return -ESHUTDOWN;
++
++	switch (command) {
++	case KDBUS_CMD_ENDPOINT_UPDATE:
++		ret = kdbus_cmd_ep_update(ep, buf);
++		break;
++	default:
++		ret = -EBADFD;
++		break;
++	}
++
++	kdbus_node_release(&ep->node);
++	return ret;
++}
++
++static long kdbus_handle_ioctl_connected(struct file *file,
++					 unsigned int command, void __user *buf)
++{
++	struct kdbus_handle *handle = file->private_data;
++	struct kdbus_conn *conn = handle->conn;
++	struct kdbus_conn *release_conn = NULL;
++	int ret;
++
++	release_conn = conn;
++	ret = kdbus_conn_acquire(release_conn);
++	if (ret < 0)
++		return ret;
++
++	switch (command) {
++	case KDBUS_CMD_BYEBYE:
++		/*
++		 * BYEBYE is special; we must not acquire a connection when
++		 * calling into kdbus_conn_disconnect() or we will deadlock,
++		 * because kdbus_conn_disconnect() will wait for all acquired
++		 * references to be dropped.
++		 */
++		kdbus_conn_release(release_conn);
++		release_conn = NULL;
++		ret = kdbus_cmd_byebye_unlocked(conn, buf);
++		break;
++	case KDBUS_CMD_NAME_ACQUIRE:
++		ret = kdbus_cmd_name_acquire(conn, buf);
++		break;
++	case KDBUS_CMD_NAME_RELEASE:
++		ret = kdbus_cmd_name_release(conn, buf);
++		break;
++	case KDBUS_CMD_LIST:
++		ret = kdbus_cmd_list(conn, buf);
++		break;
++	case KDBUS_CMD_CONN_INFO:
++		ret = kdbus_cmd_conn_info(conn, buf);
++		break;
++	case KDBUS_CMD_BUS_CREATOR_INFO:
++		ret = kdbus_cmd_bus_creator_info(conn, buf);
++		break;
++	case KDBUS_CMD_UPDATE:
++		ret = kdbus_cmd_update(conn, buf);
++		break;
++	case KDBUS_CMD_MATCH_ADD:
++		ret = kdbus_cmd_match_add(conn, buf);
++		break;
++	case KDBUS_CMD_MATCH_REMOVE:
++		ret = kdbus_cmd_match_remove(conn, buf);
++		break;
++	case KDBUS_CMD_SEND:
++		ret = kdbus_cmd_send(conn, file, buf);
++		break;
++	case KDBUS_CMD_RECV:
++		ret = kdbus_cmd_recv(conn, buf);
++		break;
++	case KDBUS_CMD_FREE:
++		ret = kdbus_cmd_free(conn, buf);
++		break;
++	default:
++		ret = -EBADFD;
++		break;
++	}
++
++	kdbus_conn_release(release_conn);
++	return ret;
++}
++
++static long kdbus_handle_ioctl(struct file *file, unsigned int cmd,
++			       unsigned long arg)
++{
++	struct kdbus_handle *handle = file->private_data;
++	struct kdbus_node *node = kdbus_node_from_inode(file_inode(file));
++	void __user *argp = (void __user *)arg;
++	long ret = -EBADFD;
++
++	switch (cmd) {
++	case KDBUS_CMD_BUS_MAKE:
++	case KDBUS_CMD_ENDPOINT_MAKE:
++	case KDBUS_CMD_HELLO:
++		mutex_lock(&handle->lock);
++		if (handle->type == KDBUS_HANDLE_NONE) {
++			if (node->type == KDBUS_NODE_CONTROL)
++				ret = kdbus_handle_ioctl_control(file, cmd,
++								 argp);
++			else if (node->type == KDBUS_NODE_ENDPOINT)
++				ret = kdbus_handle_ioctl_ep(file, cmd, argp);
++
++			if (ret > 0) {
++				/*
++				 * The data given via open() is not sufficient
++				 * to setup a kdbus handle. Hence, we require
++				 * the user to perform a setup ioctl. This setup
++				 * can only be performed once and defines the
++				 * type of the handle. The different setup
++				 * ioctls are locked against each other so they
++				 * cannot race. Once the handle type is set,
++				 * the type-dependent ioctls are enabled. To
++				 * improve performance, we don't lock those via
++				 * handle->lock. Instead, we issue a
++				 * write-barrier before performing the
++				 * type-change, which pairs with smp_rmb() in
++				 * all handlers that access the type field. This
++				 * guarantees the handle is fully setup, if
++				 * handle->type is set. If handle->type is
++				 * unset, you must not make any assumptions
++				 * without taking handle->lock.
++				 * Note that handle->type is only set once. It
++				 * will never change afterwards.
++				 */
++				smp_wmb();
++				handle->type = ret;
++			}
++		}
++		mutex_unlock(&handle->lock);
++		break;
++
++	case KDBUS_CMD_ENDPOINT_UPDATE:
++	case KDBUS_CMD_BYEBYE:
++	case KDBUS_CMD_NAME_ACQUIRE:
++	case KDBUS_CMD_NAME_RELEASE:
++	case KDBUS_CMD_LIST:
++	case KDBUS_CMD_CONN_INFO:
++	case KDBUS_CMD_BUS_CREATOR_INFO:
++	case KDBUS_CMD_UPDATE:
++	case KDBUS_CMD_MATCH_ADD:
++	case KDBUS_CMD_MATCH_REMOVE:
++	case KDBUS_CMD_SEND:
++	case KDBUS_CMD_RECV:
++	case KDBUS_CMD_FREE: {
++		enum kdbus_handle_type type;
++
++		/*
++		 * This read-barrier pairs with smp_wmb() of the handle setup.
++		 * it guarantees the handle is fully written, in case the
++		 * type has been set. It allows us to access the handle without
++		 * taking handle->lock, given the guarantee that the type is
++		 * only ever set once, and stays constant afterwards.
++		 * Furthermore, the handle object itself is not modified in any
++		 * way after the type is set. That is, the type-field is the
++		 * last field that is written on any handle. If it has not been
++		 * set, we must not access the handle here.
++		 */
++		type = handle->type;
++		smp_rmb();
++
++		if (type == KDBUS_HANDLE_EP_OWNER)
++			ret = kdbus_handle_ioctl_ep_owner(file, cmd, argp);
++		else if (type == KDBUS_HANDLE_CONNECTED)
++			ret = kdbus_handle_ioctl_connected(file, cmd, argp);
++
++		break;
++	}
++	default:
++		ret = -ENOTTY;
++		break;
++	}
++
++	return ret < 0 ? ret : 0;
++}
++
++static unsigned int kdbus_handle_poll(struct file *file,
++				      struct poll_table_struct *wait)
++{
++	struct kdbus_handle *handle = file->private_data;
++	enum kdbus_handle_type type;
++	unsigned int mask = POLLOUT | POLLWRNORM;
++
++	/*
++	 * This pairs with smp_wmb() during handle setup. It guarantees that
++	 * _iff_ the handle type is set, handle->conn is valid. Furthermore,
++	 * _iff_ the type is set, the handle object is constant and never
++	 * changed again. If it's not set, we must not access the handle but
++	 * bail out. We also must assume no setup has taken place, yet.
++	 */
++	type = handle->type;
++	smp_rmb();
++
++	/* Only a connected endpoint can read/write data */
++	if (type != KDBUS_HANDLE_CONNECTED)
++		return POLLERR | POLLHUP;
++
++	poll_wait(file, &handle->conn->wait, wait);
++
++	/*
++	 * Verify the connection hasn't been deactivated _after_ adding the
++	 * wait-queue. This guarantees, that if the connection is deactivated
++	 * after we checked it, the waitqueue is signaled and we're called
++	 * again.
++	 */
++	if (!kdbus_conn_active(handle->conn))
++		return POLLERR | POLLHUP;
++
++	if (!list_empty(&handle->conn->queue.msg_list) ||
++	    atomic_read(&handle->conn->lost_count) > 0)
++		mask |= POLLIN | POLLRDNORM;
++
++	return mask;
++}
++
++static int kdbus_handle_mmap(struct file *file, struct vm_area_struct *vma)
++{
++	struct kdbus_handle *handle = file->private_data;
++	enum kdbus_handle_type type;
++	int ret = -EBADFD;
++
++	/*
++	 * This pairs with smp_wmb() during handle setup. It guarantees that
++	 * _iff_ the handle type is set, handle->conn is valid. Furthermore,
++	 * _iff_ the type is set, the handle object is constant and never
++	 * changed again. If it's not set, we must not access the handle but
++	 * bail out. We also must assume no setup has taken place, yet.
++	 */
++	type = handle->type;
++	smp_rmb();
++
++	/* Only connected handles have a pool we can map */
++	if (type == KDBUS_HANDLE_CONNECTED)
++		ret = kdbus_pool_mmap(handle->conn->pool, vma);
++
++	return ret;
++}
++
++const struct file_operations kdbus_handle_ops = {
++	.owner =		THIS_MODULE,
++	.open =			kdbus_handle_open,
++	.release =		kdbus_handle_release,
++	.poll =			kdbus_handle_poll,
++	.llseek =		noop_llseek,
++	.unlocked_ioctl =	kdbus_handle_ioctl,
++	.mmap =			kdbus_handle_mmap,
++#ifdef CONFIG_COMPAT
++	.compat_ioctl =		kdbus_handle_ioctl,
++#endif
++};
+diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h
+new file mode 100644
+index 0000000..5dde2c1
+--- /dev/null
++++ b/ipc/kdbus/handle.h
+@@ -0,0 +1,103 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_HANDLE_H
++#define __KDBUS_HANDLE_H
++
++#include <linux/fs.h>
++#include <uapi/linux/kdbus.h>
++
++extern const struct file_operations kdbus_handle_ops;
++
++/**
++ * kdbus_arg - information and state of a single ioctl command item
++ * @type:		item type
++ * @item:		set by the parser to the first found item of this type
++ * @multiple:		whether multiple items of this type are allowed
++ * @mandatory:		whether at least one item of this type is required
++ *
++ * This structure describes a single item in an ioctl command payload. The
++ * caller has to pre-fill the type and flags, the parser will then use this
++ * information to verify the ioctl payload. @item is set by the parser to point
++ * to the first occurrence of the item.
++ */
++struct kdbus_arg {
++	u64 type;
++	struct kdbus_item *item;
++	bool multiple : 1;
++	bool mandatory : 1;
++};
++
++/**
++ * kdbus_args - information and state of ioctl command parser
++ * @allowed_flags:	set of flags this command supports
++ * @argc:		number of items in @argv
++ * @argv:		array of items this command supports
++ * @user:		set by parser to user-space location of current command
++ * @cmd:		set by parser to kernel copy of command payload
++ * @cmd_buf:		inline buf to avoid kmalloc() on small cmds
++ * @items:		points to item array in @cmd
++ * @items_size:		size of @items in bytes
++ * @is_cmd:		whether this is a command-payload or msg-payload
++ *
++ * This structure is used to parse ioctl command payloads on each invocation.
++ * The ioctl handler has to pre-fill the flags and allowed items before passing
++ * the object to kdbus_args_parse(). The parser will copy the command payload
++ * into kernel-space and verify the correctness of the data.
++ *
++ * We use a 256 bytes buffer for small command payloads, to be allocated on
++ * stack on syscall entrance.
++ */
++struct kdbus_args {
++	u64 allowed_flags;
++	size_t argc;
++	struct kdbus_arg *argv;
++
++	struct kdbus_cmd __user *user;
++	struct kdbus_cmd *cmd;
++	u8 cmd_buf[256];
++
++	struct kdbus_item *items;
++	size_t items_size;
++	bool is_cmd : 1;
++};
++
++int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp,
++		       size_t type_size, size_t items_offset, void **out);
++int kdbus_args_clear(struct kdbus_args *args, int ret);
++
++#define kdbus_args_parse(_args, _argp, _v)                              \
++	({                                                              \
++		BUILD_BUG_ON(offsetof(typeof(**(_v)), size) !=          \
++			     offsetof(struct kdbus_cmd, size));         \
++		BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) !=         \
++			     offsetof(struct kdbus_cmd, flags));        \
++		BUILD_BUG_ON(offsetof(typeof(**(_v)), return_flags) !=  \
++			     offsetof(struct kdbus_cmd, return_flags)); \
++		__kdbus_args_parse((_args), 1, (_argp), sizeof(**(_v)), \
++				   offsetof(typeof(**(_v)), items),     \
++				   (void **)(_v));                      \
++	})
++
++#define kdbus_args_parse_msg(_args, _argp, _v)                          \
++	({                                                              \
++		BUILD_BUG_ON(offsetof(typeof(**(_v)), size) !=          \
++			     offsetof(struct kdbus_cmd, size));         \
++		BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) !=         \
++			     offsetof(struct kdbus_cmd, flags));        \
++		__kdbus_args_parse((_args), 0, (_argp), sizeof(**(_v)), \
++				   offsetof(typeof(**(_v)), items),     \
++				   (void **)(_v));                      \
++	})
++
++#endif
+diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c
+new file mode 100644
+index 0000000..ce78dba
+--- /dev/null
++++ b/ipc/kdbus/item.c
+@@ -0,0 +1,293 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/ctype.h>
++#include <linux/fs.h>
++#include <linux/string.h>
++
++#include "item.h"
++#include "limits.h"
++#include "util.h"
++
++/*
++ * This verifies the string at position @str with size @size is properly
++ * zero-terminated and does not contain a 0-byte but at the end.
++ */
++static bool kdbus_str_valid(const char *str, size_t size)
++{
++	return size > 0 && memchr(str, '\0', size) == str + size - 1;
++}
++
++/**
++ * kdbus_item_validate_name() - validate an item containing a name
++ * @item:		Item to validate
++ *
++ * Return: zero on success or an negative error code on failure
++ */
++int kdbus_item_validate_name(const struct kdbus_item *item)
++{
++	const char *name = item->str;
++	unsigned int i;
++	size_t len;
++
++	if (item->size < KDBUS_ITEM_HEADER_SIZE + 2)
++		return -EINVAL;
++
++	if (item->size > KDBUS_ITEM_HEADER_SIZE +
++			 KDBUS_SYSNAME_MAX_LEN + 1)
++		return -ENAMETOOLONG;
++
++	if (!kdbus_str_valid(name, KDBUS_ITEM_PAYLOAD_SIZE(item)))
++		return -EINVAL;
++
++	len = strlen(name);
++	if (len == 0)
++		return -EINVAL;
++
++	for (i = 0; i < len; i++) {
++		if (isalpha(name[i]))
++			continue;
++		if (isdigit(name[i]))
++			continue;
++		if (name[i] == '_')
++			continue;
++		if (i > 0 && i + 1 < len && (name[i] == '-' || name[i] == '.'))
++			continue;
++
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++/**
++ * kdbus_item_validate() - validate a single item
++ * @item:	item to validate
++ *
++ * Return: 0 if item is valid, negative error code if not.
++ */
++int kdbus_item_validate(const struct kdbus_item *item)
++{
++	size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item);
++	size_t l;
++	int ret;
++
++	BUILD_BUG_ON(KDBUS_ITEM_HEADER_SIZE !=
++		     sizeof(struct kdbus_item_header));
++
++	if (item->size < KDBUS_ITEM_HEADER_SIZE)
++		return -EINVAL;
++
++	switch (item->type) {
++	case KDBUS_ITEM_NEGOTIATE:
++		if (payload_size % sizeof(u64) != 0)
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_PAYLOAD_VEC:
++	case KDBUS_ITEM_PAYLOAD_OFF:
++		if (payload_size != sizeof(struct kdbus_vec))
++			return -EINVAL;
++		if (item->vec.size == 0 || item->vec.size > SIZE_MAX)
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_PAYLOAD_MEMFD:
++		if (payload_size != sizeof(struct kdbus_memfd))
++			return -EINVAL;
++		if (item->memfd.size == 0 || item->memfd.size > SIZE_MAX)
++			return -EINVAL;
++		if (item->memfd.fd < 0)
++			return -EBADF;
++		break;
++
++	case KDBUS_ITEM_FDS:
++		if (payload_size % sizeof(int) != 0)
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_CANCEL_FD:
++		if (payload_size != sizeof(int))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_BLOOM_PARAMETER:
++		if (payload_size != sizeof(struct kdbus_bloom_parameter))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_BLOOM_FILTER:
++		/* followed by the bloom-mask, depends on the bloom-size */
++		if (payload_size < sizeof(struct kdbus_bloom_filter))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_BLOOM_MASK:
++		/* size depends on bloom-size of bus */
++		break;
++
++	case KDBUS_ITEM_CONN_DESCRIPTION:
++	case KDBUS_ITEM_MAKE_NAME:
++		ret = kdbus_item_validate_name(item);
++		if (ret < 0)
++			return ret;
++		break;
++
++	case KDBUS_ITEM_ATTACH_FLAGS_SEND:
++	case KDBUS_ITEM_ATTACH_FLAGS_RECV:
++	case KDBUS_ITEM_ID:
++	case KDBUS_ITEM_DST_ID:
++		if (payload_size != sizeof(u64))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_TIMESTAMP:
++		if (payload_size != sizeof(struct kdbus_timestamp))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_CREDS:
++		if (payload_size != sizeof(struct kdbus_creds))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_AUXGROUPS:
++		if (payload_size % sizeof(u32) != 0)
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_NAME:
++	case KDBUS_ITEM_DST_NAME:
++	case KDBUS_ITEM_PID_COMM:
++	case KDBUS_ITEM_TID_COMM:
++	case KDBUS_ITEM_EXE:
++	case KDBUS_ITEM_CMDLINE:
++	case KDBUS_ITEM_CGROUP:
++	case KDBUS_ITEM_SECLABEL:
++		if (!kdbus_str_valid(item->str, payload_size))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_CAPS:
++		if (payload_size < sizeof(u32))
++			return -EINVAL;
++		if (payload_size < sizeof(u32) +
++		    4 * CAP_TO_INDEX(item->caps.last_cap) * sizeof(u32))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_AUDIT:
++		if (payload_size != sizeof(struct kdbus_audit))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_POLICY_ACCESS:
++		if (payload_size != sizeof(struct kdbus_policy_access))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_NAME_ADD:
++	case KDBUS_ITEM_NAME_REMOVE:
++	case KDBUS_ITEM_NAME_CHANGE:
++		if (payload_size < sizeof(struct kdbus_notify_name_change))
++			return -EINVAL;
++		l = payload_size - offsetof(struct kdbus_notify_name_change,
++					    name);
++		if (l > 0 && !kdbus_str_valid(item->name_change.name, l))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_ID_ADD:
++	case KDBUS_ITEM_ID_REMOVE:
++		if (payload_size != sizeof(struct kdbus_notify_id_change))
++			return -EINVAL;
++		break;
++
++	case KDBUS_ITEM_REPLY_TIMEOUT:
++	case KDBUS_ITEM_REPLY_DEAD:
++		if (payload_size != 0)
++			return -EINVAL;
++		break;
++
++	default:
++		break;
++	}
++
++	return 0;
++}
++
++/**
++ * kdbus_items_validate() - validate items passed by user-space
++ * @items:		items to validate
++ * @items_size:		number of items
++ *
++ * This verifies that the passed items pointer is consistent and valid.
++ * Furthermore, each item is checked for:
++ *  - valid "size" value
++ *  - payload is of expected type
++ *  - payload is fully included in the item
++ *  - string payloads are zero-terminated
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_items_validate(const struct kdbus_item *items, size_t items_size)
++{
++	const struct kdbus_item *item;
++	int ret;
++
++	KDBUS_ITEMS_FOREACH(item, items, items_size) {
++		if (!KDBUS_ITEM_VALID(item, items, items_size))
++			return -EINVAL;
++
++		ret = kdbus_item_validate(item);
++		if (ret < 0)
++			return ret;
++	}
++
++	if (!KDBUS_ITEMS_END(item, items, items_size))
++		return -EINVAL;
++
++	return 0;
++}
++
++/**
++ * kdbus_item_set() - Set item content
++ * @item:	The item to modify
++ * @type:	The item type to set (KDBUS_ITEM_*)
++ * @data:	Data to copy to item->data, may be %NULL
++ * @len:	Number of bytes in @data
++ *
++ * This sets type, size and data fields of an item. If @data is NULL, the data
++ * memory is cleared.
++ *
++ * Note that you must align your @data memory to 8 bytes. Trailing padding (in
++ * case @len is not 8byte aligned) is cleared by this call.
++ *
++ * Returns: Pointer to the following item.
++ */
++struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type,
++				  const void *data, size_t len)
++{
++	item->type = type;
++	item->size = KDBUS_ITEM_HEADER_SIZE + len;
++
++	if (data) {
++		memcpy(item->data, data, len);
++		memset(item->data + len, 0, KDBUS_ALIGN8(len) - len);
++	} else {
++		memset(item->data, 0, KDBUS_ALIGN8(len));
++	}
++
++	return KDBUS_ITEM_NEXT(item);
++}
+diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h
+new file mode 100644
+index 0000000..3a7e6cc
+--- /dev/null
++++ b/ipc/kdbus/item.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_ITEM_H
++#define __KDBUS_ITEM_H
++
++#include <linux/kernel.h>
++#include <uapi/linux/kdbus.h>
++
++#include "util.h"
++
++/* generic access and iterators over a stream of items */
++#define KDBUS_ITEM_NEXT(_i) (typeof(_i))((u8 *)(_i) + KDBUS_ALIGN8((_i)->size))
++#define KDBUS_ITEMS_SIZE(_h, _is) ((_h)->size - offsetof(typeof(*(_h)), _is))
++#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
++#define KDBUS_ITEM_SIZE(_s) KDBUS_ALIGN8(KDBUS_ITEM_HEADER_SIZE + (_s))
++#define KDBUS_ITEM_PAYLOAD_SIZE(_i) ((_i)->size - KDBUS_ITEM_HEADER_SIZE)
++
++#define KDBUS_ITEMS_FOREACH(_i, _is, _s)				\
++	for ((_i) = (_is);						\
++	     ((u8 *)(_i) < (u8 *)(_is) + (_s)) &&			\
++	       ((u8 *)(_i) >= (u8 *)(_is));				\
++	     (_i) = KDBUS_ITEM_NEXT(_i))
++
++#define KDBUS_ITEM_VALID(_i, _is, _s)					\
++	((_i)->size >= KDBUS_ITEM_HEADER_SIZE &&			\
++	 (u8 *)(_i) + (_i)->size > (u8 *)(_i) &&			\
++	 (u8 *)(_i) + (_i)->size <= (u8 *)(_is) + (_s) &&		\
++	 (u8 *)(_i) >= (u8 *)(_is))
++
++#define KDBUS_ITEMS_END(_i, _is, _s)					\
++	((u8 *)(_i) == ((u8 *)(_is) + KDBUS_ALIGN8(_s)))
++
++/**
++ * struct kdbus_item_header - Describes the fix part of an item
++ * @size:	The total size of the item
++ * @type:	The item type, one of KDBUS_ITEM_*
++ */
++struct kdbus_item_header {
++	u64 size;
++	u64 type;
++};
++
++int kdbus_item_validate_name(const struct kdbus_item *item);
++int kdbus_item_validate(const struct kdbus_item *item);
++int kdbus_items_validate(const struct kdbus_item *items, size_t items_size);
++struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type,
++				  const void *data, size_t len);
++
++#endif
+diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h
+new file mode 100644
+index 0000000..c54925a
+--- /dev/null
++++ b/ipc/kdbus/limits.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_DEFAULTS_H
++#define __KDBUS_DEFAULTS_H
++
++#include <linux/kernel.h>
++
++/* maximum size of message header and items */
++#define KDBUS_MSG_MAX_SIZE		SZ_8K
++
++/* maximum number of memfd items per message */
++#define KDBUS_MSG_MAX_MEMFD_ITEMS	16
++
++/* max size of ioctl command data */
++#define KDBUS_CMD_MAX_SIZE		SZ_32K
++
++/* maximum number of inflight fds in a target queue per user */
++#define KDBUS_CONN_MAX_FDS_PER_USER	16
++
++/* maximum message payload size */
++#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE		SZ_2M
++
++/* maximum size of bloom bit field in bytes */
++#define KDBUS_BUS_BLOOM_MAX_SIZE		SZ_4K
++
++/* maximum length of well-known bus name */
++#define KDBUS_NAME_MAX_LEN			255
++
++/* maximum length of bus, domain, ep name */
++#define KDBUS_SYSNAME_MAX_LEN			63
++
++/* maximum number of matches per connection */
++#define KDBUS_MATCH_MAX				256
++
++/* maximum number of queued messages from the same individual user */
++#define KDBUS_CONN_MAX_MSGS			256
++
++/* maximum number of well-known names per connection */
++#define KDBUS_CONN_MAX_NAMES			256
++
++/* maximum number of queued requests waiting for a reply */
++#define KDBUS_CONN_MAX_REQUESTS_PENDING		128
++
++/* maximum number of connections per user in one domain */
++#define KDBUS_USER_MAX_CONN			1024
++
++/* maximum number of buses per user in one domain */
++#define KDBUS_USER_MAX_BUSES			16
++
++#endif
+diff --git a/ipc/kdbus/main.c b/ipc/kdbus/main.c
+new file mode 100644
+index 0000000..1ad4dc8
+--- /dev/null
++++ b/ipc/kdbus/main.c
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/module.h>
++
++#include "util.h"
++#include "fs.h"
++#include "handle.h"
++#include "metadata.h"
++#include "node.h"
++
++/*
++ * This is a simplified outline of the internal kdbus object relations, for
++ * those interested in the inner life of the driver implementation.
++ *
++ * From a mount point's (domain's) perspective:
++ *
++ * struct kdbus_domain
++ *   |» struct kdbus_user *user (many, owned)
++ *   '» struct kdbus_node node (embedded)
++ *       |» struct kdbus_node children (many, referenced)
++ *       |» struct kdbus_node *parent (pinned)
++ *       '» struct kdbus_bus (many, pinned)
++ *           |» struct kdbus_node node (embedded)
++ *           '» struct kdbus_ep (many, pinned)
++ *               |» struct kdbus_node node (embedded)
++ *               |» struct kdbus_bus *bus (pinned)
++ *               |» struct kdbus_conn conn_list (many, pinned)
++ *               |   |» struct kdbus_ep *ep (pinned)
++ *               |   |» struct kdbus_name_entry *activator_of (owned)
++ *               |   |» struct kdbus_match_db *match_db (owned)
++ *               |   |» struct kdbus_meta *meta (owned)
++ *               |   |» struct kdbus_match_db *match_db (owned)
++ *               |   |    '» struct kdbus_match_entry (many, owned)
++ *               |   |
++ *               |   |» struct kdbus_pool *pool (owned)
++ *               |   |    '» struct kdbus_pool_slice *slices (many, owned)
++ *               |   |       '» struct kdbus_pool *pool (pinned)
++ *               |   |
++ *               |   |» struct kdbus_user *user (pinned)
++ *               |   `» struct kdbus_queue_entry entries (many, embedded)
++ *               |        |» struct kdbus_pool_slice *slice (pinned)
++ *               |        |» struct kdbus_conn_reply *reply (owned)
++ *               |        '» struct kdbus_user *user (pinned)
++ *               |
++ *               '» struct kdbus_user *user (pinned)
++ *                   '» struct kdbus_policy_db policy_db (embedded)
++ *                        |» struct kdbus_policy_db_entry (many, owned)
++ *                        |   |» struct kdbus_conn (pinned)
++ *                        |   '» struct kdbus_ep (pinned)
++ *                        |
++ *                        '» struct kdbus_policy_db_cache_entry (many, owned)
++ *                            '» struct kdbus_conn (pinned)
++ *
++ * For the life-time of a file descriptor derived from calling open() on a file
++ * inside the mount point:
++ *
++ * struct kdbus_handle
++ *  |» struct kdbus_meta *meta (owned)
++ *  |» struct kdbus_ep *ep (pinned)
++ *  |» struct kdbus_conn *conn (owned)
++ *  '» struct kdbus_ep *ep (owned)
++ */
++
++/* kdbus mount-point /sys/fs/kdbus */
++static struct kobject *kdbus_dir;
++
++static int __init kdbus_init(void)
++{
++	int ret;
++
++	kdbus_dir = kobject_create_and_add(KBUILD_MODNAME, fs_kobj);
++	if (!kdbus_dir)
++		return -ENOMEM;
++
++	ret = kdbus_fs_init();
++	if (ret < 0) {
++		pr_err("cannot register filesystem: %d\n", ret);
++		goto exit_dir;
++	}
++
++	pr_info("initialized\n");
++	return 0;
++
++exit_dir:
++	kobject_put(kdbus_dir);
++	return ret;
++}
++
++static void __exit kdbus_exit(void)
++{
++	kdbus_fs_exit();
++	kobject_put(kdbus_dir);
++	ida_destroy(&kdbus_node_ida);
++}
++
++module_init(kdbus_init);
++module_exit(kdbus_exit);
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("D-Bus, powerful, easy to use interprocess communication");
++MODULE_ALIAS_FS(KBUILD_MODNAME "fs");
+diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c
+new file mode 100644
+index 0000000..4ee6a1f
+--- /dev/null
++++ b/ipc/kdbus/match.c
+@@ -0,0 +1,546 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/fs.h>
++#include <linux/hash.h>
++#include <linux/init.h>
++#include <linux/mutex.h>
++#include <linux/sched.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "endpoint.h"
++#include "handle.h"
++#include "item.h"
++#include "match.h"
++#include "message.h"
++#include "names.h"
++
++/**
++ * struct kdbus_match_db - message filters
++ * @entries_list:	List of matches
++ * @mdb_rwlock:		Match data lock
++ * @entries_count:	Number of entries in database
++ */
++struct kdbus_match_db {
++	struct list_head entries_list;
++	struct rw_semaphore mdb_rwlock;
++	unsigned int entries_count;
++};
++
++/**
++ * struct kdbus_match_entry - a match database entry
++ * @cookie:		User-supplied cookie to lookup the entry
++ * @list_entry:		The list entry element for the db list
++ * @rules_list:		The list head for tracking rules of this entry
++ */
++struct kdbus_match_entry {
++	u64 cookie;
++	struct list_head list_entry;
++	struct list_head rules_list;
++};
++
++/**
++ * struct kdbus_bloom_mask - mask to match against filter
++ * @generations:	Number of generations carried
++ * @data:		Array of bloom bit fields
++ */
++struct kdbus_bloom_mask {
++	u64 generations;
++	u64 *data;
++};
++
++/**
++ * struct kdbus_match_rule - a rule appended to a match entry
++ * @type:		An item type to match against
++ * @bloom_mask:		Bloom mask to match a message's filter against, used
++ *			with KDBUS_ITEM_BLOOM_MASK
++ * @name:		Name to match against, used with KDBUS_ITEM_NAME,
++ *			KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
++ * @old_id:		ID to match against, used with
++ *			KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE},
++ *			KDBUS_ITEM_ID_REMOVE
++ * @new_id:		ID to match against, used with
++ *			KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE},
++ *			KDBUS_ITEM_ID_REMOVE
++ * @src_id:		ID to match against, used with KDBUS_ITEM_ID
++ * @dst_id:		Message destination ID, used with KDBUS_ITEM_DST_ID
++ * @rules_entry:	Entry in the entry's rules list
++ */
++struct kdbus_match_rule {
++	u64 type;
++	union {
++		struct kdbus_bloom_mask bloom_mask;
++		struct {
++			char *name;
++			u64 old_id;
++			u64 new_id;
++		};
++		u64 src_id;
++		u64 dst_id;
++	};
++	struct list_head rules_entry;
++};
++
++static void kdbus_match_rule_free(struct kdbus_match_rule *rule)
++{
++	if (!rule)
++		return;
++
++	switch (rule->type) {
++	case KDBUS_ITEM_BLOOM_MASK:
++		kfree(rule->bloom_mask.data);
++		break;
++
++	case KDBUS_ITEM_NAME:
++	case KDBUS_ITEM_NAME_ADD:
++	case KDBUS_ITEM_NAME_REMOVE:
++	case KDBUS_ITEM_NAME_CHANGE:
++		kfree(rule->name);
++		break;
++
++	case KDBUS_ITEM_ID:
++	case KDBUS_ITEM_DST_ID:
++	case KDBUS_ITEM_ID_ADD:
++	case KDBUS_ITEM_ID_REMOVE:
++		break;
++
++	default:
++		BUG();
++	}
++
++	list_del(&rule->rules_entry);
++	kfree(rule);
++}
++
++static void kdbus_match_entry_free(struct kdbus_match_entry *entry)
++{
++	struct kdbus_match_rule *r, *tmp;
++
++	if (!entry)
++		return;
++
++	list_for_each_entry_safe(r, tmp, &entry->rules_list, rules_entry)
++		kdbus_match_rule_free(r);
++
++	list_del(&entry->list_entry);
++	kfree(entry);
++}
++
++/**
++ * kdbus_match_db_free() - free match db resources
++ * @mdb:		The match database
++ */
++void kdbus_match_db_free(struct kdbus_match_db *mdb)
++{
++	struct kdbus_match_entry *entry, *tmp;
++
++	if (!mdb)
++		return;
++
++	list_for_each_entry_safe(entry, tmp, &mdb->entries_list, list_entry)
++		kdbus_match_entry_free(entry);
++
++	kfree(mdb);
++}
++
++/**
++ * kdbus_match_db_new() - create a new match database
++ *
++ * Return: a new kdbus_match_db on success, ERR_PTR on failure.
++ */
++struct kdbus_match_db *kdbus_match_db_new(void)
++{
++	struct kdbus_match_db *d;
++
++	d = kzalloc(sizeof(*d), GFP_KERNEL);
++	if (!d)
++		return ERR_PTR(-ENOMEM);
++
++	init_rwsem(&d->mdb_rwlock);
++	INIT_LIST_HEAD(&d->entries_list);
++
++	return d;
++}
++
++static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter,
++			      const struct kdbus_bloom_mask *mask,
++			      const struct kdbus_conn *conn)
++{
++	size_t n = conn->ep->bus->bloom.size / sizeof(u64);
++	const u64 *m;
++	size_t i;
++
++	/*
++	 * The message's filter carries a generation identifier, the
++	 * match's mask possibly carries an array of multiple generations
++	 * of the mask. Select the mask with the closest match of the
++	 * filter's generation.
++	 */
++	m = mask->data + (min(filter->generation, mask->generations - 1) * n);
++
++	/*
++	 * The message's filter contains the messages properties,
++	 * the match's mask contains the properties to look for in the
++	 * message. Check the mask bit field against the filter bit field,
++	 * if the message possibly carries the properties the connection
++	 * has subscribed to.
++	 */
++	for (i = 0; i < n; i++)
++		if ((filter->data[i] & m[i]) != m[i])
++			return false;
++
++	return true;
++}
++
++static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r,
++				  struct kdbus_conn *c,
++				  const struct kdbus_staging *s)
++{
++	lockdep_assert_held(&c->ep->bus->name_registry->rwlock);
++
++	switch (r->type) {
++	case KDBUS_ITEM_BLOOM_MASK:
++		return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c);
++	case KDBUS_ITEM_ID:
++		return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY;
++	case KDBUS_ITEM_DST_ID:
++		return r->dst_id == s->msg->dst_id ||
++		       r->dst_id == KDBUS_MATCH_ID_ANY;
++	case KDBUS_ITEM_NAME:
++		return kdbus_conn_has_name(c, r->name);
++	default:
++		return false;
++	}
++}
++
++static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r,
++				    const struct kdbus_staging *s)
++{
++	struct kdbus_item *n = s->notify;
++
++	if (WARN_ON(!n) || n->type != r->type)
++		return false;
++
++	switch (r->type) {
++	case KDBUS_ITEM_ID_ADD:
++		return r->new_id == KDBUS_MATCH_ID_ANY ||
++		       r->new_id == n->id_change.id;
++	case KDBUS_ITEM_ID_REMOVE:
++		return r->old_id == KDBUS_MATCH_ID_ANY ||
++		       r->old_id == n->id_change.id;
++	case KDBUS_ITEM_NAME_ADD:
++	case KDBUS_ITEM_NAME_CHANGE:
++	case KDBUS_ITEM_NAME_REMOVE:
++		return (r->old_id == KDBUS_MATCH_ID_ANY ||
++		        r->old_id == n->name_change.old_id.id) &&
++		       (r->new_id == KDBUS_MATCH_ID_ANY ||
++		        r->new_id == n->name_change.new_id.id) &&
++		       (!r->name || !strcmp(r->name, n->name_change.name));
++	default:
++		return false;
++	}
++}
++
++static bool kdbus_match_rules(const struct kdbus_match_entry *entry,
++			      struct kdbus_conn *c,
++			      const struct kdbus_staging *s)
++{
++	struct kdbus_match_rule *r;
++
++	list_for_each_entry(r, &entry->rules_list, rules_entry)
++		if ((c && !kdbus_match_rule_conn(r, c, s)) ||
++		    (!c && !kdbus_match_rule_kernel(r, s)))
++			return false;
++
++	return true;
++}
++
++/**
++ * kdbus_match_db_match_msg() - match a msg object agains the database entries
++ * @mdb:		The match database
++ * @conn_src:		The connection object originating the message
++ * @staging:		Staging object containing the message to match against
++ *
++ * This function will walk through all the database entries previously uploaded
++ * with kdbus_match_db_add(). As soon as any of them has an all-satisfied rule
++ * set, this function will return true.
++ *
++ * The caller must hold the registry lock of conn_src->ep->bus, in case conn_src
++ * is non-NULL.
++ *
++ * Return: true if there was a matching database entry, false otherwise.
++ */
++bool kdbus_match_db_match_msg(struct kdbus_match_db *mdb,
++			      struct kdbus_conn *conn_src,
++			      const struct kdbus_staging *staging)
++{
++	struct kdbus_match_entry *entry;
++	bool matched = false;
++
++	down_read(&mdb->mdb_rwlock);
++	list_for_each_entry(entry, &mdb->entries_list, list_entry) {
++		matched = kdbus_match_rules(entry, conn_src, staging);
++		if (matched)
++			break;
++	}
++	up_read(&mdb->mdb_rwlock);
++
++	return matched;
++}
++
++static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb,
++					  u64 cookie)
++{
++	struct kdbus_match_entry *entry, *tmp;
++	bool found = false;
++
++	list_for_each_entry_safe(entry, tmp, &mdb->entries_list, list_entry)
++		if (entry->cookie == cookie) {
++			kdbus_match_entry_free(entry);
++			--mdb->entries_count;
++			found = true;
++		}
++
++	return found ? 0 : -EBADSLT;
++}
++
++/**
++ * kdbus_cmd_match_add() - handle KDBUS_CMD_MATCH_ADD
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * One call to this function (or one ioctl(KDBUS_CMD_MATCH_ADD), respectively,
++ * adds one new database entry with n rules attached to it. Each rule is
++ * described with an kdbus_item, and an entry is considered matching if all
++ * its rules are satisfied.
++ *
++ * The items attached to a kdbus_cmd_match struct have the following mapping:
++ *
++ * KDBUS_ITEM_BLOOM_MASK:	A bloom mask
++ * KDBUS_ITEM_NAME:		A connection's source name
++ * KDBUS_ITEM_ID:		A connection ID
++ * KDBUS_ITEM_DST_ID:		A connection ID
++ * KDBUS_ITEM_NAME_ADD:
++ * KDBUS_ITEM_NAME_REMOVE:
++ * KDBUS_ITEM_NAME_CHANGE:	Well-known name changes, carry
++ *				kdbus_notify_name_change
++ * KDBUS_ITEM_ID_ADD:
++ * KDBUS_ITEM_ID_REMOVE:	Connection ID changes, carry
++ *				kdbus_notify_id_change
++ *
++ * For kdbus_notify_{id,name}_change structs, only the ID and name fields
++ * are looked at when adding an entry. The flags are unused.
++ *
++ * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME, KDBUS_ITEM_ID,
++ * and KDBUS_ITEM_DST_ID are used to match messages from userspace, while the
++ * others apply to kernel-generated notifications.
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_match_db *mdb = conn->match_db;
++	struct kdbus_match_entry *entry = NULL;
++	struct kdbus_cmd_match *cmd;
++	struct kdbus_item *item;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_BLOOM_MASK, .multiple = true },
++		{ .type = KDBUS_ITEM_NAME, .multiple = true },
++		{ .type = KDBUS_ITEM_ID, .multiple = true },
++		{ .type = KDBUS_ITEM_DST_ID, .multiple = true },
++		{ .type = KDBUS_ITEM_NAME_ADD, .multiple = true },
++		{ .type = KDBUS_ITEM_NAME_REMOVE, .multiple = true },
++		{ .type = KDBUS_ITEM_NAME_CHANGE, .multiple = true },
++		{ .type = KDBUS_ITEM_ID_ADD, .multiple = true },
++		{ .type = KDBUS_ITEM_ID_REMOVE, .multiple = true },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_MATCH_REPLACE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn))
++		return -EOPNOTSUPP;
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++	if (!entry) {
++		ret = -ENOMEM;
++		goto exit;
++	}
++
++	entry->cookie = cmd->cookie;
++	INIT_LIST_HEAD(&entry->list_entry);
++	INIT_LIST_HEAD(&entry->rules_list);
++
++	KDBUS_ITEMS_FOREACH(item, cmd->items, KDBUS_ITEMS_SIZE(cmd, items)) {
++		struct kdbus_match_rule *rule;
++		size_t size = item->size - offsetof(struct kdbus_item, data);
++
++		rule = kzalloc(sizeof(*rule), GFP_KERNEL);
++		if (!rule) {
++			ret = -ENOMEM;
++			goto exit;
++		}
++
++		rule->type = item->type;
++		INIT_LIST_HEAD(&rule->rules_entry);
++
++		switch (item->type) {
++		case KDBUS_ITEM_BLOOM_MASK: {
++			u64 bsize = conn->ep->bus->bloom.size;
++			u64 generations;
++			u64 remainder;
++
++			generations = div64_u64_rem(size, bsize, &remainder);
++			if (size < bsize || remainder > 0) {
++				ret = -EDOM;
++				break;
++			}
++
++			rule->bloom_mask.data = kmemdup(item->data,
++							size, GFP_KERNEL);
++			if (!rule->bloom_mask.data) {
++				ret = -ENOMEM;
++				break;
++			}
++
++			rule->bloom_mask.generations = generations;
++			break;
++		}
++
++		case KDBUS_ITEM_NAME:
++			if (!kdbus_name_is_valid(item->str, false)) {
++				ret = -EINVAL;
++				break;
++			}
++
++			rule->name = kstrdup(item->str, GFP_KERNEL);
++			if (!rule->name)
++				ret = -ENOMEM;
++
++			break;
++
++		case KDBUS_ITEM_ID:
++			rule->src_id = item->id;
++			break;
++
++		case KDBUS_ITEM_DST_ID:
++			rule->dst_id = item->id;
++			break;
++
++		case KDBUS_ITEM_NAME_ADD:
++		case KDBUS_ITEM_NAME_REMOVE:
++		case KDBUS_ITEM_NAME_CHANGE:
++			rule->old_id = item->name_change.old_id.id;
++			rule->new_id = item->name_change.new_id.id;
++
++			if (size > sizeof(struct kdbus_notify_name_change)) {
++				rule->name = kstrdup(item->name_change.name,
++						     GFP_KERNEL);
++				if (!rule->name)
++					ret = -ENOMEM;
++			}
++
++			break;
++
++		case KDBUS_ITEM_ID_ADD:
++		case KDBUS_ITEM_ID_REMOVE:
++			if (item->type == KDBUS_ITEM_ID_ADD)
++				rule->new_id = item->id_change.id;
++			else
++				rule->old_id = item->id_change.id;
++
++			break;
++		}
++
++		if (ret < 0) {
++			kdbus_match_rule_free(rule);
++			goto exit;
++		}
++
++		list_add_tail(&rule->rules_entry, &entry->rules_list);
++	}
++
++	down_write(&mdb->mdb_rwlock);
++
++	/* Remove any entry that has the same cookie as the current one. */
++	if (cmd->flags & KDBUS_MATCH_REPLACE)
++		kdbus_match_db_remove_unlocked(mdb, entry->cookie);
++
++	/*
++	 * If the above removal caught any entry, there will be room for the
++	 * new one.
++	 */
++	if (++mdb->entries_count > KDBUS_MATCH_MAX) {
++		--mdb->entries_count;
++		ret = -EMFILE;
++	} else {
++		list_add_tail(&entry->list_entry, &mdb->entries_list);
++		entry = NULL;
++	}
++
++	up_write(&mdb->mdb_rwlock);
++
++exit:
++	kdbus_match_entry_free(entry);
++	return kdbus_args_clear(&args, ret);
++}
++
++/**
++ * kdbus_cmd_match_remove() - handle KDBUS_CMD_MATCH_REMOVE
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_cmd_match *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn))
++		return -EOPNOTSUPP;
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	down_write(&conn->match_db->mdb_rwlock);
++	ret = kdbus_match_db_remove_unlocked(conn->match_db, cmd->cookie);
++	up_write(&conn->match_db->mdb_rwlock);
++
++	return kdbus_args_clear(&args, ret);
++}
+diff --git a/ipc/kdbus/match.h b/ipc/kdbus/match.h
+new file mode 100644
+index 0000000..ceb492f
+--- /dev/null
++++ b/ipc/kdbus/match.h
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_MATCH_H
++#define __KDBUS_MATCH_H
++
++struct kdbus_conn;
++struct kdbus_match_db;
++struct kdbus_staging;
++
++struct kdbus_match_db *kdbus_match_db_new(void);
++void kdbus_match_db_free(struct kdbus_match_db *db);
++int kdbus_match_db_add(struct kdbus_conn *conn,
++		       struct kdbus_cmd_match *cmd);
++int kdbus_match_db_remove(struct kdbus_conn *conn,
++			  struct kdbus_cmd_match *cmd);
++bool kdbus_match_db_match_msg(struct kdbus_match_db *db,
++			      struct kdbus_conn *conn_src,
++			      const struct kdbus_staging *staging);
++
++int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp);
++int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp);
++
++#endif
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+new file mode 100644
+index 0000000..ae565cd
+--- /dev/null
++++ b/ipc/kdbus/message.c
+@@ -0,0 +1,1040 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/capability.h>
++#include <linux/cgroup.h>
++#include <linux/cred.h>
++#include <linux/file.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/sched.h>
++#include <linux/shmem_fs.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <net/sock.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "domain.h"
++#include "endpoint.h"
++#include "handle.h"
++#include "item.h"
++#include "match.h"
++#include "message.h"
++#include "names.h"
++#include "policy.h"
++
++static const char * const zeros = "\0\0\0\0\0\0\0";
++
++static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds)
++{
++	size_t size_offsets, size_memfds, size_fds, size;
++	struct kdbus_gaps *gaps;
++
++	size_offsets = n_memfds * sizeof(*gaps->memfd_offsets);
++	size_memfds = n_memfds * sizeof(*gaps->memfd_files);
++	size_fds = n_fds * sizeof(*gaps->fd_files);
++	size = sizeof(*gaps) + size_offsets + size_memfds + size_fds;
++
++	gaps = kzalloc(size, GFP_KERNEL);
++	if (!gaps)
++		return ERR_PTR(-ENOMEM);
++
++	kref_init(&gaps->kref);
++	gaps->n_memfds = 0; /* we reserve n_memfds, but don't enforce them */
++	gaps->memfd_offsets = (void *)(gaps + 1);
++	gaps->memfd_files = (void *)((u8 *)gaps->memfd_offsets + size_offsets);
++	gaps->n_fds = 0; /* we reserve n_fds, but don't enforce them */
++	gaps->fd_files = (void *)((u8 *)gaps->memfd_files + size_memfds);
++
++	return gaps;
++}
++
++static void kdbus_gaps_free(struct kref *kref)
++{
++	struct kdbus_gaps *gaps = container_of(kref, struct kdbus_gaps, kref);
++	size_t i;
++
++	for (i = 0; i < gaps->n_fds; ++i)
++		if (gaps->fd_files[i])
++			fput(gaps->fd_files[i]);
++	for (i = 0; i < gaps->n_memfds; ++i)
++		if (gaps->memfd_files[i])
++			fput(gaps->memfd_files[i]);
++
++	kfree(gaps);
++}
++
++/**
++ * kdbus_gaps_ref() - gain reference
++ * @gaps:	gaps object
++ *
++ * Return: @gaps is returned
++ */
++struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps)
++{
++	if (gaps)
++		kref_get(&gaps->kref);
++	return gaps;
++}
++
++/**
++ * kdbus_gaps_unref() - drop reference
++ * @gaps:	gaps object
++ *
++ * Return: NULL
++ */
++struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps)
++{
++	if (gaps)
++		kref_put(&gaps->kref, kdbus_gaps_free);
++	return NULL;
++}
++
++/**
++ * kdbus_gaps_install() - install file-descriptors
++ * @gaps:		gaps object, or NULL
++ * @slice:		pool slice that contains the message
++ * @out_incomplete	output variable to note incomplete fds
++ *
++ * This function installs all file-descriptors of @gaps into the current
++ * process and copies the file-descriptor numbers into the target pool slice.
++ *
++ * If the file-descriptors were only partially installed, then @out_incomplete
++ * will be set to true. Otherwise, it's set to false.
++ *
++ * Return: 0 on success, negative error code on failure
++ */
++int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice,
++		       bool *out_incomplete)
++{
++	bool incomplete_fds = false;
++	struct kvec kvec;
++	size_t i, n_fds;
++	int ret, *fds;
++
++	if (!gaps) {
++		/* nothing to do */
++		*out_incomplete = incomplete_fds;
++		return 0;
++	}
++
++	n_fds = gaps->n_fds + gaps->n_memfds;
++	if (n_fds < 1) {
++		/* nothing to do */
++		*out_incomplete = incomplete_fds;
++		return 0;
++	}
++
++	fds = kmalloc_array(n_fds, sizeof(*fds), GFP_TEMPORARY);
++	n_fds = 0;
++	if (!fds)
++		return -ENOMEM;
++
++	/* 1) allocate fds and copy them over */
++
++	if (gaps->n_fds > 0) {
++		for (i = 0; i < gaps->n_fds; ++i) {
++			int fd;
++
++			fd = get_unused_fd_flags(O_CLOEXEC);
++			if (fd < 0)
++				incomplete_fds = true;
++
++			WARN_ON(!gaps->fd_files[i]);
++
++			fds[n_fds++] = fd < 0 ? -1 : fd;
++		}
++
++		/*
++		 * The file-descriptor array can only be present once per
++		 * message. Hence, prepare all fds and then copy them over with
++		 * a single kvec.
++		 */
++
++		WARN_ON(!gaps->fd_offset);
++
++		kvec.iov_base = fds;
++		kvec.iov_len = gaps->n_fds * sizeof(*fds);
++		ret = kdbus_pool_slice_copy_kvec(slice, gaps->fd_offset,
++						 &kvec, 1, kvec.iov_len);
++		if (ret < 0)
++			goto exit;
++	}
++
++	for (i = 0; i < gaps->n_memfds; ++i) {
++		int memfd;
++
++		memfd = get_unused_fd_flags(O_CLOEXEC);
++		if (memfd < 0) {
++			incomplete_fds = true;
++			/* memfds are initialized to -1, skip copying it */
++			continue;
++		}
++
++		fds[n_fds++] = memfd;
++
++		/*
++		 * memfds have to be copied individually as they each are put
++		 * into a separate item. This should not be an issue, though,
++		 * as usually there is no need to send more than one memfd per
++		 * message.
++		 */
++
++		WARN_ON(!gaps->memfd_offsets[i]);
++		WARN_ON(!gaps->memfd_files[i]);
++
++		kvec.iov_base = &memfd;
++		kvec.iov_len = sizeof(memfd);
++		ret = kdbus_pool_slice_copy_kvec(slice, gaps->memfd_offsets[i],
++						 &kvec, 1, kvec.iov_len);
++		if (ret < 0)
++			goto exit;
++	}
++
++	/* 2) install fds now that everything was successful */
++
++	for (i = 0; i < gaps->n_fds; ++i)
++		if (fds[i] >= 0)
++			fd_install(fds[i], get_file(gaps->fd_files[i]));
++	for (i = 0; i < gaps->n_memfds; ++i)
++		if (fds[gaps->n_fds + i] >= 0)
++			fd_install(fds[gaps->n_fds + i],
++				   get_file(gaps->memfd_files[i]));
++
++	ret = 0;
++
++exit:
++	if (ret < 0)
++		for (i = 0; i < n_fds; ++i)
++			put_unused_fd(fds[i]);
++	kfree(fds);
++	*out_incomplete = incomplete_fds;
++	return ret;
++}
++
++static struct file *kdbus_get_fd(int fd)
++{
++	struct file *f, *ret;
++	struct inode *inode;
++	struct socket *sock;
++
++	if (fd < 0)
++		return ERR_PTR(-EBADF);
++
++	f = fget_raw(fd);
++	if (!f)
++		return ERR_PTR(-EBADF);
++
++	inode = file_inode(f);
++	sock = S_ISSOCK(inode->i_mode) ? SOCKET_I(inode) : NULL;
++
++	if (f->f_mode & FMODE_PATH)
++		ret = f; /* O_PATH is always allowed */
++	else if (f->f_op == &kdbus_handle_ops)
++		ret = ERR_PTR(-EOPNOTSUPP); /* disallow kdbus-fd over kdbus */
++	else if (sock && sock->sk && sock->ops && sock->ops->family == PF_UNIX)
++		ret = ERR_PTR(-EOPNOTSUPP); /* disallow UDS over kdbus */
++	else
++		ret = f; /* all other are allowed */
++
++	if (f != ret)
++		fput(f);
++
++	return ret;
++}
++
++static struct file *kdbus_get_memfd(const struct kdbus_memfd *memfd)
++{
++	const int m = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL;
++	struct file *f, *ret;
++	int s;
++
++	if (memfd->fd < 0)
++		return ERR_PTR(-EBADF);
++
++	f = fget(memfd->fd);
++	if (!f)
++		return ERR_PTR(-EBADF);
++
++	s = shmem_get_seals(f);
++	if (s < 0)
++		ret = ERR_PTR(-EMEDIUMTYPE);
++	else if ((s & m) != m)
++		ret = ERR_PTR(-ETXTBSY);
++	else if (memfd->start + memfd->size > (u64)i_size_read(file_inode(f)))
++		ret = ERR_PTR(-EFAULT);
++	else
++		ret = f;
++
++	if (f != ret)
++		fput(f);
++
++	return ret;
++}
++
++static int kdbus_msg_examine(struct kdbus_msg *msg, struct kdbus_bus *bus,
++			     struct kdbus_cmd_send *cmd, size_t *out_n_memfds,
++			     size_t *out_n_fds, size_t *out_n_parts)
++{
++	struct kdbus_item *item, *fds = NULL, *bloom = NULL, *dstname = NULL;
++	u64 n_parts, n_memfds, n_fds, vec_size;
++
++	/*
++	 * Step 1:
++	 * Validate the message and command parameters.
++	 */
++
++	/* KDBUS_PAYLOAD_KERNEL is reserved to kernel messages */
++	if (msg->payload_type == KDBUS_PAYLOAD_KERNEL)
++		return -EINVAL;
++
++	if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
++		/* broadcasts must be marked as signals */
++		if (!(msg->flags & KDBUS_MSG_SIGNAL))
++			return -EBADMSG;
++		/* broadcasts cannot have timeouts */
++		if (msg->timeout_ns > 0)
++			return -ENOTUNIQ;
++	}
++
++	if (msg->flags & KDBUS_MSG_EXPECT_REPLY) {
++		/* if you expect a reply, you must specify a timeout */
++		if (msg->timeout_ns == 0)
++			return -EINVAL;
++		/* signals cannot have replies */
++		if (msg->flags & KDBUS_MSG_SIGNAL)
++			return -ENOTUNIQ;
++	} else {
++		/* must expect reply if sent as synchronous call */
++		if (cmd->flags & KDBUS_SEND_SYNC_REPLY)
++			return -EINVAL;
++		/* cannot mark replies as signal */
++		if (msg->cookie_reply && (msg->flags & KDBUS_MSG_SIGNAL))
++			return -EINVAL;
++	}
++
++	/*
++	 * Step 2:
++	 * Validate all passed items. While at it, select some statistics that
++	 * are required to allocate state objects later on.
++	 *
++	 * Generic item validation has already been done via
++	 * kdbus_item_validate(). Furthermore, the number of items is naturally
++	 * limited by the maximum message size. Hence, only non-generic item
++	 * checks are performed here (mainly integer overflow tests).
++	 */
++
++	n_parts = 0;
++	n_memfds = 0;
++	n_fds = 0;
++	vec_size = 0;
++
++	KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) {
++		switch (item->type) {
++		case KDBUS_ITEM_PAYLOAD_VEC: {
++			void __force __user *ptr = KDBUS_PTR(item->vec.address);
++			u64 size = item->vec.size;
++
++			if (vec_size + size < vec_size)
++				return -EMSGSIZE;
++			if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE)
++				return -EMSGSIZE;
++			if (ptr && unlikely(!access_ok(VERIFY_READ, ptr, size)))
++				return -EFAULT;
++
++			if (ptr || size % 8) /* data or padding */
++				++n_parts;
++			break;
++		}
++		case KDBUS_ITEM_PAYLOAD_MEMFD: {
++			u64 start = item->memfd.start;
++			u64 size = item->memfd.size;
++
++			if (start + size < start)
++				return -EMSGSIZE;
++			if (n_memfds >= KDBUS_MSG_MAX_MEMFD_ITEMS)
++				return -E2BIG;
++
++			++n_memfds;
++			if (size % 8) /* vec-padding required */
++				++n_parts;
++			break;
++		}
++		case KDBUS_ITEM_FDS: {
++			if (fds)
++				return -EEXIST;
++
++			fds = item;
++			n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int);
++			if (n_fds > KDBUS_CONN_MAX_FDS_PER_USER)
++				return -EMFILE;
++
++			break;
++		}
++		case KDBUS_ITEM_BLOOM_FILTER: {
++			u64 bloom_size;
++
++			if (bloom)
++				return -EEXIST;
++
++			bloom = item;
++			bloom_size = KDBUS_ITEM_PAYLOAD_SIZE(item) -
++				     offsetof(struct kdbus_bloom_filter, data);
++			if (!KDBUS_IS_ALIGNED8(bloom_size))
++				return -EFAULT;
++			if (bloom_size != bus->bloom.size)
++				return -EDOM;
++
++			break;
++		}
++		case KDBUS_ITEM_DST_NAME: {
++			if (dstname)
++				return -EEXIST;
++
++			dstname = item;
++			if (!kdbus_name_is_valid(item->str, false))
++				return -EINVAL;
++			if (msg->dst_id == KDBUS_DST_ID_BROADCAST)
++				return -EBADMSG;
++
++			break;
++		}
++		default:
++			return -EINVAL;
++		}
++	}
++
++	/*
++	 * Step 3:
++	 * Validate that required items were actually passed, and that no item
++	 * contradicts the message flags.
++	 */
++
++	/* bloom filters must be attached _iff_ it's a signal */
++	if (!(msg->flags & KDBUS_MSG_SIGNAL) != !bloom)
++		return -EBADMSG;
++	/* destination name is required if no ID is given */
++	if (msg->dst_id == KDBUS_DST_ID_NAME && !dstname)
++		return -EDESTADDRREQ;
++	/* cannot send file-descriptors attached to broadcasts */
++	if (msg->dst_id == KDBUS_DST_ID_BROADCAST && fds)
++		return -ENOTUNIQ;
++
++	*out_n_memfds = n_memfds;
++	*out_n_fds = n_fds;
++	*out_n_parts = n_parts;
++
++	return 0;
++}
++
++static bool kdbus_staging_merge_vecs(struct kdbus_staging *staging,
++				     struct kdbus_item **prev_item,
++				     struct iovec **prev_vec,
++				     const struct kdbus_item *merge)
++{
++	void __user *ptr = (void __user *)KDBUS_PTR(merge->vec.address);
++	u64 padding = merge->vec.size % 8;
++	struct kdbus_item *prev = *prev_item;
++	struct iovec *vec = *prev_vec;
++
++	/* XXX: merging is disabled so far */
++	if (0 && prev && prev->type == KDBUS_ITEM_PAYLOAD_OFF &&
++	    !merge->vec.address == !prev->vec.address) {
++		/*
++		 * If we merge two VECs, we can always drop the second
++		 * PAYLOAD_VEC item. Hence, include its size in the previous
++		 * one.
++		 */
++		prev->vec.size += merge->vec.size;
++
++		if (ptr) {
++			/*
++			 * If we merge two data VECs, we need two iovecs to copy
++			 * the data. But the items can be easily merged by
++			 * summing their lengths.
++			 */
++			vec = &staging->parts[staging->n_parts++];
++			vec->iov_len = merge->vec.size;
++			vec->iov_base = ptr;
++			staging->n_payload += vec->iov_len;
++		} else if (padding) {
++			/*
++			 * If we merge two 0-vecs with the second 0-vec
++			 * requiring padding, we need to insert an iovec to copy
++			 * the 0-padding. We try merging it with the previous
++			 * 0-padding iovec. This might end up with an
++			 * iov_len==0, in which case we simply drop the iovec.
++			 */
++			if (vec) {
++				staging->n_payload -= vec->iov_len;
++				vec->iov_len = prev->vec.size % 8;
++				if (!vec->iov_len) {
++					--staging->n_parts;
++					vec = NULL;
++				} else {
++					staging->n_payload += vec->iov_len;
++				}
++			} else {
++				vec = &staging->parts[staging->n_parts++];
++				vec->iov_len = padding;
++				vec->iov_base = (char __user *)zeros;
++				staging->n_payload += vec->iov_len;
++			}
++		} else {
++			/*
++			 * If we merge two 0-vecs with the second 0-vec having
++			 * no padding, we know the padding of the first stays
++			 * the same. Hence, @vec needs no adjustment.
++			 */
++		}
++
++		/* successfully merged with previous item */
++		merge = prev;
++	} else {
++		/*
++		 * If we cannot merge the payload item with the previous one,
++		 * we simply insert a new iovec for the data/padding.
++		 */
++		if (ptr) {
++			vec = &staging->parts[staging->n_parts++];
++			vec->iov_len = merge->vec.size;
++			vec->iov_base = ptr;
++			staging->n_payload += vec->iov_len;
++		} else if (padding) {
++			vec = &staging->parts[staging->n_parts++];
++			vec->iov_len = padding;
++			vec->iov_base = (char __user *)zeros;
++			staging->n_payload += vec->iov_len;
++		} else {
++			vec = NULL;
++		}
++	}
++
++	*prev_item = (struct kdbus_item *)merge;
++	*prev_vec = vec;
++
++	return merge == prev;
++}
++
++static int kdbus_staging_import(struct kdbus_staging *staging)
++{
++	struct kdbus_item *it, *item, *last, *prev_payload;
++	struct kdbus_gaps *gaps = staging->gaps;
++	struct kdbus_msg *msg = staging->msg;
++	struct iovec *part, *prev_part;
++	bool drop_item;
++
++	drop_item = false;
++	last = NULL;
++	prev_payload = NULL;
++	prev_part = NULL;
++
++	/*
++	 * We modify msg->items along the way; make sure to use @item as offset
++	 * to the next item (instead of the iterator @it).
++	 */
++	for (it = item = msg->items;
++	     it >= msg->items &&
++	             (u8 *)it < (u8 *)msg + msg->size &&
++	             (u8 *)it + it->size <= (u8 *)msg + msg->size; ) {
++		/*
++		 * If we dropped items along the way, move current item to
++		 * front. We must not access @it afterwards, but use @item
++		 * instead!
++		 */
++		if (it != item)
++			memmove(item, it, it->size);
++		it = (void *)((u8 *)it + KDBUS_ALIGN8(item->size));
++
++		switch (item->type) {
++		case KDBUS_ITEM_PAYLOAD_VEC: {
++			size_t offset = staging->n_payload;
++
++			if (kdbus_staging_merge_vecs(staging, &prev_payload,
++						     &prev_part, item)) {
++				drop_item = true;
++			} else if (item->vec.address) {
++				/* real offset is patched later on */
++				item->type = KDBUS_ITEM_PAYLOAD_OFF;
++				item->vec.offset = offset;
++			} else {
++				item->type = KDBUS_ITEM_PAYLOAD_OFF;
++				item->vec.offset = ~0ULL;
++			}
++
++			break;
++		}
++		case KDBUS_ITEM_PAYLOAD_MEMFD: {
++			struct file *f;
++
++			f = kdbus_get_memfd(&item->memfd);
++			if (IS_ERR(f))
++				return PTR_ERR(f);
++
++			gaps->memfd_files[gaps->n_memfds] = f;
++			gaps->memfd_offsets[gaps->n_memfds] =
++					(u8 *)&item->memfd.fd - (u8 *)msg;
++			++gaps->n_memfds;
++
++			/* memfds cannot be merged */
++			prev_payload = item;
++			prev_part = NULL;
++
++			/* insert padding to make following VECs aligned */
++			if (item->memfd.size % 8) {
++				part = &staging->parts[staging->n_parts++];
++				part->iov_len = item->memfd.size % 8;
++				part->iov_base = (char __user *)zeros;
++				staging->n_payload += part->iov_len;
++			}
++
++			break;
++		}
++		case KDBUS_ITEM_FDS: {
++			size_t i, n_fds;
++
++			n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int);
++			for (i = 0; i < n_fds; ++i) {
++				struct file *f;
++
++				f = kdbus_get_fd(item->fds[i]);
++				if (IS_ERR(f))
++					return PTR_ERR(f);
++
++				gaps->fd_files[gaps->n_fds++] = f;
++			}
++
++			gaps->fd_offset = (u8 *)item->fds - (u8 *)msg;
++
++			break;
++		}
++		case KDBUS_ITEM_BLOOM_FILTER:
++			staging->bloom_filter = &item->bloom_filter;
++			break;
++		case KDBUS_ITEM_DST_NAME:
++			staging->dst_name = item->str;
++			break;
++		}
++
++		/* drop item if we merged it with a previous one */
++		if (drop_item) {
++			drop_item = false;
++		} else {
++			last = item;
++			item = KDBUS_ITEM_NEXT(item);
++		}
++	}
++
++	/* adjust message size regarding dropped items */
++	msg->size = offsetof(struct kdbus_msg, items);
++	if (last)
++		msg->size += ((u8 *)last - (u8 *)msg->items) + last->size;
++
++	return 0;
++}
++
++static void kdbus_staging_reserve(struct kdbus_staging *staging)
++{
++	struct iovec *part;
++
++	part = &staging->parts[staging->n_parts++];
++	part->iov_base = (void __user *)zeros;
++	part->iov_len = 0;
++}
++
++static struct kdbus_staging *kdbus_staging_new(struct kdbus_bus *bus,
++					       size_t n_parts,
++					       size_t msg_extra_size)
++{
++	const size_t reserved_parts = 5; /* see below for explanation */
++	struct kdbus_staging *staging;
++	int ret;
++
++	n_parts += reserved_parts;
++
++	staging = kzalloc(sizeof(*staging) + n_parts * sizeof(*staging->parts) +
++			  msg_extra_size, GFP_TEMPORARY);
++	if (!staging)
++		return ERR_PTR(-ENOMEM);
++
++	staging->msg_seqnum = atomic64_inc_return(&bus->last_message_id);
++	staging->n_parts = 0; /* we reserve n_parts, but don't enforce them */
++	staging->parts = (void *)(staging + 1);
++
++	if (msg_extra_size) /* if requested, allocate message, too */
++		staging->msg = (void *)((u8 *)staging->parts +
++				        n_parts * sizeof(*staging->parts));
++
++	staging->meta_proc = kdbus_meta_proc_new();
++	if (IS_ERR(staging->meta_proc)) {
++		ret = PTR_ERR(staging->meta_proc);
++		staging->meta_proc = NULL;
++		goto error;
++	}
++
++	staging->meta_conn = kdbus_meta_conn_new();
++	if (IS_ERR(staging->meta_conn)) {
++		ret = PTR_ERR(staging->meta_conn);
++		staging->meta_conn = NULL;
++		goto error;
++	}
++
++	/*
++	 * Prepare iovecs to copy the message into the target pool. We use the
++	 * following iovecs:
++	 *   * iovec to copy "kdbus_msg.size"
++	 *   * iovec to copy "struct kdbus_msg" (minus size) plus items
++	 *   * iovec for possible padding after the items
++	 *   * iovec for metadata items
++	 *   * iovec for possible padding after the items
++	 *
++	 * Make sure to update @reserved_parts if you add more parts here.
++	 */
++
++	kdbus_staging_reserve(staging); /* msg.size */
++	kdbus_staging_reserve(staging); /* msg (minus msg.size) plus items */
++	kdbus_staging_reserve(staging); /* msg padding */
++	kdbus_staging_reserve(staging); /* meta */
++	kdbus_staging_reserve(staging); /* meta padding */
++
++	return staging;
++
++error:
++	kdbus_staging_free(staging);
++	return ERR_PTR(ret);
++}
++
++struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus,
++					       u64 dst, u64 cookie_timeout,
++					       size_t it_size, size_t it_type)
++{
++	struct kdbus_staging *staging;
++	size_t size;
++
++	size = offsetof(struct kdbus_msg, items) +
++	       KDBUS_ITEM_HEADER_SIZE + it_size;
++
++	staging = kdbus_staging_new(bus, 0, KDBUS_ALIGN8(size));
++	if (IS_ERR(staging))
++		return ERR_CAST(staging);
++
++	staging->msg->size = size;
++	staging->msg->flags = (dst == KDBUS_DST_ID_BROADCAST) ?
++							KDBUS_MSG_SIGNAL : 0;
++	staging->msg->dst_id = dst;
++	staging->msg->src_id = KDBUS_SRC_ID_KERNEL;
++	staging->msg->payload_type = KDBUS_PAYLOAD_KERNEL;
++	staging->msg->cookie_reply = cookie_timeout;
++	staging->notify = staging->msg->items;
++	staging->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size;
++	staging->notify->type = it_type;
++
++	return staging;
++}
++
++struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus,
++					     struct kdbus_cmd_send *cmd,
++					     struct kdbus_msg *msg)
++{
++	const size_t reserved_parts = 1; /* see below for explanation */
++	size_t n_memfds, n_fds, n_parts;
++	struct kdbus_staging *staging;
++	int ret;
++
++	/*
++	 * Examine user-supplied message and figure out how many resources we
++	 * need to allocate in our staging area. This requires us to iterate
++	 * the message twice, but saves us from re-allocating our resources
++	 * all the time.
++	 */
++
++	ret = kdbus_msg_examine(msg, bus, cmd, &n_memfds, &n_fds, &n_parts);
++	if (ret < 0)
++		return ERR_PTR(ret);
++
++	n_parts += reserved_parts;
++
++	/*
++	 * Allocate staging area with the number of required resources. Make
++	 * sure that we have enough iovecs for all required parts pre-allocated
++	 * so this will hopefully be the only memory allocation for this
++	 * message transaction.
++	 */
++
++	staging = kdbus_staging_new(bus, n_parts, 0);
++	if (IS_ERR(staging))
++		return ERR_CAST(staging);
++
++	staging->msg = msg;
++
++	/*
++	 * If the message contains memfds or fd items, we need to remember some
++	 * state so we can fill in the requested information at RECV time.
++	 * File-descriptors cannot be passed at SEND time. Hence, allocate a
++	 * gaps-object to remember that state. That gaps object is linked to
++	 * from the staging area, but will also be linked to from the message
++	 * queue of each peer. Hence, each receiver owns a reference to it, and
++	 * it will later be used to fill the 'gaps' in message that couldn't be
++	 * filled at SEND time.
++	 * Note that the 'gaps' object is read-only once the staging-allocator
++	 * returns. There might be connections receiving a queued message while
++	 * the sender still broadcasts the message to other receivers.
++	 */
++
++	if (n_memfds > 0 || n_fds > 0) {
++		staging->gaps = kdbus_gaps_new(n_memfds, n_fds);
++		if (IS_ERR(staging->gaps)) {
++			ret = PTR_ERR(staging->gaps);
++			staging->gaps = NULL;
++			kdbus_staging_free(staging);
++			return ERR_PTR(ret);
++		}
++	}
++
++	/*
++	 * kdbus_staging_new() already reserves parts for message setup. For
++	 * user-supplied messages, we add the following iovecs:
++	 *   ... variable number of iovecs for payload ...
++	 *   * final iovec for possible padding of payload
++	 *
++	 * Make sure to update @reserved_parts if you add more parts here.
++	 */
++
++	ret = kdbus_staging_import(staging); /* payload */
++	kdbus_staging_reserve(staging); /* payload padding */
++
++	if (ret < 0)
++		goto error;
++
++	return staging;
++
++error:
++	kdbus_staging_free(staging);
++	return ERR_PTR(ret);
++}
++
++struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging)
++{
++	if (!staging)
++		return NULL;
++
++	kdbus_meta_conn_unref(staging->meta_conn);
++	kdbus_meta_proc_unref(staging->meta_proc);
++	kdbus_gaps_unref(staging->gaps);
++	kfree(staging);
++
++	return NULL;
++}
++
++static int kdbus_staging_collect_metadata(struct kdbus_staging *staging,
++					  struct kdbus_conn *src,
++					  struct kdbus_conn *dst,
++					  u64 *out_attach)
++{
++	u64 attach;
++	int ret;
++
++	if (src)
++		attach = kdbus_meta_msg_mask(src, dst);
++	else
++		attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */
++
++	if (src && !src->meta_fake) {
++		ret = kdbus_meta_proc_collect(staging->meta_proc, attach);
++		if (ret < 0)
++			return ret;
++	}
++
++	ret = kdbus_meta_conn_collect(staging->meta_conn, src,
++				      staging->msg_seqnum, attach);
++	if (ret < 0)
++		return ret;
++
++	*out_attach = attach;
++	return 0;
++}
++
++/**
++ * kdbus_staging_emit() - emit linearized message in target pool
++ * @staging:		staging object to create message from
++ * @src:		sender of the message (or NULL)
++ * @dst:		target connection to allocate message for
++ *
++ * This allocates a pool-slice for @dst and copies the message provided by
++ * @staging into it. The new slice is then returned to the caller for further
++ * processing. It's not linked into any queue, yet.
++ *
++ * Return: Newly allocated slice or ERR_PTR on failure.
++ */
++struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging,
++					    struct kdbus_conn *src,
++					    struct kdbus_conn *dst)
++{
++	struct kdbus_item *item, *meta_items = NULL;
++	struct kdbus_pool_slice *slice = NULL;
++	size_t off, size, meta_size;
++	struct iovec *v;
++	u64 attach, msg_size;
++	int ret;
++
++	/*
++	 * Step 1:
++	 * Collect metadata from @src depending on the attach-flags allowed for
++	 * @dst. Translate it into the namespaces pinned by @dst.
++	 */
++
++	ret = kdbus_staging_collect_metadata(staging, src, dst, &attach);
++	if (ret < 0)
++		goto error;
++
++	ret = kdbus_meta_emit(staging->meta_proc, NULL, staging->meta_conn,
++			      dst, attach, &meta_items, &meta_size);
++	if (ret < 0)
++		goto error;
++
++	/*
++	 * Step 2:
++	 * Setup iovecs for the message. See kdbus_staging_new() for allocation
++	 * of those iovecs. All reserved iovecs have been initialized with
++	 * iov_len=0 + iov_base=zeros. Furthermore, the iovecs to copy the
++	 * actual message payload have already been initialized and need not be
++	 * touched.
++	 */
++
++	v = staging->parts;
++	msg_size = staging->msg->size;
++
++	/* msg.size */
++	v->iov_len = sizeof(msg_size);
++	v->iov_base = (void __user *)&msg_size;
++	++v;
++
++	/* msg (after msg.size) plus items */
++	v->iov_len = staging->msg->size - sizeof(staging->msg->size);
++	v->iov_base = (void __user *)((u8 *)staging->msg +
++				      sizeof(staging->msg->size));
++	++v;
++
++	/* padding after msg */
++	v->iov_len = KDBUS_ALIGN8(staging->msg->size) - staging->msg->size;
++	v->iov_base = (void __user *)zeros;
++	++v;
++
++	if (meta_size > 0) {
++		/* metadata items */
++		v->iov_len = meta_size;
++		v->iov_base = (void __user *)meta_items;
++		++v;
++
++		/* padding after metadata */
++		v->iov_len = KDBUS_ALIGN8(meta_size) - meta_size;
++		v->iov_base = (void __user *)zeros;
++		++v;
++
++		msg_size = KDBUS_ALIGN8(msg_size) + meta_size;
++	} else {
++		/* metadata items */
++		v->iov_len = 0;
++		v->iov_base = (void __user *)zeros;
++		++v;
++
++		/* padding after metadata */
++		v->iov_len = 0;
++		v->iov_base = (void __user *)zeros;
++		++v;
++	}
++
++	/* ... payload iovecs are already filled in ... */
++
++	/* compute overall size and fill in padding after payload */
++	size = KDBUS_ALIGN8(msg_size);
++
++	if (staging->n_payload > 0) {
++		size += staging->n_payload;
++
++		v = &staging->parts[staging->n_parts - 1];
++		v->iov_len = KDBUS_ALIGN8(size) - size;
++		v->iov_base = (void __user *)zeros;
++
++		size = KDBUS_ALIGN8(size);
++	}
++
++	/*
++	 * Step 3:
++	 * The PAYLOAD_OFF items in the message contain a relative 'offset'
++	 * field that tells the receiver where to find the actual payload. This
++	 * offset is relative to the start of the message, and as such depends
++	 * on the size of the metadata items we inserted. This size is variable
++	 * and changes for each peer we send the message to. Hence, we remember
++	 * the last relative offset that was used to calculate the 'offset'
++	 * fields. For each message, we re-calculate it and patch all items, in
++	 * case it changed.
++	 */
++
++	off = KDBUS_ALIGN8(msg_size);
++
++	if (off != staging->i_payload) {
++		KDBUS_ITEMS_FOREACH(item, staging->msg->items,
++				    KDBUS_ITEMS_SIZE(staging->msg, items)) {
++			if (item->type != KDBUS_ITEM_PAYLOAD_OFF)
++				continue;
++
++			item->vec.offset -= staging->i_payload;
++			item->vec.offset += off;
++		}
++
++		staging->i_payload = off;
++	}
++
++	/*
++	 * Step 4:
++	 * Allocate pool slice and copy over all data. Make sure to properly
++	 * account on user quota.
++	 */
++
++	ret = kdbus_conn_quota_inc(dst, src ? src->user : NULL, size,
++				   staging->gaps ? staging->gaps->n_fds : 0);
++	if (ret < 0)
++		goto error;
++
++	slice = kdbus_pool_slice_alloc(dst->pool, size, true);
++	if (IS_ERR(slice)) {
++		ret = PTR_ERR(slice);
++		slice = NULL;
++		goto error;
++	}
++
++	WARN_ON(kdbus_pool_slice_size(slice) != size);
++
++	ret = kdbus_pool_slice_copy_iovec(slice, 0, staging->parts,
++					  staging->n_parts, size);
++	if (ret < 0)
++		goto error;
++
++	/* all done, return slice to caller */
++	goto exit;
++
++error:
++	if (slice)
++		kdbus_conn_quota_dec(dst, src ? src->user : NULL, size,
++				     staging->gaps ? staging->gaps->n_fds : 0);
++	kdbus_pool_slice_release(slice);
++	slice = ERR_PTR(ret);
++exit:
++	kfree(meta_items);
++	return slice;
++}
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+new file mode 100644
+index 0000000..298f9c9
+--- /dev/null
++++ b/ipc/kdbus/message.h
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_MESSAGE_H
++#define __KDBUS_MESSAGE_H
++
++#include <linux/fs.h>
++#include <linux/kref.h>
++#include <uapi/linux/kdbus.h>
++
++struct kdbus_bus;
++struct kdbus_conn;
++struct kdbus_meta_conn;
++struct kdbus_meta_proc;
++struct kdbus_pool_slice;
++
++/**
++ * struct kdbus_gaps - gaps in message to be filled later
++ * @kref:		Reference counter
++ * @n_memfd_offs:	Number of memfds
++ * @memfd_offs:		Offsets of kdbus_memfd items in target slice
++ * @n_fds:		Number of fds
++ * @fds:		Array of sent fds
++ * @fds_offset:		Offset of fd-array in target slice
++ *
++ * The 'gaps' object is used to track data that is needed to fill gaps in a
++ * message at RECV time. Usually, we try to compile the whole message at SEND
++ * time. This has the advantage, that we don't have to cache any information and
++ * can keep the memory consumption small. Furthermore, all copy operations can
++ * be combined into a single function call, which speeds up transactions
++ * considerably.
++ * However, things like file-descriptors can only be fully installed at RECV
++ * time. The gaps object tracks this data and pins it until a message is
++ * received. The gaps object is shared between all receivers of the same
++ * message.
++ */
++struct kdbus_gaps {
++	struct kref kref;
++
++	/* state tracking for KDBUS_ITEM_PAYLOAD_MEMFD entries */
++	size_t n_memfds;
++	u64 *memfd_offsets;
++	struct file **memfd_files;
++
++	/* state tracking for KDBUS_ITEM_FDS */
++	size_t n_fds;
++	struct file **fd_files;
++	u64 fd_offset;
++};
++
++struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps);
++struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps);
++int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice,
++		       bool *out_incomplete);
++
++/**
++ * struct kdbus_staging - staging area to import messages
++ * @msg:		User-supplied message
++ * @gaps:		Gaps-object created during import (or NULL if empty)
++ * @msg_seqnum:		Message sequence number
++ * @notify_entry:	Entry into list of kernel-generated notifications
++ * @i_payload:		Current relative index of start of payload
++ * @n_payload:		Total number of bytes needed for payload
++ * @n_parts:		Number of parts
++ * @parts:		Array of iovecs that make up the whole message
++ * @meta_proc:		Process metadata of the sender (or NULL if empty)
++ * @meta_conn:		Connection metadata of the sender (or NULL if empty)
++ * @bloom_filter:	Pointer to the bloom-item in @msg, or NULL
++ * @dst_name:		Pointer to the dst-name-item in @msg, or NULL
++ * @notify:		Pointer to the notification item in @msg, or NULL
++ *
++ * The kdbus_staging object is a temporary staging area to import user-supplied
++ * messages into the kernel. It is only used during SEND and dropped once the
++ * message is queued. Any data that cannot be collected during SEND, is
++ * collected in a kdbus_gaps object and attached to the message queue.
++ */
++struct kdbus_staging {
++	struct kdbus_msg *msg;
++	struct kdbus_gaps *gaps;
++	u64 msg_seqnum;
++	struct list_head notify_entry;
++
++	/* crafted iovecs to copy the message */
++	size_t i_payload;
++	size_t n_payload;
++	size_t n_parts;
++	struct iovec *parts;
++
++	/* metadata state */
++	struct kdbus_meta_proc *meta_proc;
++	struct kdbus_meta_conn *meta_conn;
++
++	/* cached pointers into @msg */
++	const struct kdbus_bloom_filter *bloom_filter;
++	const char *dst_name;
++	struct kdbus_item *notify;
++};
++
++struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus,
++					       u64 dst, u64 cookie_timeout,
++					       size_t it_size, size_t it_type);
++struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus,
++					     struct kdbus_cmd_send *cmd,
++					     struct kdbus_msg *msg);
++struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging);
++struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging,
++					    struct kdbus_conn *src,
++					    struct kdbus_conn *dst);
++
++#endif
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+new file mode 100644
+index 0000000..71ca475
+--- /dev/null
++++ b/ipc/kdbus/metadata.c
+@@ -0,0 +1,1347 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/audit.h>
++#include <linux/capability.h>
++#include <linux/cgroup.h>
++#include <linux/cred.h>
++#include <linux/file.h>
++#include <linux/fs_struct.h>
++#include <linux/init.h>
++#include <linux/kref.h>
++#include <linux/mutex.h>
++#include <linux/sched.h>
++#include <linux/security.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/uidgid.h>
++#include <linux/uio.h>
++#include <linux/user_namespace.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "endpoint.h"
++#include "item.h"
++#include "message.h"
++#include "metadata.h"
++#include "names.h"
++
++/**
++ * struct kdbus_meta_proc - Process metadata
++ * @kref:		Reference counting
++ * @lock:		Object lock
++ * @collected:		Bitmask of collected items
++ * @valid:		Bitmask of collected and valid items
++ * @cred:		Credentials
++ * @pid:		PID of process
++ * @tgid:		TGID of process
++ * @ppid:		PPID of process
++ * @tid_comm:		TID comm line
++ * @pid_comm:		PID comm line
++ * @exe_path:		Executable path
++ * @root_path:		Root-FS path
++ * @cmdline:		Command-line
++ * @cgroup:		Full cgroup path
++ * @seclabel:		Seclabel
++ * @audit_loginuid:	Audit login-UID
++ * @audit_sessionid:	Audit session-ID
++ */
++struct kdbus_meta_proc {
++	struct kref kref;
++	struct mutex lock;
++	u64 collected;
++	u64 valid;
++
++	/* KDBUS_ITEM_CREDS */
++	/* KDBUS_ITEM_AUXGROUPS */
++	/* KDBUS_ITEM_CAPS */
++	const struct cred *cred;
++
++	/* KDBUS_ITEM_PIDS */
++	struct pid *pid;
++	struct pid *tgid;
++	struct pid *ppid;
++
++	/* KDBUS_ITEM_TID_COMM */
++	char tid_comm[TASK_COMM_LEN];
++	/* KDBUS_ITEM_PID_COMM */
++	char pid_comm[TASK_COMM_LEN];
++
++	/* KDBUS_ITEM_EXE */
++	struct path exe_path;
++	struct path root_path;
++
++	/* KDBUS_ITEM_CMDLINE */
++	char *cmdline;
++
++	/* KDBUS_ITEM_CGROUP */
++	char *cgroup;
++
++	/* KDBUS_ITEM_SECLABEL */
++	char *seclabel;
++
++	/* KDBUS_ITEM_AUDIT */
++	kuid_t audit_loginuid;
++	unsigned int audit_sessionid;
++};
++
++/**
++ * struct kdbus_meta_conn
++ * @kref:		Reference counting
++ * @lock:		Object lock
++ * @collected:		Bitmask of collected items
++ * @valid:		Bitmask of collected and valid items
++ * @ts:			Timestamp values
++ * @owned_names_items:	Serialized items for owned names
++ * @owned_names_size:	Size of @owned_names_items
++ * @conn_description:	Connection description
++ */
++struct kdbus_meta_conn {
++	struct kref kref;
++	struct mutex lock;
++	u64 collected;
++	u64 valid;
++
++	/* KDBUS_ITEM_TIMESTAMP */
++	struct kdbus_timestamp ts;
++
++	/* KDBUS_ITEM_OWNED_NAME */
++	struct kdbus_item *owned_names_items;
++	size_t owned_names_size;
++
++	/* KDBUS_ITEM_CONN_DESCRIPTION */
++	char *conn_description;
++};
++
++/* fixed size equivalent of "kdbus_caps" */
++struct kdbus_meta_caps {
++	u32 last_cap;
++	struct {
++		u32 caps[_KERNEL_CAPABILITY_U32S];
++	} set[4];
++};
++
++/**
++ * kdbus_meta_proc_new() - Create process metadata object
++ *
++ * Return: Pointer to new object on success, ERR_PTR on failure.
++ */
++struct kdbus_meta_proc *kdbus_meta_proc_new(void)
++{
++	struct kdbus_meta_proc *mp;
++
++	mp = kzalloc(sizeof(*mp), GFP_KERNEL);
++	if (!mp)
++		return ERR_PTR(-ENOMEM);
++
++	kref_init(&mp->kref);
++	mutex_init(&mp->lock);
++
++	return mp;
++}
++
++static void kdbus_meta_proc_free(struct kref *kref)
++{
++	struct kdbus_meta_proc *mp = container_of(kref, struct kdbus_meta_proc,
++						  kref);
++
++	path_put(&mp->exe_path);
++	path_put(&mp->root_path);
++	if (mp->cred)
++		put_cred(mp->cred);
++	put_pid(mp->ppid);
++	put_pid(mp->tgid);
++	put_pid(mp->pid);
++
++	kfree(mp->seclabel);
++	kfree(mp->cmdline);
++	kfree(mp->cgroup);
++	kfree(mp);
++}
++
++/**
++ * kdbus_meta_proc_ref() - Gain reference
++ * @mp:		Process metadata object
++ *
++ * Return: @mp is returned
++ */
++struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp)
++{
++	if (mp)
++		kref_get(&mp->kref);
++	return mp;
++}
++
++/**
++ * kdbus_meta_proc_unref() - Drop reference
++ * @mp:		Process metadata object
++ *
++ * Return: NULL
++ */
++struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp)
++{
++	if (mp)
++		kref_put(&mp->kref, kdbus_meta_proc_free);
++	return NULL;
++}
++
++static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp)
++{
++	struct task_struct *parent;
++
++	mp->pid = get_pid(task_pid(current));
++	mp->tgid = get_pid(task_tgid(current));
++
++	rcu_read_lock();
++	parent = rcu_dereference(current->real_parent);
++	mp->ppid = get_pid(task_tgid(parent));
++	rcu_read_unlock();
++
++	mp->valid |= KDBUS_ATTACH_PIDS;
++}
++
++static void kdbus_meta_proc_collect_tid_comm(struct kdbus_meta_proc *mp)
++{
++	get_task_comm(mp->tid_comm, current);
++	mp->valid |= KDBUS_ATTACH_TID_COMM;
++}
++
++static void kdbus_meta_proc_collect_pid_comm(struct kdbus_meta_proc *mp)
++{
++	get_task_comm(mp->pid_comm, current->group_leader);
++	mp->valid |= KDBUS_ATTACH_PID_COMM;
++}
++
++static void kdbus_meta_proc_collect_exe(struct kdbus_meta_proc *mp)
++{
++	struct file *exe_file;
++
++	rcu_read_lock();
++	exe_file = rcu_dereference(current->mm->exe_file);
++	if (exe_file) {
++		mp->exe_path = exe_file->f_path;
++		path_get(&mp->exe_path);
++		get_fs_root(current->fs, &mp->root_path);
++		mp->valid |= KDBUS_ATTACH_EXE;
++	}
++	rcu_read_unlock();
++}
++
++static int kdbus_meta_proc_collect_cmdline(struct kdbus_meta_proc *mp)
++{
++	struct mm_struct *mm = current->mm;
++	char *cmdline;
++
++	if (!mm->arg_end)
++		return 0;
++
++	cmdline = strndup_user((const char __user *)mm->arg_start,
++			       mm->arg_end - mm->arg_start);
++	if (IS_ERR(cmdline))
++		return PTR_ERR(cmdline);
++
++	mp->cmdline = cmdline;
++	mp->valid |= KDBUS_ATTACH_CMDLINE;
++
++	return 0;
++}
++
++static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp)
++{
++#ifdef CONFIG_CGROUPS
++	void *page;
++	char *s;
++
++	page = (void *)__get_free_page(GFP_TEMPORARY);
++	if (!page)
++		return -ENOMEM;
++
++	s = task_cgroup_path(current, page, PAGE_SIZE);
++	if (s) {
++		mp->cgroup = kstrdup(s, GFP_KERNEL);
++		if (!mp->cgroup) {
++			free_page((unsigned long)page);
++			return -ENOMEM;
++		}
++	}
++
++	free_page((unsigned long)page);
++	mp->valid |= KDBUS_ATTACH_CGROUP;
++#endif
++
++	return 0;
++}
++
++static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp)
++{
++#ifdef CONFIG_SECURITY
++	char *ctx = NULL;
++	u32 sid, len;
++	int ret;
++
++	security_task_getsecid(current, &sid);
++	ret = security_secid_to_secctx(sid, &ctx, &len);
++	if (ret < 0) {
++		/*
++		 * EOPNOTSUPP means no security module is active,
++		 * lets skip adding the seclabel then. This effectively
++		 * drops the SECLABEL item.
++		 */
++		return (ret == -EOPNOTSUPP) ? 0 : ret;
++	}
++
++	mp->seclabel = kstrdup(ctx, GFP_KERNEL);
++	security_release_secctx(ctx, len);
++	if (!mp->seclabel)
++		return -ENOMEM;
++
++	mp->valid |= KDBUS_ATTACH_SECLABEL;
++#endif
++
++	return 0;
++}
++
++static void kdbus_meta_proc_collect_audit(struct kdbus_meta_proc *mp)
++{
++#ifdef CONFIG_AUDITSYSCALL
++	mp->audit_loginuid = audit_get_loginuid(current);
++	mp->audit_sessionid = audit_get_sessionid(current);
++	mp->valid |= KDBUS_ATTACH_AUDIT;
++#endif
++}
++
++/**
++ * kdbus_meta_proc_collect() - Collect process metadata
++ * @mp:		Process metadata object
++ * @what:	Attach flags to collect
++ *
++ * This collects process metadata from current and saves it in @mp.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what)
++{
++	int ret;
++
++	if (!mp || !(what & (KDBUS_ATTACH_CREDS |
++			     KDBUS_ATTACH_PIDS |
++			     KDBUS_ATTACH_AUXGROUPS |
++			     KDBUS_ATTACH_TID_COMM |
++			     KDBUS_ATTACH_PID_COMM |
++			     KDBUS_ATTACH_EXE |
++			     KDBUS_ATTACH_CMDLINE |
++			     KDBUS_ATTACH_CGROUP |
++			     KDBUS_ATTACH_CAPS |
++			     KDBUS_ATTACH_SECLABEL |
++			     KDBUS_ATTACH_AUDIT)))
++		return 0;
++
++	mutex_lock(&mp->lock);
++
++	/* creds, auxgrps and caps share "struct cred" as context */
++	{
++		const u64 m_cred = KDBUS_ATTACH_CREDS |
++				   KDBUS_ATTACH_AUXGROUPS |
++				   KDBUS_ATTACH_CAPS;
++
++		if ((what & m_cred) && !(mp->collected & m_cred)) {
++			mp->cred = get_current_cred();
++			mp->valid |= m_cred;
++			mp->collected |= m_cred;
++		}
++	}
++
++	if ((what & KDBUS_ATTACH_PIDS) &&
++	    !(mp->collected & KDBUS_ATTACH_PIDS)) {
++		kdbus_meta_proc_collect_pids(mp);
++		mp->collected |= KDBUS_ATTACH_PIDS;
++	}
++
++	if ((what & KDBUS_ATTACH_TID_COMM) &&
++	    !(mp->collected & KDBUS_ATTACH_TID_COMM)) {
++		kdbus_meta_proc_collect_tid_comm(mp);
++		mp->collected |= KDBUS_ATTACH_TID_COMM;
++	}
++
++	if ((what & KDBUS_ATTACH_PID_COMM) &&
++	    !(mp->collected & KDBUS_ATTACH_PID_COMM)) {
++		kdbus_meta_proc_collect_pid_comm(mp);
++		mp->collected |= KDBUS_ATTACH_PID_COMM;
++	}
++
++	if ((what & KDBUS_ATTACH_EXE) &&
++	    !(mp->collected & KDBUS_ATTACH_EXE)) {
++		kdbus_meta_proc_collect_exe(mp);
++		mp->collected |= KDBUS_ATTACH_EXE;
++	}
++
++	if ((what & KDBUS_ATTACH_CMDLINE) &&
++	    !(mp->collected & KDBUS_ATTACH_CMDLINE)) {
++		ret = kdbus_meta_proc_collect_cmdline(mp);
++		if (ret < 0)
++			goto exit_unlock;
++		mp->collected |= KDBUS_ATTACH_CMDLINE;
++	}
++
++	if ((what & KDBUS_ATTACH_CGROUP) &&
++	    !(mp->collected & KDBUS_ATTACH_CGROUP)) {
++		ret = kdbus_meta_proc_collect_cgroup(mp);
++		if (ret < 0)
++			goto exit_unlock;
++		mp->collected |= KDBUS_ATTACH_CGROUP;
++	}
++
++	if ((what & KDBUS_ATTACH_SECLABEL) &&
++	    !(mp->collected & KDBUS_ATTACH_SECLABEL)) {
++		ret = kdbus_meta_proc_collect_seclabel(mp);
++		if (ret < 0)
++			goto exit_unlock;
++		mp->collected |= KDBUS_ATTACH_SECLABEL;
++	}
++
++	if ((what & KDBUS_ATTACH_AUDIT) &&
++	    !(mp->collected & KDBUS_ATTACH_AUDIT)) {
++		kdbus_meta_proc_collect_audit(mp);
++		mp->collected |= KDBUS_ATTACH_AUDIT;
++	}
++
++	ret = 0;
++
++exit_unlock:
++	mutex_unlock(&mp->lock);
++	return ret;
++}
++
++/**
++ * kdbus_meta_fake_new() - Create fake metadata object
++ *
++ * Return: Pointer to new object on success, ERR_PTR on failure.
++ */
++struct kdbus_meta_fake *kdbus_meta_fake_new(void)
++{
++	struct kdbus_meta_fake *mf;
++
++	mf = kzalloc(sizeof(*mf), GFP_KERNEL);
++	if (!mf)
++		return ERR_PTR(-ENOMEM);
++
++	return mf;
++}
++
++/**
++ * kdbus_meta_fake_free() - Free fake metadata object
++ * @mf:		Fake metadata object
++ *
++ * Return: NULL
++ */
++struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf)
++{
++	if (mf) {
++		put_pid(mf->ppid);
++		put_pid(mf->tgid);
++		put_pid(mf->pid);
++		kfree(mf->seclabel);
++		kfree(mf);
++	}
++
++	return NULL;
++}
++
++/**
++ * kdbus_meta_fake_collect() - Fill fake metadata from faked credentials
++ * @mf:		Fake metadata object
++ * @creds:	Creds to set, may be %NULL
++ * @pids:	PIDs to set, may be %NULL
++ * @seclabel:	Seclabel to set, may be %NULL
++ *
++ * This function takes information stored in @creds, @pids and @seclabel and
++ * resolves them to kernel-representations, if possible. This call uses the
++ * current task's namespaces to resolve the given information.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf,
++			    const struct kdbus_creds *creds,
++			    const struct kdbus_pids *pids,
++			    const char *seclabel)
++{
++	if (mf->valid)
++		return -EALREADY;
++
++	if (creds) {
++		struct user_namespace *ns = current_user_ns();
++
++		mf->uid		= make_kuid(ns, creds->uid);
++		mf->euid	= make_kuid(ns, creds->euid);
++		mf->suid	= make_kuid(ns, creds->suid);
++		mf->fsuid	= make_kuid(ns, creds->fsuid);
++
++		mf->gid		= make_kgid(ns, creds->gid);
++		mf->egid	= make_kgid(ns, creds->egid);
++		mf->sgid	= make_kgid(ns, creds->sgid);
++		mf->fsgid	= make_kgid(ns, creds->fsgid);
++
++		if ((creds->uid   != (uid_t)-1 && !uid_valid(mf->uid))   ||
++		    (creds->euid  != (uid_t)-1 && !uid_valid(mf->euid))  ||
++		    (creds->suid  != (uid_t)-1 && !uid_valid(mf->suid))  ||
++		    (creds->fsuid != (uid_t)-1 && !uid_valid(mf->fsuid)) ||
++		    (creds->gid   != (gid_t)-1 && !gid_valid(mf->gid))   ||
++		    (creds->egid  != (gid_t)-1 && !gid_valid(mf->egid))  ||
++		    (creds->sgid  != (gid_t)-1 && !gid_valid(mf->sgid))  ||
++		    (creds->fsgid != (gid_t)-1 && !gid_valid(mf->fsgid)))
++			return -EINVAL;
++
++		mf->valid |= KDBUS_ATTACH_CREDS;
++	}
++
++	if (pids) {
++		mf->pid = get_pid(find_vpid(pids->tid));
++		mf->tgid = get_pid(find_vpid(pids->pid));
++		mf->ppid = get_pid(find_vpid(pids->ppid));
++
++		if ((pids->tid != 0 && !mf->pid) ||
++		    (pids->pid != 0 && !mf->tgid) ||
++		    (pids->ppid != 0 && !mf->ppid)) {
++			put_pid(mf->pid);
++			put_pid(mf->tgid);
++			put_pid(mf->ppid);
++			mf->pid = NULL;
++			mf->tgid = NULL;
++			mf->ppid = NULL;
++			return -EINVAL;
++		}
++
++		mf->valid |= KDBUS_ATTACH_PIDS;
++	}
++
++	if (seclabel) {
++		mf->seclabel = kstrdup(seclabel, GFP_KERNEL);
++		if (!mf->seclabel)
++			return -ENOMEM;
++
++		mf->valid |= KDBUS_ATTACH_SECLABEL;
++	}
++
++	return 0;
++}
++
++/**
++ * kdbus_meta_conn_new() - Create connection metadata object
++ *
++ * Return: Pointer to new object on success, ERR_PTR on failure.
++ */
++struct kdbus_meta_conn *kdbus_meta_conn_new(void)
++{
++	struct kdbus_meta_conn *mc;
++
++	mc = kzalloc(sizeof(*mc), GFP_KERNEL);
++	if (!mc)
++		return ERR_PTR(-ENOMEM);
++
++	kref_init(&mc->kref);
++	mutex_init(&mc->lock);
++
++	return mc;
++}
++
++static void kdbus_meta_conn_free(struct kref *kref)
++{
++	struct kdbus_meta_conn *mc =
++		container_of(kref, struct kdbus_meta_conn, kref);
++
++	kfree(mc->conn_description);
++	kfree(mc->owned_names_items);
++	kfree(mc);
++}
++
++/**
++ * kdbus_meta_conn_ref() - Gain reference
++ * @mc:		Connection metadata object
++ */
++struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc)
++{
++	if (mc)
++		kref_get(&mc->kref);
++	return mc;
++}
++
++/**
++ * kdbus_meta_conn_unref() - Drop reference
++ * @mc:		Connection metadata object
++ */
++struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc)
++{
++	if (mc)
++		kref_put(&mc->kref, kdbus_meta_conn_free);
++	return NULL;
++}
++
++static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc,
++					      u64 msg_seqnum)
++{
++	mc->ts.monotonic_ns = ktime_get_ns();
++	mc->ts.realtime_ns = ktime_get_real_ns();
++
++	if (msg_seqnum)
++		mc->ts.seqnum = msg_seqnum;
++
++	mc->valid |= KDBUS_ATTACH_TIMESTAMP;
++}
++
++static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc,
++					 struct kdbus_conn *conn)
++{
++	const struct kdbus_name_owner *owner;
++	struct kdbus_item *item;
++	size_t slen, size;
++
++	lockdep_assert_held(&conn->ep->bus->name_registry->rwlock);
++
++	size = 0;
++	/* open-code length calculation to avoid final padding */
++	list_for_each_entry(owner, &conn->names_list, conn_entry)
++		if (!(owner->flags & KDBUS_NAME_IN_QUEUE))
++			size = KDBUS_ALIGN8(size) + KDBUS_ITEM_HEADER_SIZE +
++				sizeof(struct kdbus_name) +
++				strlen(owner->name->name) + 1;
++
++	if (!size)
++		return 0;
++
++	/* make sure we include zeroed padding for convenience helpers */
++	item = kmalloc(KDBUS_ALIGN8(size), GFP_KERNEL);
++	if (!item)
++		return -ENOMEM;
++
++	mc->owned_names_items = item;
++	mc->owned_names_size = size;
++
++	list_for_each_entry(owner, &conn->names_list, conn_entry) {
++		if (owner->flags & KDBUS_NAME_IN_QUEUE)
++			continue;
++
++		slen = strlen(owner->name->name) + 1;
++		kdbus_item_set(item, KDBUS_ITEM_OWNED_NAME, NULL,
++			       sizeof(struct kdbus_name) + slen);
++		item->name.flags = owner->flags;
++		memcpy(item->name.name, owner->name->name, slen);
++		item = KDBUS_ITEM_NEXT(item);
++	}
++
++	/* sanity check: the buffer should be completely written now */
++	WARN_ON((u8 *)item !=
++			(u8 *)mc->owned_names_items + KDBUS_ALIGN8(size));
++
++	mc->valid |= KDBUS_ATTACH_NAMES;
++	return 0;
++}
++
++static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc,
++					       struct kdbus_conn *conn)
++{
++	if (!conn->description)
++		return 0;
++
++	mc->conn_description = kstrdup(conn->description, GFP_KERNEL);
++	if (!mc->conn_description)
++		return -ENOMEM;
++
++	mc->valid |= KDBUS_ATTACH_CONN_DESCRIPTION;
++	return 0;
++}
++
++/**
++ * kdbus_meta_conn_collect() - Collect connection metadata
++ * @mc:		Message metadata object
++ * @conn:	Connection to collect data from
++ * @msg_seqnum:	Sequence number of the message to send
++ * @what:	Attach flags to collect
++ *
++ * This collects connection metadata from @msg_seqnum and @conn and saves it
++ * in @mc.
++ *
++ * If KDBUS_ATTACH_NAMES is set in @what and @conn is non-NULL, the caller must
++ * hold the name-registry read-lock of conn->ep->bus->registry.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
++			    struct kdbus_conn *conn,
++			    u64 msg_seqnum, u64 what)
++{
++	int ret;
++
++	if (!mc || !(what & (KDBUS_ATTACH_TIMESTAMP |
++			     KDBUS_ATTACH_NAMES |
++			     KDBUS_ATTACH_CONN_DESCRIPTION)))
++		return 0;
++
++	mutex_lock(&mc->lock);
++
++	if (msg_seqnum && (what & KDBUS_ATTACH_TIMESTAMP) &&
++	    !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) {
++		kdbus_meta_conn_collect_timestamp(mc, msg_seqnum);
++		mc->collected |= KDBUS_ATTACH_TIMESTAMP;
++	}
++
++	if (conn && (what & KDBUS_ATTACH_NAMES) &&
++	    !(mc->collected & KDBUS_ATTACH_NAMES)) {
++		ret = kdbus_meta_conn_collect_names(mc, conn);
++		if (ret < 0)
++			goto exit_unlock;
++		mc->collected |= KDBUS_ATTACH_NAMES;
++	}
++
++	if (conn && (what & KDBUS_ATTACH_CONN_DESCRIPTION) &&
++	    !(mc->collected & KDBUS_ATTACH_CONN_DESCRIPTION)) {
++		ret = kdbus_meta_conn_collect_description(mc, conn);
++		if (ret < 0)
++			goto exit_unlock;
++		mc->collected |= KDBUS_ATTACH_CONN_DESCRIPTION;
++	}
++
++	ret = 0;
++
++exit_unlock:
++	mutex_unlock(&mc->lock);
++	return ret;
++}
++
++static void kdbus_meta_export_caps(struct kdbus_meta_caps *out,
++				   const struct kdbus_meta_proc *mp,
++				   struct user_namespace *user_ns)
++{
++	struct user_namespace *iter;
++	const struct cred *cred = mp->cred;
++	bool parent = false, owner = false;
++	int i;
++
++	/*
++	 * This translates the effective capabilities of 'cred' into the given
++	 * user-namespace. If the given user-namespace is a child-namespace of
++	 * the user-namespace of 'cred', the mask can be copied verbatim. If
++	 * not, the mask is cleared.
++	 * There's one exception: If 'cred' is the owner of any user-namespace
++	 * in the path between the given user-namespace and the user-namespace
++	 * of 'cred', then it has all effective capabilities set. This means,
++	 * the user who created a user-namespace always has all effective
++	 * capabilities in any child namespaces. Note that this is based on the
++	 * uid of the namespace creator, not the task hierarchy.
++	 */
++	for (iter = user_ns; iter; iter = iter->parent) {
++		if (iter == cred->user_ns) {
++			parent = true;
++			break;
++		}
++
++		if (iter == &init_user_ns)
++			break;
++
++		if ((iter->parent == cred->user_ns) &&
++		    uid_eq(iter->owner, cred->euid)) {
++			owner = true;
++			break;
++		}
++	}
++
++	out->last_cap = CAP_LAST_CAP;
++
++	CAP_FOR_EACH_U32(i) {
++		if (parent) {
++			out->set[0].caps[i] = cred->cap_inheritable.cap[i];
++			out->set[1].caps[i] = cred->cap_permitted.cap[i];
++			out->set[2].caps[i] = cred->cap_effective.cap[i];
++			out->set[3].caps[i] = cred->cap_bset.cap[i];
++		} else if (owner) {
++			out->set[0].caps[i] = 0U;
++			out->set[1].caps[i] = ~0U;
++			out->set[2].caps[i] = ~0U;
++			out->set[3].caps[i] = ~0U;
++		} else {
++			out->set[0].caps[i] = 0U;
++			out->set[1].caps[i] = 0U;
++			out->set[2].caps[i] = 0U;
++			out->set[3].caps[i] = 0U;
++		}
++	}
++
++	/* clear unused bits */
++	for (i = 0; i < 4; i++)
++		out->set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &=
++					CAP_LAST_U32_VALID_MASK;
++}
++
++/* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */
++static uid_t kdbus_from_kuid_keep(struct user_namespace *ns, kuid_t uid)
++{
++	return uid_valid(uid) ? from_kuid_munged(ns, uid) : ((uid_t)-1);
++}
++
++/* This is equivalent to from_kgid_munged(), but maps INVALID_GID to itself */
++static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid)
++{
++	return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1);
++}
++
++struct kdbus_meta_staging {
++	const struct kdbus_meta_proc *mp;
++	const struct kdbus_meta_fake *mf;
++	const struct kdbus_meta_conn *mc;
++	const struct kdbus_conn *conn;
++	u64 mask;
++
++	void *exe;
++	const char *exe_path;
++};
++
++static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging)
++{
++	const struct kdbus_meta_proc *mp = staging->mp;
++	const struct kdbus_meta_fake *mf = staging->mf;
++	const struct kdbus_meta_conn *mc = staging->mc;
++	const u64 mask = staging->mask;
++	size_t size = 0;
++
++	/* process metadata */
++
++	if (mf && (mask & KDBUS_ATTACH_CREDS))
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds));
++	else if (mp && (mask & KDBUS_ATTACH_CREDS))
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds));
++
++	if (mf && (mask & KDBUS_ATTACH_PIDS))
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
++	else if (mp && (mask & KDBUS_ATTACH_PIDS))
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
++
++	if (mp && (mask & KDBUS_ATTACH_AUXGROUPS))
++		size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups *
++					sizeof(u64));
++
++	if (mp && (mask & KDBUS_ATTACH_TID_COMM))
++		size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1);
++
++	if (mp && (mask & KDBUS_ATTACH_PID_COMM))
++		size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1);
++
++	if (staging->exe_path && (mask & KDBUS_ATTACH_EXE))
++		size += KDBUS_ITEM_SIZE(strlen(staging->exe_path) + 1);
++
++	if (mp && (mask & KDBUS_ATTACH_CMDLINE))
++		size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1);
++
++	if (mp && (mask & KDBUS_ATTACH_CGROUP))
++		size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1);
++
++	if (mp && (mask & KDBUS_ATTACH_CAPS))
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps));
++
++	if (mf && (mask & KDBUS_ATTACH_SECLABEL))
++		size += KDBUS_ITEM_SIZE(strlen(mf->seclabel) + 1);
++	else if (mp && (mask & KDBUS_ATTACH_SECLABEL))
++		size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1);
++
++	if (mp && (mask & KDBUS_ATTACH_AUDIT))
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit));
++
++	/* connection metadata */
++
++	if (mc && (mask & KDBUS_ATTACH_NAMES))
++		size += KDBUS_ALIGN8(mc->owned_names_size);
++
++	if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION))
++		size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1);
++
++	if (mc && (mask & KDBUS_ATTACH_TIMESTAMP))
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp));
++
++	return size;
++}
++
++static struct kdbus_item *kdbus_write_head(struct kdbus_item **iter,
++					   u64 type, u64 size)
++{
++	struct kdbus_item *item = *iter;
++	size_t padding;
++
++	item->type = type;
++	item->size = KDBUS_ITEM_HEADER_SIZE + size;
++
++	/* clear padding */
++	padding = KDBUS_ALIGN8(item->size) - item->size;
++	if (padding)
++		memset(item->data + size, 0, padding);
++
++	*iter = KDBUS_ITEM_NEXT(item);
++	return item;
++}
++
++static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter,
++					   u64 type, u64 size, const void *data)
++{
++	struct kdbus_item *item;
++
++	item = kdbus_write_head(iter, type, size);
++	memcpy(item->data, data, size);
++	return item;
++}
++
++static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem,
++			       size_t size)
++{
++	struct user_namespace *user_ns = staging->conn->cred->user_ns;
++	struct pid_namespace *pid_ns = ns_of_pid(staging->conn->pid);
++	struct kdbus_item *item = NULL, *items = mem;
++	u8 *end, *owned_names_end = NULL;
++
++	/* process metadata */
++
++	if (staging->mf && (staging->mask & KDBUS_ATTACH_CREDS)) {
++		const struct kdbus_meta_fake *mf = staging->mf;
++
++		item = kdbus_write_head(&items, KDBUS_ITEM_CREDS,
++					sizeof(struct kdbus_creds));
++		item->creds = (struct kdbus_creds){
++			.uid	= kdbus_from_kuid_keep(user_ns, mf->uid),
++			.euid	= kdbus_from_kuid_keep(user_ns, mf->euid),
++			.suid	= kdbus_from_kuid_keep(user_ns, mf->suid),
++			.fsuid	= kdbus_from_kuid_keep(user_ns, mf->fsuid),
++			.gid	= kdbus_from_kgid_keep(user_ns, mf->gid),
++			.egid	= kdbus_from_kgid_keep(user_ns, mf->egid),
++			.sgid	= kdbus_from_kgid_keep(user_ns, mf->sgid),
++			.fsgid	= kdbus_from_kgid_keep(user_ns, mf->fsgid),
++		};
++	} else if (staging->mp && (staging->mask & KDBUS_ATTACH_CREDS)) {
++		const struct cred *c = staging->mp->cred;
++
++		item = kdbus_write_head(&items, KDBUS_ITEM_CREDS,
++					sizeof(struct kdbus_creds));
++		item->creds = (struct kdbus_creds){
++			.uid	= kdbus_from_kuid_keep(user_ns, c->uid),
++			.euid	= kdbus_from_kuid_keep(user_ns, c->euid),
++			.suid	= kdbus_from_kuid_keep(user_ns, c->suid),
++			.fsuid	= kdbus_from_kuid_keep(user_ns, c->fsuid),
++			.gid	= kdbus_from_kgid_keep(user_ns, c->gid),
++			.egid	= kdbus_from_kgid_keep(user_ns, c->egid),
++			.sgid	= kdbus_from_kgid_keep(user_ns, c->sgid),
++			.fsgid	= kdbus_from_kgid_keep(user_ns, c->fsgid),
++		};
++	}
++
++	if (staging->mf && (staging->mask & KDBUS_ATTACH_PIDS)) {
++		item = kdbus_write_head(&items, KDBUS_ITEM_PIDS,
++					sizeof(struct kdbus_pids));
++		item->pids = (struct kdbus_pids){
++			.pid = pid_nr_ns(staging->mf->tgid, pid_ns),
++			.tid = pid_nr_ns(staging->mf->pid, pid_ns),
++			.ppid = pid_nr_ns(staging->mf->ppid, pid_ns),
++		};
++	} else if (staging->mp && (staging->mask & KDBUS_ATTACH_PIDS)) {
++		item = kdbus_write_head(&items, KDBUS_ITEM_PIDS,
++					sizeof(struct kdbus_pids));
++		item->pids = (struct kdbus_pids){
++			.pid = pid_nr_ns(staging->mp->tgid, pid_ns),
++			.tid = pid_nr_ns(staging->mp->pid, pid_ns),
++			.ppid = pid_nr_ns(staging->mp->ppid, pid_ns),
++		};
++	}
++
++	if (staging->mp && (staging->mask & KDBUS_ATTACH_AUXGROUPS)) {
++		const struct group_info *info = staging->mp->cred->group_info;
++		size_t i;
++
++		item = kdbus_write_head(&items, KDBUS_ITEM_AUXGROUPS,
++					info->ngroups * sizeof(u64));
++		for (i = 0; i < info->ngroups; ++i)
++			item->data64[i] = from_kgid_munged(user_ns,
++							   GROUP_AT(info, i));
++	}
++
++	if (staging->mp && (staging->mask & KDBUS_ATTACH_TID_COMM))
++		item = kdbus_write_full(&items, KDBUS_ITEM_TID_COMM,
++					strlen(staging->mp->tid_comm) + 1,
++					staging->mp->tid_comm);
++
++	if (staging->mp && (staging->mask & KDBUS_ATTACH_PID_COMM))
++		item = kdbus_write_full(&items, KDBUS_ITEM_PID_COMM,
++					strlen(staging->mp->pid_comm) + 1,
++					staging->mp->pid_comm);
++
++	if (staging->exe_path && (staging->mask & KDBUS_ATTACH_EXE))
++		item = kdbus_write_full(&items, KDBUS_ITEM_EXE,
++					strlen(staging->exe_path) + 1,
++					staging->exe_path);
++
++	if (staging->mp && (staging->mask & KDBUS_ATTACH_CMDLINE))
++		item = kdbus_write_full(&items, KDBUS_ITEM_CMDLINE,
++					strlen(staging->mp->cmdline) + 1,
++					staging->mp->cmdline);
++
++	if (staging->mp && (staging->mask & KDBUS_ATTACH_CGROUP))
++		item = kdbus_write_full(&items, KDBUS_ITEM_CGROUP,
++					strlen(staging->mp->cgroup) + 1,
++					staging->mp->cgroup);
++
++	if (staging->mp && (staging->mask & KDBUS_ATTACH_CAPS)) {
++		item = kdbus_write_head(&items, KDBUS_ITEM_CAPS,
++					sizeof(struct kdbus_meta_caps));
++		kdbus_meta_export_caps((void*)&item->caps, staging->mp,
++				       user_ns);
++	}
++
++	if (staging->mf && (staging->mask & KDBUS_ATTACH_SECLABEL))
++		item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL,
++					strlen(staging->mf->seclabel) + 1,
++					staging->mf->seclabel);
++	else if (staging->mp && (staging->mask & KDBUS_ATTACH_SECLABEL))
++		item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL,
++					strlen(staging->mp->seclabel) + 1,
++					staging->mp->seclabel);
++
++	if (staging->mp && (staging->mask & KDBUS_ATTACH_AUDIT)) {
++		item = kdbus_write_head(&items, KDBUS_ITEM_AUDIT,
++					sizeof(struct kdbus_audit));
++		item->audit = (struct kdbus_audit){
++			.loginuid = from_kuid(user_ns,
++					      staging->mp->audit_loginuid),
++			.sessionid = staging->mp->audit_sessionid,
++		};
++	}
++
++	/* connection metadata */
++
++	if (staging->mc && (staging->mask & KDBUS_ATTACH_NAMES)) {
++		memcpy(items, staging->mc->owned_names_items,
++		       KDBUS_ALIGN8(staging->mc->owned_names_size));
++		owned_names_end = (u8 *)items + staging->mc->owned_names_size;
++		items = (void *)KDBUS_ALIGN8((unsigned long)owned_names_end);
++	}
++
++	if (staging->mc && (staging->mask & KDBUS_ATTACH_CONN_DESCRIPTION))
++		item = kdbus_write_full(&items, KDBUS_ITEM_CONN_DESCRIPTION,
++				strlen(staging->mc->conn_description) + 1,
++				staging->mc->conn_description);
++
++	if (staging->mc && (staging->mask & KDBUS_ATTACH_TIMESTAMP))
++		item = kdbus_write_full(&items, KDBUS_ITEM_TIMESTAMP,
++					sizeof(staging->mc->ts),
++					&staging->mc->ts);
++
++	/*
++	 * Return real size (minus trailing padding). In case of 'owned_names'
++	 * we cannot deduce it from item->size, so treat it special.
++	 */
++
++	if (items == (void *)KDBUS_ALIGN8((unsigned long)owned_names_end))
++		end = owned_names_end;
++	else if (item)
++		end = (u8 *)item + item->size;
++	else
++		end = mem;
++
++	WARN_ON((u8 *)items - (u8 *)mem != size);
++	WARN_ON((void *)KDBUS_ALIGN8((unsigned long)end) != (void *)items);
++
++	return end - (u8 *)mem;
++}
++
++int kdbus_meta_emit(struct kdbus_meta_proc *mp,
++		    struct kdbus_meta_fake *mf,
++		    struct kdbus_meta_conn *mc,
++		    struct kdbus_conn *conn,
++		    u64 mask,
++		    struct kdbus_item **out_items,
++		    size_t *out_size)
++{
++	struct kdbus_meta_staging staging = {};
++	struct kdbus_item *items = NULL;
++	size_t size = 0;
++	int ret;
++
++	if (WARN_ON(mf && mp))
++		mp = NULL;
++
++	staging.mp = mp;
++	staging.mf = mf;
++	staging.mc = mc;
++	staging.conn = conn;
++
++	/* get mask of valid items */
++	if (mf)
++		staging.mask |= mf->valid;
++	if (mp) {
++		mutex_lock(&mp->lock);
++		staging.mask |= mp->valid;
++		mutex_unlock(&mp->lock);
++	}
++	if (mc) {
++		mutex_lock(&mc->lock);
++		staging.mask |= mc->valid;
++		mutex_unlock(&mc->lock);
++	}
++
++	staging.mask &= mask;
++
++	if (!staging.mask) { /* bail out if nothing to do */
++		ret = 0;
++		goto exit;
++	}
++
++	/* EXE is special as it needs a temporary page to assemble */
++	if (mp && (staging.mask & KDBUS_ATTACH_EXE)) {
++		struct path p;
++
++		/*
++		 * XXX: We need access to __d_path() so we can write the path
++		 * relative to conn->root_path. Once upstream, we need
++		 * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that
++		 * takes the root path directly. Until then, we drop this item
++		 * if the root-paths differ.
++		 */
++
++		get_fs_root(current->fs, &p);
++		if (path_equal(&p, &conn->root_path)) {
++			staging.exe = (void *)__get_free_page(GFP_TEMPORARY);
++			if (!staging.exe) {
++				path_put(&p);
++				ret = -ENOMEM;
++				goto exit;
++			}
++
++			staging.exe_path = d_path(&mp->exe_path, staging.exe,
++						  PAGE_SIZE);
++			if (IS_ERR(staging.exe_path)) {
++				path_put(&p);
++				ret = PTR_ERR(staging.exe_path);
++				goto exit;
++			}
++		}
++		path_put(&p);
++	}
++
++	size = kdbus_meta_measure(&staging);
++	if (!size) { /* bail out if nothing to do */
++		ret = 0;
++		goto exit;
++	}
++
++	items = kmalloc(size, GFP_KERNEL);
++	if (!items) {
++		ret = -ENOMEM;
++		goto exit;
++	}
++
++	size = kdbus_meta_write(&staging, items, size);
++	if (!size) {
++		kfree(items);
++		items = NULL;
++	}
++
++	ret = 0;
++
++exit:
++	if (staging.exe)
++		free_page((unsigned long)staging.exe);
++	if (ret >= 0) {
++		*out_items = items;
++		*out_size = size;
++	}
++	return ret;
++}
++
++enum {
++	KDBUS_META_PROC_NONE,
++	KDBUS_META_PROC_NORMAL,
++};
++
++/**
++ * kdbus_proc_permission() - check /proc permissions on target pid
++ * @pid_ns:		namespace we operate in
++ * @cred:		credentials of requestor
++ * @target:		target process
++ *
++ * This checks whether a process with credentials @cred can access information
++ * of @target in the namespace @pid_ns. This tries to follow /proc permissions,
++ * but is slightly more restrictive.
++ *
++ * Return: The /proc access level (KDBUS_META_PROC_*) is returned.
++ */
++static unsigned int kdbus_proc_permission(const struct pid_namespace *pid_ns,
++					  const struct cred *cred,
++					  struct pid *target)
++{
++	if (pid_ns->hide_pid < 1)
++		return KDBUS_META_PROC_NORMAL;
++
++	/* XXX: we need groups_search() exported for aux-groups */
++	if (gid_eq(cred->egid, pid_ns->pid_gid))
++		return KDBUS_META_PROC_NORMAL;
++
++	/*
++	 * XXX: If ptrace_may_access(PTRACE_MODE_READ) is granted, you can
++	 * overwrite hide_pid. However, ptrace_may_access() only supports
++	 * checking 'current', hence, we cannot use this here. But we
++	 * simply decide to not support this override, so no need to worry.
++	 */
++
++	return KDBUS_META_PROC_NONE;
++}
++
++/**
++ * kdbus_meta_proc_mask() - calculate which metadata would be visible to
++ *			    a connection via /proc
++ * @prv_pid:		pid of metadata provider
++ * @req_pid:		pid of metadata requestor
++ * @req_cred:		credentials of metadata reqeuestor
++ * @wanted:		metadata that is requested
++ *
++ * This checks which metadata items of @prv_pid can be read via /proc by the
++ * requestor @req_pid.
++ *
++ * Return: Set of metadata flags the requestor can see (limited by @wanted).
++ */
++static u64 kdbus_meta_proc_mask(struct pid *prv_pid,
++				struct pid *req_pid,
++				const struct cred *req_cred,
++				u64 wanted)
++{
++	struct pid_namespace *prv_ns, *req_ns;
++	unsigned int proc;
++
++	prv_ns = ns_of_pid(prv_pid);
++	req_ns = ns_of_pid(req_pid);
++
++	/*
++	 * If the sender is not visible in the receiver namespace, then the
++	 * receiver cannot access the sender via its own procfs. Hence, we do
++	 * not attach any additional metadata.
++	 */
++	if (!pid_nr_ns(prv_pid, req_ns))
++		return 0;
++
++	/*
++	 * If the pid-namespace of the receiver has hide_pid set, it cannot see
++	 * any process but its own. We shortcut this /proc permission check if
++	 * provider and requestor are the same. If not, we perform rather
++	 * expensive /proc permission checks.
++	 */
++	if (prv_pid == req_pid)
++		proc = KDBUS_META_PROC_NORMAL;
++	else
++		proc = kdbus_proc_permission(req_ns, req_cred, prv_pid);
++
++	/* you need /proc access to read standard process attributes */
++	if (proc < KDBUS_META_PROC_NORMAL)
++		wanted &= ~(KDBUS_ATTACH_TID_COMM |
++			    KDBUS_ATTACH_PID_COMM |
++			    KDBUS_ATTACH_SECLABEL |
++			    KDBUS_ATTACH_CMDLINE |
++			    KDBUS_ATTACH_CGROUP |
++			    KDBUS_ATTACH_AUDIT |
++			    KDBUS_ATTACH_CAPS |
++			    KDBUS_ATTACH_EXE);
++
++	/* clear all non-/proc flags */
++	return wanted & (KDBUS_ATTACH_TID_COMM |
++			 KDBUS_ATTACH_PID_COMM |
++			 KDBUS_ATTACH_SECLABEL |
++			 KDBUS_ATTACH_CMDLINE |
++			 KDBUS_ATTACH_CGROUP |
++			 KDBUS_ATTACH_AUDIT |
++			 KDBUS_ATTACH_CAPS |
++			 KDBUS_ATTACH_EXE);
++}
++
++/**
++ * kdbus_meta_get_mask() - calculate attach flags mask for metadata request
++ * @prv_pid:		pid of metadata provider
++ * @prv_mask:		mask of metadata the provide grants unchecked
++ * @req_pid:		pid of metadata requestor
++ * @req_cred:		credentials of metadata requestor
++ * @req_mask:		mask of metadata that is requested
++ *
++ * This calculates the metadata items that the requestor @req_pid can access
++ * from the metadata provider @prv_pid. This permission check consists of
++ * several different parts:
++ *  - Providers can grant metadata items unchecked. Regardless of their type,
++ *    they're always granted to the requestor. This mask is passed as @prv_mask.
++ *  - Basic items (credentials and connection metadata) are granted implicitly
++ *    to everyone. They're publicly available to any bus-user that can see the
++ *    provider.
++ *  - Process credentials that are not granted implicitly follow the same
++ *    permission checks as /proc. This means, we always assume a requestor
++ *    process has access to their *own* /proc mount, if they have access to
++ *    kdbusfs.
++ *
++ * Return: Mask of metadata that is granted.
++ */
++static u64 kdbus_meta_get_mask(struct pid *prv_pid, u64 prv_mask,
++			       struct pid *req_pid,
++			       const struct cred *req_cred, u64 req_mask)
++{
++	u64 missing, impl_mask, proc_mask = 0;
++
++	/*
++	 * Connection metadata and basic unix process credentials are
++	 * transmitted implicitly, and cannot be suppressed. Both are required
++	 * to perform user-space policies on the receiver-side. Furthermore,
++	 * connection metadata is public state, anyway, and unix credentials
++	 * are needed for UDS-compatibility. We extend them slightly by
++	 * auxiliary groups and additional uids/gids/pids.
++	 */
++	impl_mask = /* connection metadata */
++		    KDBUS_ATTACH_CONN_DESCRIPTION |
++		    KDBUS_ATTACH_TIMESTAMP |
++		    KDBUS_ATTACH_NAMES |
++		    /* credentials and pids */
++		    KDBUS_ATTACH_AUXGROUPS |
++		    KDBUS_ATTACH_CREDS |
++		    KDBUS_ATTACH_PIDS;
++
++	/*
++	 * Calculate the set of metadata that is not granted implicitly nor by
++	 * the sender, but still requested by the receiver. If any are left,
++	 * perform rather expensive /proc access checks for them.
++	 */
++	missing = req_mask & ~((prv_mask | impl_mask) & req_mask);
++	if (missing)
++		proc_mask = kdbus_meta_proc_mask(prv_pid, req_pid, req_cred,
++						 missing);
++
++	return (prv_mask | impl_mask | proc_mask) & req_mask;
++}
++
++/**
++ */
++u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask)
++{
++	return kdbus_meta_get_mask(conn->pid,
++				   atomic64_read(&conn->attach_flags_send),
++				   task_pid(current),
++				   current_cred(),
++				   mask);
++}
++
++/**
++ */
++u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd,
++			const struct kdbus_conn *rcv)
++{
++	return kdbus_meta_get_mask(task_pid(current),
++				   atomic64_read(&snd->attach_flags_send),
++				   rcv->pid,
++				   rcv->cred,
++				   atomic64_read(&rcv->attach_flags_recv));
++}
+diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h
+new file mode 100644
+index 0000000..dba7cc7
+--- /dev/null
++++ b/ipc/kdbus/metadata.h
+@@ -0,0 +1,86 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_METADATA_H
++#define __KDBUS_METADATA_H
++
++#include <linux/kernel.h>
++
++struct kdbus_conn;
++struct kdbus_pool_slice;
++
++struct kdbus_meta_proc;
++struct kdbus_meta_conn;
++
++/**
++ * struct kdbus_meta_fake - Fake metadata
++ * @valid:		Bitmask of collected and valid items
++ * @uid:		UID of process
++ * @euid:		EUID of process
++ * @suid:		SUID of process
++ * @fsuid:		FSUID of process
++ * @gid:		GID of process
++ * @egid:		EGID of process
++ * @sgid:		SGID of process
++ * @fsgid:		FSGID of process
++ * @pid:		PID of process
++ * @tgid:		TGID of process
++ * @ppid:		PPID of process
++ * @seclabel:		Seclabel
++ */
++struct kdbus_meta_fake {
++	u64 valid;
++
++	/* KDBUS_ITEM_CREDS */
++	kuid_t uid, euid, suid, fsuid;
++	kgid_t gid, egid, sgid, fsgid;
++
++	/* KDBUS_ITEM_PIDS */
++	struct pid *pid, *tgid, *ppid;
++
++	/* KDBUS_ITEM_SECLABEL */
++	char *seclabel;
++};
++
++struct kdbus_meta_proc *kdbus_meta_proc_new(void);
++struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp);
++struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp);
++int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what);
++
++struct kdbus_meta_fake *kdbus_meta_fake_new(void);
++struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf);
++int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf,
++			    const struct kdbus_creds *creds,
++			    const struct kdbus_pids *pids,
++			    const char *seclabel);
++
++struct kdbus_meta_conn *kdbus_meta_conn_new(void);
++struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc);
++struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc);
++int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
++			    struct kdbus_conn *conn,
++			    u64 msg_seqnum, u64 what);
++
++int kdbus_meta_emit(struct kdbus_meta_proc *mp,
++		    struct kdbus_meta_fake *mf,
++		    struct kdbus_meta_conn *mc,
++		    struct kdbus_conn *conn,
++		    u64 mask,
++		    struct kdbus_item **out_items,
++		    size_t *out_size);
++u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask);
++u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd,
++			const struct kdbus_conn *rcv);
++
++#endif
+diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c
+new file mode 100644
+index 0000000..bf44ca3
+--- /dev/null
++++ b/ipc/kdbus/names.c
+@@ -0,0 +1,854 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/ctype.h>
++#include <linux/fs.h>
++#include <linux/hash.h>
++#include <linux/idr.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/uio.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "endpoint.h"
++#include "handle.h"
++#include "item.h"
++#include "names.h"
++#include "notify.h"
++#include "policy.h"
++
++#define KDBUS_NAME_SAVED_MASK (KDBUS_NAME_ALLOW_REPLACEMENT |	\
++			       KDBUS_NAME_QUEUE)
++
++static bool kdbus_name_owner_is_used(struct kdbus_name_owner *owner)
++{
++	return !list_empty(&owner->name_entry) ||
++	       owner == owner->name->activator;
++}
++
++static struct kdbus_name_owner *
++kdbus_name_owner_new(struct kdbus_conn *conn, struct kdbus_name_entry *name,
++		     u64 flags)
++{
++	struct kdbus_name_owner *owner;
++
++	kdbus_conn_assert_active(conn);
++
++	if (conn->name_count >= KDBUS_CONN_MAX_NAMES)
++		return ERR_PTR(-E2BIG);
++
++	owner = kmalloc(sizeof(*owner), GFP_KERNEL);
++	if (!owner)
++		return ERR_PTR(-ENOMEM);
++
++	owner->flags = flags & KDBUS_NAME_SAVED_MASK;
++	owner->conn = conn;
++	owner->name = name;
++	list_add_tail(&owner->conn_entry, &conn->names_list);
++	INIT_LIST_HEAD(&owner->name_entry);
++
++	++conn->name_count;
++	return owner;
++}
++
++static void kdbus_name_owner_free(struct kdbus_name_owner *owner)
++{
++	if (!owner)
++		return;
++
++	WARN_ON(kdbus_name_owner_is_used(owner));
++	--owner->conn->name_count;
++	list_del(&owner->conn_entry);
++	kfree(owner);
++}
++
++static struct kdbus_name_owner *
++kdbus_name_owner_find(struct kdbus_name_entry *name, struct kdbus_conn *conn)
++{
++	struct kdbus_name_owner *owner;
++
++	/*
++	 * Use conn->names_list over name->queue to make sure boundaries of
++	 * this linear search are controlled by the connection itself.
++	 * Furthermore, this will find normal owners as well as activators
++	 * without any additional code.
++	 */
++	list_for_each_entry(owner, &conn->names_list, conn_entry)
++		if (owner->name == name)
++			return owner;
++
++	return NULL;
++}
++
++static bool kdbus_name_entry_is_used(struct kdbus_name_entry *name)
++{
++	return !list_empty(&name->queue) || name->activator;
++}
++
++static struct kdbus_name_owner *
++kdbus_name_entry_first(struct kdbus_name_entry *name)
++{
++	return list_first_entry_or_null(&name->queue, struct kdbus_name_owner,
++					name_entry);
++}
++
++static struct kdbus_name_entry *
++kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash,
++		     const char *name_str)
++{
++	struct kdbus_name_entry *name;
++	size_t namelen;
++
++	lockdep_assert_held(&r->rwlock);
++
++	namelen = strlen(name_str);
++
++	name = kmalloc(sizeof(*name) + namelen + 1, GFP_KERNEL);
++	if (!name)
++		return ERR_PTR(-ENOMEM);
++
++	name->name_id = ++r->name_seq_last;
++	name->activator = NULL;
++	INIT_LIST_HEAD(&name->queue);
++	hash_add(r->entries_hash, &name->hentry, hash);
++	memcpy(name->name, name_str, namelen + 1);
++
++	return name;
++}
++
++static void kdbus_name_entry_free(struct kdbus_name_entry *name)
++{
++	if (!name)
++		return;
++
++	WARN_ON(kdbus_name_entry_is_used(name));
++	hash_del(&name->hentry);
++	kfree(name);
++}
++
++static struct kdbus_name_entry *
++kdbus_name_entry_find(struct kdbus_name_registry *r, u32 hash,
++		      const char *name_str)
++{
++	struct kdbus_name_entry *name;
++
++	lockdep_assert_held(&r->rwlock);
++
++	hash_for_each_possible(r->entries_hash, name, hentry, hash)
++		if (!strcmp(name->name, name_str))
++			return name;
++
++	return NULL;
++}
++
++/**
++ * kdbus_name_registry_new() - create a new name registry
++ *
++ * Return: a new kdbus_name_registry on success, ERR_PTR on failure.
++ */
++struct kdbus_name_registry *kdbus_name_registry_new(void)
++{
++	struct kdbus_name_registry *r;
++
++	r = kmalloc(sizeof(*r), GFP_KERNEL);
++	if (!r)
++		return ERR_PTR(-ENOMEM);
++
++	hash_init(r->entries_hash);
++	init_rwsem(&r->rwlock);
++	r->name_seq_last = 0;
++
++	return r;
++}
++
++/**
++ * kdbus_name_registry_free() - free name registry
++ * @r:		name registry to free, or NULL
++ *
++ * Free a name registry and cleanup all internal objects. This is a no-op if
++ * you pass NULL as registry.
++ */
++void kdbus_name_registry_free(struct kdbus_name_registry *r)
++{
++	if (!r)
++		return;
++
++	WARN_ON(!hash_empty(r->entries_hash));
++	kfree(r);
++}
++
++/**
++ * kdbus_name_lookup_unlocked() - lookup name in registry
++ * @reg:		name registry
++ * @name:		name to lookup
++ *
++ * This looks up @name in the given name-registry and returns the
++ * kdbus_name_entry object. The caller must hold the registry-lock and must not
++ * access the returned object after releasing the lock.
++ *
++ * Return: Pointer to name-entry, or NULL if not found.
++ */
++struct kdbus_name_entry *
++kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name)
++{
++	return kdbus_name_entry_find(reg, kdbus_strhash(name), name);
++}
++
++static int kdbus_name_become_activator(struct kdbus_name_owner *owner,
++				       u64 *return_flags)
++{
++	if (kdbus_name_owner_is_used(owner))
++		return -EALREADY;
++	if (owner->name->activator)
++		return -EEXIST;
++
++	owner->name->activator = owner;
++	owner->flags |= KDBUS_NAME_ACTIVATOR;
++
++	if (kdbus_name_entry_first(owner->name)) {
++		owner->flags |= KDBUS_NAME_IN_QUEUE;
++	} else {
++		owner->flags |= KDBUS_NAME_PRIMARY;
++		kdbus_notify_name_change(owner->conn->ep->bus,
++					 KDBUS_ITEM_NAME_ADD,
++					 0, owner->conn->id,
++					 0, owner->flags,
++					 owner->name->name);
++	}
++
++	if (return_flags)
++		*return_flags = owner->flags | KDBUS_NAME_ACQUIRED;
++
++	return 0;
++}
++
++static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags,
++			     u64 *return_flags)
++{
++	struct kdbus_name_owner *primary, *activator;
++	struct kdbus_name_entry *name;
++	struct kdbus_bus *bus;
++	u64 nflags = 0;
++	int ret = 0;
++
++	name = owner->name;
++	bus = owner->conn->ep->bus;
++	primary = kdbus_name_entry_first(name);
++	activator = name->activator;
++
++	/* cannot be activator and acquire a name */
++	if (owner == activator)
++		return -EUCLEAN;
++
++	/* update saved flags */
++	owner->flags = flags & KDBUS_NAME_SAVED_MASK;
++
++	if (!primary) {
++		/*
++		 * No primary owner (but maybe an activator). Take over the
++		 * name.
++		 */
++
++		list_add(&owner->name_entry, &name->queue);
++		owner->flags |= KDBUS_NAME_PRIMARY;
++		nflags |= KDBUS_NAME_ACQUIRED;
++
++		/* move messages to new owner on activation */
++		if (activator) {
++			kdbus_conn_move_messages(owner->conn, activator->conn,
++						 name->name_id);
++			kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_CHANGE,
++					activator->conn->id, owner->conn->id,
++					activator->flags, owner->flags,
++					name->name);
++			activator->flags &= ~KDBUS_NAME_PRIMARY;
++			activator->flags |= KDBUS_NAME_IN_QUEUE;
++		} else {
++			kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_ADD,
++						 0, owner->conn->id,
++						 0, owner->flags,
++						 name->name);
++		}
++
++	} else if (owner == primary) {
++		/*
++		 * Already the primary owner of the name, flags were already
++		 * updated. Nothing to do.
++		 */
++
++		owner->flags |= KDBUS_NAME_PRIMARY;
++
++	} else if ((primary->flags & KDBUS_NAME_ALLOW_REPLACEMENT) &&
++		   (flags & KDBUS_NAME_REPLACE_EXISTING)) {
++		/*
++		 * We're not the primary owner but can replace it. Move us
++		 * ahead of the primary owner and acquire the name (possibly
++		 * skipping queued owners ahead of us).
++		 */
++
++		list_del_init(&owner->name_entry);
++		list_add(&owner->name_entry, &name->queue);
++		owner->flags |= KDBUS_NAME_PRIMARY;
++		nflags |= KDBUS_NAME_ACQUIRED;
++
++		kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_CHANGE,
++					 primary->conn->id, owner->conn->id,
++					 primary->flags, owner->flags,
++					 name->name);
++
++		/* requeue old primary, or drop if queueing not wanted */
++		if (primary->flags & KDBUS_NAME_QUEUE) {
++			primary->flags &= ~KDBUS_NAME_PRIMARY;
++			primary->flags |= KDBUS_NAME_IN_QUEUE;
++		} else {
++			list_del_init(&primary->name_entry);
++			kdbus_name_owner_free(primary);
++		}
++
++	} else if (flags & KDBUS_NAME_QUEUE) {
++		/*
++		 * Name is already occupied and we cannot take it over, but
++		 * queuing is allowed. Put us silently on the queue, if not
++		 * already there.
++		 */
++
++		owner->flags |= KDBUS_NAME_IN_QUEUE;
++		if (!kdbus_name_owner_is_used(owner)) {
++			list_add_tail(&owner->name_entry, &name->queue);
++			nflags |= KDBUS_NAME_ACQUIRED;
++		}
++	} else if (kdbus_name_owner_is_used(owner)) {
++		/*
++		 * Already queued on name, but re-queueing was not requested.
++		 * Make sure to unlink it from the name, the caller is
++		 * responsible for releasing it.
++		 */
++
++		list_del_init(&owner->name_entry);
++	} else {
++		/*
++		 * Name is already claimed and queueing is not requested.
++		 * Return error to the caller.
++		 */
++
++		ret = -EEXIST;
++	}
++
++	if (return_flags)
++		*return_flags = owner->flags | nflags;
++
++	return ret;
++}
++
++int kdbus_name_acquire(struct kdbus_name_registry *reg,
++		       struct kdbus_conn *conn, const char *name_str,
++		       u64 flags, u64 *return_flags)
++{
++	struct kdbus_name_entry *name = NULL;
++	struct kdbus_name_owner *owner = NULL;
++	u32 hash;
++	int ret;
++
++	kdbus_conn_assert_active(conn);
++
++	down_write(&reg->rwlock);
++
++	/*
++	 * Verify the connection has access to the name. Do this before testing
++	 * for double-acquisitions and other errors to make sure we do not leak
++	 * information about this name through possible custom endpoints.
++	 */
++	if (!kdbus_conn_policy_own_name(conn, current_cred(), name_str)) {
++		ret = -EPERM;
++		goto exit;
++	}
++
++	/*
++	 * Lookup the name entry. If it already exists, search for an owner
++	 * entry as we might already own that name. If either does not exist,
++	 * we will allocate a fresh one.
++	 */
++	hash = kdbus_strhash(name_str);
++	name = kdbus_name_entry_find(reg, hash, name_str);
++	if (name) {
++		owner = kdbus_name_owner_find(name, conn);
++	} else {
++		name = kdbus_name_entry_new(reg, hash, name_str);
++		if (IS_ERR(name)) {
++			ret = PTR_ERR(name);
++			name = NULL;
++			goto exit;
++		}
++	}
++
++	/* create name owner object if not already queued */
++	if (!owner) {
++		owner = kdbus_name_owner_new(conn, name, flags);
++		if (IS_ERR(owner)) {
++			ret = PTR_ERR(owner);
++			owner = NULL;
++			goto exit;
++		}
++	}
++
++	if (flags & KDBUS_NAME_ACTIVATOR)
++		ret = kdbus_name_become_activator(owner, return_flags);
++	else
++		ret = kdbus_name_update(owner, flags, return_flags);
++	if (ret < 0)
++		goto exit;
++
++exit:
++	if (owner && !kdbus_name_owner_is_used(owner))
++		kdbus_name_owner_free(owner);
++	if (name && !kdbus_name_entry_is_used(name))
++		kdbus_name_entry_free(name);
++	up_write(&reg->rwlock);
++	kdbus_notify_flush(conn->ep->bus);
++	return ret;
++}
++
++static void kdbus_name_release_unlocked(struct kdbus_name_owner *owner)
++{
++	struct kdbus_name_owner *primary, *next;
++	struct kdbus_name_entry *name;
++
++	name = owner->name;
++	primary = kdbus_name_entry_first(name);
++
++	list_del_init(&owner->name_entry);
++	if (owner == name->activator)
++		name->activator = NULL;
++
++	if (!primary || owner == primary) {
++		next = kdbus_name_entry_first(name);
++		if (!next)
++			next = name->activator;
++
++		if (next) {
++			/* hand to next in queue */
++			next->flags &= ~KDBUS_NAME_IN_QUEUE;
++			next->flags |= KDBUS_NAME_PRIMARY;
++			if (next == name->activator)
++				kdbus_conn_move_messages(next->conn,
++							 owner->conn,
++							 name->name_id);
++
++			kdbus_notify_name_change(owner->conn->ep->bus,
++					KDBUS_ITEM_NAME_CHANGE,
++					owner->conn->id, next->conn->id,
++					owner->flags, next->flags,
++					name->name);
++		} else {
++			kdbus_notify_name_change(owner->conn->ep->bus,
++						 KDBUS_ITEM_NAME_REMOVE,
++						 owner->conn->id, 0,
++						 owner->flags, 0,
++						 name->name);
++		}
++	}
++
++	kdbus_name_owner_free(owner);
++	if (!kdbus_name_entry_is_used(name))
++		kdbus_name_entry_free(name);
++}
++
++static int kdbus_name_release(struct kdbus_name_registry *reg,
++			      struct kdbus_conn *conn,
++			      const char *name_str)
++{
++	struct kdbus_name_owner *owner;
++	struct kdbus_name_entry *name;
++	int ret = 0;
++
++	down_write(&reg->rwlock);
++	name = kdbus_name_entry_find(reg, kdbus_strhash(name_str), name_str);
++	if (name) {
++		owner = kdbus_name_owner_find(name, conn);
++		if (owner)
++			kdbus_name_release_unlocked(owner);
++		else
++			ret = -EADDRINUSE;
++	} else {
++		ret = -ESRCH;
++	}
++	up_write(&reg->rwlock);
++
++	kdbus_notify_flush(conn->ep->bus);
++	return ret;
++}
++
++/**
++ * kdbus_name_release_all() - remove all name entries of a given connection
++ * @reg:		name registry
++ * @conn:		connection
++ */
++void kdbus_name_release_all(struct kdbus_name_registry *reg,
++			    struct kdbus_conn *conn)
++{
++	struct kdbus_name_owner *owner;
++
++	down_write(&reg->rwlock);
++
++	while ((owner = list_first_entry_or_null(&conn->names_list,
++						 struct kdbus_name_owner,
++						 conn_entry)))
++		kdbus_name_release_unlocked(owner);
++
++	up_write(&reg->rwlock);
++
++	kdbus_notify_flush(conn->ep->bus);
++}
++
++/**
++ * kdbus_name_is_valid() - check if a name is valid
++ * @p:			The name to check
++ * @allow_wildcard:	Whether or not to allow a wildcard name
++ *
++ * A name is valid if all of the following criterias are met:
++ *
++ *  - The name has two or more elements separated by a period ('.') character.
++ *  - All elements must contain at least one character.
++ *  - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_-"
++ *    and must not begin with a digit.
++ *  - The name must not exceed KDBUS_NAME_MAX_LEN.
++ *  - If @allow_wildcard is true, the name may end on '.*'
++ */
++bool kdbus_name_is_valid(const char *p, bool allow_wildcard)
++{
++	bool dot, found_dot = false;
++	const char *q;
++
++	for (dot = true, q = p; *q; q++) {
++		if (*q == '.') {
++			if (dot)
++				return false;
++
++			found_dot = true;
++			dot = true;
++		} else {
++			bool good;
++
++			good = isalpha(*q) || (!dot && isdigit(*q)) ||
++				*q == '_' || *q == '-' ||
++				(allow_wildcard && dot &&
++					*q == '*' && *(q + 1) == '\0');
++
++			if (!good)
++				return false;
++
++			dot = false;
++		}
++	}
++
++	if (q - p > KDBUS_NAME_MAX_LEN)
++		return false;
++
++	if (dot)
++		return false;
++
++	if (!found_dot)
++		return false;
++
++	return true;
++}
++
++/**
++ * kdbus_cmd_name_acquire() - handle KDBUS_CMD_NAME_ACQUIRE
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp)
++{
++	const char *item_name;
++	struct kdbus_cmd *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_NAME, .mandatory = true },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_NAME_REPLACE_EXISTING |
++				 KDBUS_NAME_ALLOW_REPLACEMENT |
++				 KDBUS_NAME_QUEUE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn))
++		return -EOPNOTSUPP;
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	item_name = argv[1].item->str;
++	if (!kdbus_name_is_valid(item_name, false)) {
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	ret = kdbus_name_acquire(conn->ep->bus->name_registry, conn, item_name,
++				 cmd->flags, &cmd->return_flags);
++
++exit:
++	return kdbus_args_clear(&args, ret);
++}
++
++/**
++ * kdbus_cmd_name_release() - handle KDBUS_CMD_NAME_RELEASE
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_cmd *cmd;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++		{ .type = KDBUS_ITEM_NAME, .mandatory = true },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	if (!kdbus_conn_is_ordinary(conn))
++		return -EOPNOTSUPP;
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	ret = kdbus_name_release(conn->ep->bus->name_registry, conn,
++				 argv[1].item->str);
++	return kdbus_args_clear(&args, ret);
++}
++
++static int kdbus_list_write(struct kdbus_conn *conn,
++			    struct kdbus_conn *c,
++			    struct kdbus_pool_slice *slice,
++			    size_t *pos,
++			    struct kdbus_name_owner *o,
++			    bool write)
++{
++	struct kvec kvec[4];
++	size_t cnt = 0;
++	int ret;
++
++	/* info header */
++	struct kdbus_info info = {
++		.size = 0,
++		.id = c->id,
++		.flags = c->flags,
++	};
++
++	/* fake the header of a kdbus_name item */
++	struct {
++		u64 size;
++		u64 type;
++		u64 flags;
++	} h = {};
++
++	if (o && !kdbus_conn_policy_see_name_unlocked(conn, current_cred(),
++						      o->name->name))
++		return 0;
++
++	kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &info.size);
++
++	/* append name */
++	if (o) {
++		size_t slen = strlen(o->name->name) + 1;
++
++		h.size = offsetof(struct kdbus_item, name.name) + slen;
++		h.type = KDBUS_ITEM_OWNED_NAME;
++		h.flags = o->flags;
++
++		kdbus_kvec_set(&kvec[cnt++], &h, sizeof(h), &info.size);
++		kdbus_kvec_set(&kvec[cnt++], o->name->name, slen, &info.size);
++		cnt += !!kdbus_kvec_pad(&kvec[cnt], &info.size);
++	}
++
++	if (write) {
++		ret = kdbus_pool_slice_copy_kvec(slice, *pos, kvec,
++						 cnt, info.size);
++		if (ret < 0)
++			return ret;
++	}
++
++	*pos += info.size;
++	return 0;
++}
++
++static int kdbus_list_all(struct kdbus_conn *conn, u64 flags,
++			  struct kdbus_pool_slice *slice,
++			  size_t *pos, bool write)
++{
++	struct kdbus_conn *c;
++	size_t p = *pos;
++	int ret, i;
++
++	hash_for_each(conn->ep->bus->conn_hash, i, c, hentry) {
++		bool added = false;
++
++		/* skip monitors */
++		if (kdbus_conn_is_monitor(c))
++			continue;
++
++		/* all names the connection owns */
++		if (flags & (KDBUS_LIST_NAMES |
++			     KDBUS_LIST_ACTIVATORS |
++			     KDBUS_LIST_QUEUED)) {
++			struct kdbus_name_owner *o;
++
++			list_for_each_entry(o, &c->names_list, conn_entry) {
++				if (o->flags & KDBUS_NAME_ACTIVATOR) {
++					if (!(flags & KDBUS_LIST_ACTIVATORS))
++						continue;
++
++					ret = kdbus_list_write(conn, c, slice,
++							       &p, o, write);
++					if (ret < 0) {
++						mutex_unlock(&c->lock);
++						return ret;
++					}
++
++					added = true;
++				} else if (o->flags & KDBUS_NAME_IN_QUEUE) {
++					if (!(flags & KDBUS_LIST_QUEUED))
++						continue;
++
++					ret = kdbus_list_write(conn, c, slice,
++							       &p, o, write);
++					if (ret < 0) {
++						mutex_unlock(&c->lock);
++						return ret;
++					}
++
++					added = true;
++				} else if (flags & KDBUS_LIST_NAMES) {
++					ret = kdbus_list_write(conn, c, slice,
++							       &p, o, write);
++					if (ret < 0) {
++						mutex_unlock(&c->lock);
++						return ret;
++					}
++
++					added = true;
++				}
++			}
++		}
++
++		/* nothing added so far, just add the unique ID */
++		if (!added && (flags & KDBUS_LIST_UNIQUE)) {
++			ret = kdbus_list_write(conn, c, slice, &p, NULL, write);
++			if (ret < 0)
++				return ret;
++		}
++	}
++
++	*pos = p;
++	return 0;
++}
++
++/**
++ * kdbus_cmd_list() - handle KDBUS_CMD_LIST
++ * @conn:		connection to operate on
++ * @argp:		command payload
++ *
++ * Return: >=0 on success, negative error code on failure.
++ */
++int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp)
++{
++	struct kdbus_name_registry *reg = conn->ep->bus->name_registry;
++	struct kdbus_pool_slice *slice = NULL;
++	struct kdbus_cmd_list *cmd;
++	size_t pos, size;
++	int ret;
++
++	struct kdbus_arg argv[] = {
++		{ .type = KDBUS_ITEM_NEGOTIATE },
++	};
++	struct kdbus_args args = {
++		.allowed_flags = KDBUS_FLAG_NEGOTIATE |
++				 KDBUS_LIST_UNIQUE |
++				 KDBUS_LIST_NAMES |
++				 KDBUS_LIST_ACTIVATORS |
++				 KDBUS_LIST_QUEUED,
++		.argv = argv,
++		.argc = ARRAY_SIZE(argv),
++	};
++
++	ret = kdbus_args_parse(&args, argp, &cmd);
++	if (ret != 0)
++		return ret;
++
++	/* lock order: domain -> bus -> ep -> names -> conn */
++	down_read(&reg->rwlock);
++	down_read(&conn->ep->bus->conn_rwlock);
++	down_read(&conn->ep->policy_db.entries_rwlock);
++
++	/* size of records */
++	size = 0;
++	ret = kdbus_list_all(conn, cmd->flags, NULL, &size, false);
++	if (ret < 0)
++		goto exit_unlock;
++
++	if (size == 0) {
++		kdbus_pool_publish_empty(conn->pool, &cmd->offset,
++					 &cmd->list_size);
++	} else {
++		slice = kdbus_pool_slice_alloc(conn->pool, size, false);
++		if (IS_ERR(slice)) {
++			ret = PTR_ERR(slice);
++			slice = NULL;
++			goto exit_unlock;
++		}
++
++		/* copy the records */
++		pos = 0;
++		ret = kdbus_list_all(conn, cmd->flags, slice, &pos, true);
++		if (ret < 0)
++			goto exit_unlock;
++
++		WARN_ON(pos != size);
++		kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->list_size);
++	}
++
++	if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) ||
++	    kdbus_member_set_user(&cmd->list_size, argp,
++				  typeof(*cmd), list_size))
++		ret = -EFAULT;
++
++exit_unlock:
++	up_read(&conn->ep->policy_db.entries_rwlock);
++	up_read(&conn->ep->bus->conn_rwlock);
++	up_read(&reg->rwlock);
++	kdbus_pool_slice_release(slice);
++	return kdbus_args_clear(&args, ret);
++}
+diff --git a/ipc/kdbus/names.h b/ipc/kdbus/names.h
+new file mode 100644
+index 0000000..edac59d
+--- /dev/null
++++ b/ipc/kdbus/names.h
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_NAMES_H
++#define __KDBUS_NAMES_H
++
++#include <linux/hashtable.h>
++#include <linux/rwsem.h>
++
++struct kdbus_name_entry;
++struct kdbus_name_owner;
++struct kdbus_name_registry;
++
++/**
++ * struct kdbus_name_registry - names registered for a bus
++ * @entries_hash:	Map of entries
++ * @lock:		Registry data lock
++ * @name_seq_last:	Last used sequence number to assign to a name entry
++ */
++struct kdbus_name_registry {
++	DECLARE_HASHTABLE(entries_hash, 8);
++	struct rw_semaphore rwlock;
++	u64 name_seq_last;
++};
++
++/**
++ * struct kdbus_name_entry - well-know name entry
++ * @name_id:		sequence number of name entry to be able to uniquely
++ *			identify a name over its registration lifetime
++ * @activator:		activator of this name, or NULL
++ * @queue:		list of queued owners
++ * @hentry:		entry in registry map
++ * @name:		well-known name
++ */
++struct kdbus_name_entry {
++	u64 name_id;
++	struct kdbus_name_owner *activator;
++	struct list_head queue;
++	struct hlist_node hentry;
++	char name[];
++};
++
++/**
++ * struct kdbus_name_owner - owner of a well-known name
++ * @flags:		KDBUS_NAME_* flags of this owner
++ * @conn:		connection owning the name
++ * @name:		name that is owned
++ * @conn_entry:		link into @conn
++ * @name_entry:		link into @name
++ */
++struct kdbus_name_owner {
++	u64 flags;
++	struct kdbus_conn *conn;
++	struct kdbus_name_entry *name;
++	struct list_head conn_entry;
++	struct list_head name_entry;
++};
++
++bool kdbus_name_is_valid(const char *p, bool allow_wildcard);
++
++struct kdbus_name_registry *kdbus_name_registry_new(void);
++void kdbus_name_registry_free(struct kdbus_name_registry *reg);
++
++struct kdbus_name_entry *
++kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name);
++
++int kdbus_name_acquire(struct kdbus_name_registry *reg,
++		       struct kdbus_conn *conn, const char *name,
++		       u64 flags, u64 *return_flags);
++void kdbus_name_release_all(struct kdbus_name_registry *reg,
++			    struct kdbus_conn *conn);
++
++int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp);
++int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp);
++int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp);
++
++/**
++ * kdbus_name_get_owner() - get current owner of a name
++ * @name:	name to get current owner of
++ *
++ * This returns a pointer to the current owner of a name (or its activator if
++ * there is no owner). The caller must make sure @name is valid and does not
++ * vanish.
++ *
++ * Return: Pointer to current owner or NULL if there is none.
++ */
++static inline struct kdbus_name_owner *
++kdbus_name_get_owner(struct kdbus_name_entry *name)
++{
++	return list_first_entry_or_null(&name->queue, struct kdbus_name_owner,
++					name_entry) ? : name->activator;
++}
++
++#endif
+diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c
+new file mode 100644
+index 0000000..89f58bc
+--- /dev/null
++++ b/ipc/kdbus/node.c
+@@ -0,0 +1,897 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/atomic.h>
++#include <linux/fs.h>
++#include <linux/idr.h>
++#include <linux/kdev_t.h>
++#include <linux/rbtree.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++
++#include "bus.h"
++#include "domain.h"
++#include "endpoint.h"
++#include "fs.h"
++#include "handle.h"
++#include "node.h"
++#include "util.h"
++
++/**
++ * DOC: kdbus nodes
++ *
++ * Nodes unify lifetime management across exposed kdbus objects and provide a
++ * hierarchy. Each kdbus object, that might be exposed to user-space, has a
++ * kdbus_node object embedded and is linked into the hierarchy. Each node can
++ * have any number (0-n) of child nodes linked. Each child retains a reference
++ * to its parent node. For root-nodes, the parent is NULL.
++ *
++ * Each node object goes through a bunch of states during it's lifetime:
++ *     * NEW
++ *       * LINKED    (can be skipped by NEW->FREED transition)
++ *         * ACTIVE  (can be skipped by LINKED->INACTIVE transition)
++ *       * INACTIVE
++ *       * DRAINED
++ *     * FREED
++ *
++ * Each node is allocated by the caller and initialized via kdbus_node_init().
++ * This never fails and sets the object into state NEW. From now on, ref-counts
++ * on the node manage its lifetime. During init, the ref-count is set to 1. Once
++ * it drops to 0, the node goes to state FREED and the node->free_cb() callback
++ * is called to deallocate any memory.
++ *
++ * After initializing a node, you usually link it into the hierarchy. You need
++ * to provide a parent node and a name. The node will be linked as child to the
++ * parent and a globally unique ID is assigned to the child. The name of the
++ * child must be unique for all children of this parent. Otherwise, linking the
++ * child will fail with -EEXIST.
++ * Note that the child is not marked active, yet. Admittedly, it prevents any
++ * other node from being linked with the same name (thus, it reserves that
++ * name), but any child-lookup (via name or unique ID) will never return this
++ * child unless it has been marked active.
++ *
++ * Once successfully linked, you can use kdbus_node_activate() to activate a
++ * child. This will mark the child active. This state can be skipped by directly
++ * deactivating the child via kdbus_node_deactivate() (see below).
++ * By activating a child, you enable any lookups on this child to succeed from
++ * now on. Furthermore, any code that got its hands on a reference to the node,
++ * can from now on "acquire" the node.
++ *
++ *     Active References (or: 'acquiring' and 'releasing' a node)
++ *     Additionally to normal object references, nodes support something we call
++ *     "active references". An active reference can be acquired via
++ *     kdbus_node_acquire() and released via kdbus_node_release(). A caller
++ *     _must_ own a normal object reference whenever calling those functions.
++ *     Unlike object references, acquiring an active reference can fail (by
++ *     returning 'false' from kdbus_node_acquire()). An active reference can
++ *     only be acquired if the node is marked active. If it is not marked
++ *     active, yet, or if it was already deactivated, no more active references
++ *     can be acquired, ever!
++ *     Active references are used to track tasks working on a node. Whenever a
++ *     task enters kernel-space to perform an action on a node, it acquires an
++ *     active reference, performs the action and releases the reference again.
++ *     While holding an active reference, the node is guaranteed to stay active.
++ *     If the node is deactivated in parallel, the node is marked as
++ *     deactivated, then we wait for all active references to be dropped, before
++ *     we finally proceed with any cleanups. That is, if you hold an active
++ *     reference to a node, any resources that are bound to the "active" state
++ *     are guaranteed to stay accessible until you release your reference.
++ *
++ *     Active-references are very similar to rw-locks, where acquiring a node is
++ *     equal to try-read-lock and releasing to read-unlock. Deactivating a node
++ *     means write-lock and never releasing it again.
++ *     Unlike rw-locks, the 'active reference' concept is more versatile and
++ *     avoids unusual rw-lock usage (never releasing a write-lock..).
++ *
++ *     It is safe to acquire multiple active-references recursively. But you
++ *     need to check the return value of kdbus_node_acquire() on _each_ call. It
++ *     may stop granting references at _any_ time.
++ *
++ *     You're free to perform any operations you want while holding an active
++ *     reference, except sleeping for an indefinite period. Sleeping for a fixed
++ *     amount of time is fine, but you usually should not wait on wait-queues
++ *     without a timeout.
++ *     For example, if you wait for I/O to happen, you should gather all data
++ *     and schedule the I/O operation, then release your active reference and
++ *     wait for it to complete. Then try to acquire a new reference. If it
++ *     fails, perform any cleanup (the node is now dead). Otherwise, you can
++ *     finish your operation.
++ *
++ * All nodes can be deactivated via kdbus_node_deactivate() at any time. You can
++ * call this multiple times, even in parallel or on nodes that were never
++ * linked, and it will just work. The only restriction is, you must not hold an
++ * active reference when calling kdbus_node_deactivate().
++ * By deactivating a node, it is immediately marked inactive. Then, we wait for
++ * all active references to be released (called 'draining' the node). This
++ * shouldn't take very long as we don't perform long-lasting operations while
++ * holding an active reference. Note that once the node is marked inactive, no
++ * new active references can be acquired.
++ * Once all active references are dropped, the node is considered 'drained'. Now
++ * kdbus_node_deactivate() is called on each child of the node before we
++ * continue deactivating our node. That is, once all children are entirely
++ * deactivated, we call ->release_cb() of our node. ->release_cb() can release
++ * any resources on that node which are bound to the "active" state of a node.
++ * When done, we unlink the node from its parent rb-tree, mark it as
++ * 'released' and return.
++ * If kdbus_node_deactivate() is called multiple times (even in parallel), all
++ * but one caller will just wait until the node is fully deactivated. That is,
++ * one random caller of kdbus_node_deactivate() is selected to call
++ * ->release_cb() and cleanup the node. Only once all this is done, all other
++ * callers will return from kdbus_node_deactivate(). That is, it doesn't matter
++ * whether you're the selected caller or not, it will only return after
++ * everything is fully done.
++ *
++ * When a node is activated, we acquire a normal object reference to the node.
++ * This reference is dropped after deactivation is fully done (and only iff the
++ * node really was activated). This allows callers to link+activate a child node
++ * and then drop all refs. The node will be deactivated together with the
++ * parent, and then be freed when this reference is dropped.
++ *
++ * Currently, nodes provide a bunch of resources that external code can use
++ * directly. This includes:
++ *
++ *     * node->waitq: Each node has its own wait-queue that is used to manage
++ *                    the 'active' state. When a node is deactivated, we wait on
++ *                    this queue until all active refs are dropped. Analogously,
++ *                    when you release an active reference on a deactivated
++ *                    node, and the active ref-count drops to 0, we wake up a
++ *                    single thread on this queue. Furthermore, once the
++ *                    ->release_cb() callback finished, we wake up all waiters.
++ *                    The node-owner is free to re-use this wait-queue for other
++ *                    purposes. As node-management uses this queue only during
++ *                    deactivation, it is usually totally fine to re-use the
++ *                    queue for other, preferably low-overhead, use-cases.
++ *
++ *     * node->type: This field defines the type of the owner of this node. It
++ *                   must be set during node initialization and must remain
++ *                   constant. The node management never looks at this value,
++ *                   but external users might use to gain access to the owner
++ *                   object of a node.
++ *                   It is totally up to the owner of the node to define what
++ *                   their type means. Usually it means you can access the
++ *                   parent structure via container_of(), as long as you hold an
++ *                   active reference to the node.
++ *
++ *     * node->free_cb:    callback after all references are dropped
++ *       node->release_cb: callback during node deactivation
++ *                         These fields must be set by the node owner during
++ *                         node initialization. They must remain constant. If
++ *                         NULL, they're skipped.
++ *
++ *     * node->mode: filesystem access modes
++ *       node->uid:  filesystem owner uid
++ *       node->gid:  filesystem owner gid
++ *                   These fields must be set by the node owner during node
++ *                   initialization. They must remain constant and may be
++ *                   accessed by other callers to properly initialize
++ *                   filesystem nodes.
++ *
++ *     * node->id: This is an unsigned 32bit integer allocated by an IDA. It is
++ *                 always kept as small as possible during allocation and is
++ *                 globally unique across all nodes allocated by this module. 0
++ *                 is reserved as "not assigned" and is the default.
++ *                 The ID is assigned during kdbus_node_link() and is kept until
++ *                 the object is freed. Thus, the ID surpasses the active
++ *                 lifetime of a node. As long as you hold an object reference
++ *                 to a node (and the node was linked once), the ID is valid and
++ *                 unique.
++ *
++ *     * node->name: name of this node
++ *       node->hash: 31bit hash-value of @name (range [2..INT_MAX-1])
++ *                   These values follow the same lifetime rules as node->id.
++ *                   They're initialized when the node is linked and then remain
++ *                   constant until the last object reference is dropped.
++ *                   Unlike the id, the name is only unique across all siblings
++ *                   and only until the node is deactivated. Currently, the name
++ *                   is even unique if linked but not activated, yet. This might
++ *                   change in the future, though. Code should not rely on this.
++ *
++ *     * node->lock:     lock to protect node->children, node->rb, node->parent
++ *     * node->parent: Reference to parent node. This is set during LINK time
++ *                     and is dropped during destruction. You must not access
++ *                     it unless you hold an active reference to the node or if
++ *                     you know the node is dead.
++ *     * node->children: rb-tree of all linked children of this node. You must
++ *                       not access this directly, but use one of the iterator
++ *                       or lookup helpers.
++ */
++
++/*
++ * Bias values track states of "active references". They're all negative. If a
++ * node is active, its active-ref-counter is >=0 and tracks all active
++ * references. Once a node is deactivaed, we subtract NODE_BIAS. This means, the
++ * counter is now negative but still counts the active references. Once it drops
++ * to exactly NODE_BIAS, we know all active references were dropped. Exactly one
++ * thread will change it to NODE_RELEASE now, perform cleanup and then put it
++ * into NODE_DRAINED. Once drained, all other threads that tried deactivating
++ * the node will now be woken up (thus, they wait until the node is fully done).
++ * The initial state during node-setup is NODE_NEW. If a node is directly
++ * deactivated without having ever been active, it is put into
++ * NODE_RELEASE_DIRECT instead of NODE_BIAS. This tracks this one-bit state
++ * across node-deactivation. The task putting it into NODE_RELEASE now knows
++ * whether the node was active before or not.
++ *
++ * Some archs implement atomic_sub(v) with atomic_add(-v), so reserve INT_MIN
++ * to avoid overflows if multiplied by -1.
++ */
++#define KDBUS_NODE_BIAS			(INT_MIN + 5)
++#define KDBUS_NODE_RELEASE_DIRECT	(KDBUS_NODE_BIAS - 1)
++#define KDBUS_NODE_RELEASE		(KDBUS_NODE_BIAS - 2)
++#define KDBUS_NODE_DRAINED		(KDBUS_NODE_BIAS - 3)
++#define KDBUS_NODE_NEW			(KDBUS_NODE_BIAS - 4)
++
++/* global unique ID mapping for kdbus nodes */
++DEFINE_IDA(kdbus_node_ida);
++
++/**
++ * kdbus_node_name_hash() - hash a name
++ * @name:	The string to hash
++ *
++ * This computes the hash of @name. It is guaranteed to be in the range
++ * [2..INT_MAX-1]. The values 1, 2 and INT_MAX are unused as they are reserved
++ * for the filesystem code.
++ *
++ * Return: hash value of the passed string
++ */
++static unsigned int kdbus_node_name_hash(const char *name)
++{
++	unsigned int hash;
++
++	/* reserve hash numbers 0, 1 and >=INT_MAX for magic directories */
++	hash = kdbus_strhash(name) & INT_MAX;
++	if (hash < 2)
++		hash += 2;
++	if (hash >= INT_MAX)
++		hash = INT_MAX - 1;
++
++	return hash;
++}
++
++/**
++ * kdbus_node_name_compare() - compare a name with a node's name
++ * @hash:	hash of the string to compare the node with
++ * @name:	name to compare the node with
++ * @node:	node to compare the name with
++ *
++ * Return: 0 if @name and @hash exactly match the information in @node, or
++ * an integer less than or greater than zero if @name is found, respectively,
++ * to be less than or be greater than the string stored in @node.
++ */
++static int kdbus_node_name_compare(unsigned int hash, const char *name,
++				   const struct kdbus_node *node)
++{
++	if (hash != node->hash)
++		return hash - node->hash;
++
++	return strcmp(name, node->name);
++}
++
++/**
++ * kdbus_node_init() - initialize a kdbus_node
++ * @node:	Pointer to the node to initialize
++ * @type:	The type the node will have (KDBUS_NODE_*)
++ *
++ * The caller is responsible of allocating @node and initializating it to zero.
++ * Once this call returns, you must use the node_ref() and node_unref()
++ * functions to manage this node.
++ */
++void kdbus_node_init(struct kdbus_node *node, unsigned int type)
++{
++	atomic_set(&node->refcnt, 1);
++	mutex_init(&node->lock);
++	node->id = 0;
++	node->type = type;
++	RB_CLEAR_NODE(&node->rb);
++	node->children = RB_ROOT;
++	init_waitqueue_head(&node->waitq);
++	atomic_set(&node->active, KDBUS_NODE_NEW);
++}
++
++/**
++ * kdbus_node_link() - link a node into the nodes system
++ * @node:	Pointer to the node to initialize
++ * @parent:	Pointer to a parent node, may be %NULL
++ * @name:	The name of the node (or NULL if root node)
++ *
++ * This links a node into the hierarchy. This must not be called multiple times.
++ * If @parent is NULL, the node becomes a new root node.
++ *
++ * This call will fail if @name is not unique across all its siblings or if no
++ * ID could be allocated. You must not activate a node if linking failed! It is
++ * safe to deactivate it, though.
++ *
++ * Once you linked a node, you must call kdbus_node_deactivate() before you drop
++ * the last reference (even if you never activate the node).
++ *
++ * Return: 0 on success. negative error otherwise.
++ */
++int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent,
++		    const char *name)
++{
++	int ret;
++
++	if (WARN_ON(node->type != KDBUS_NODE_DOMAIN && !parent))
++		return -EINVAL;
++
++	if (WARN_ON(parent && !name))
++		return -EINVAL;
++
++	if (name) {
++		node->name = kstrdup(name, GFP_KERNEL);
++		if (!node->name)
++			return -ENOMEM;
++
++		node->hash = kdbus_node_name_hash(name);
++	}
++
++	ret = ida_simple_get(&kdbus_node_ida, 1, 0, GFP_KERNEL);
++	if (ret < 0)
++		return ret;
++
++	node->id = ret;
++	ret = 0;
++
++	if (parent) {
++		struct rb_node **n, *prev;
++
++		if (!kdbus_node_acquire(parent))
++			return -ESHUTDOWN;
++
++		mutex_lock(&parent->lock);
++
++		n = &parent->children.rb_node;
++		prev = NULL;
++
++		while (*n) {
++			struct kdbus_node *pos;
++			int result;
++
++			pos = kdbus_node_from_rb(*n);
++			prev = *n;
++			result = kdbus_node_name_compare(node->hash,
++							 node->name,
++							 pos);
++			if (result == 0) {
++				ret = -EEXIST;
++				goto exit_unlock;
++			}
++
++			if (result < 0)
++				n = &pos->rb.rb_left;
++			else
++				n = &pos->rb.rb_right;
++		}
++
++		/* add new node and rebalance the tree */
++		rb_link_node(&node->rb, prev, n);
++		rb_insert_color(&node->rb, &parent->children);
++		node->parent = kdbus_node_ref(parent);
++
++exit_unlock:
++		mutex_unlock(&parent->lock);
++		kdbus_node_release(parent);
++	}
++
++	return ret;
++}
++
++/**
++ * kdbus_node_ref() - Acquire object reference
++ * @node:	node to acquire reference to (or NULL)
++ *
++ * This acquires a new reference to @node. You must already own a reference when
++ * calling this!
++ * If @node is NULL, this is a no-op.
++ *
++ * Return: @node is returned
++ */
++struct kdbus_node *kdbus_node_ref(struct kdbus_node *node)
++{
++	if (node)
++		atomic_inc(&node->refcnt);
++	return node;
++}
++
++/**
++ * kdbus_node_unref() - Drop object reference
++ * @node:	node to drop reference to (or NULL)
++ *
++ * This drops an object reference to @node. You must not access the node if you
++ * no longer own a reference.
++ * If the ref-count drops to 0, the object will be destroyed (->free_cb will be
++ * called).
++ *
++ * If you linked or activated the node, you must deactivate the node before you
++ * drop your last reference! If you didn't link or activate the node, you can
++ * drop any reference you want.
++ *
++ * Note that this calls into ->free_cb() and thus _might_ sleep. The ->free_cb()
++ * callbacks must not acquire any outer locks, though. So you can safely drop
++ * references while holding locks.
++ *
++ * If @node is NULL, this is a no-op.
++ *
++ * Return: This always returns NULL
++ */
++struct kdbus_node *kdbus_node_unref(struct kdbus_node *node)
++{
++	if (node && atomic_dec_and_test(&node->refcnt)) {
++		struct kdbus_node safe = *node;
++
++		WARN_ON(atomic_read(&node->active) != KDBUS_NODE_DRAINED);
++		WARN_ON(!RB_EMPTY_NODE(&node->rb));
++
++		if (node->free_cb)
++			node->free_cb(node);
++		if (safe.id > 0)
++			ida_simple_remove(&kdbus_node_ida, safe.id);
++
++		kfree(safe.name);
++
++		/*
++		 * kdbusfs relies on the parent to be available even after the
++		 * node was deactivated and unlinked. Therefore, we pin it
++		 * until a node is destroyed.
++		 */
++		kdbus_node_unref(safe.parent);
++	}
++
++	return NULL;
++}
++
++/**
++ * kdbus_node_is_active() - test whether a node is active
++ * @node:	node to test
++ *
++ * This checks whether @node is active. That means, @node was linked and
++ * activated by the node owner and hasn't been deactivated, yet. If, and only
++ * if, a node is active, kdbus_node_acquire() will be able to acquire active
++ * references.
++ *
++ * Note that this function does not give any lifetime guarantees. After this
++ * call returns, the node might be deactivated immediately. Normally, what you
++ * want is to acquire a real active reference via kdbus_node_acquire().
++ *
++ * Return: true if @node is active, false otherwise
++ */
++bool kdbus_node_is_active(struct kdbus_node *node)
++{
++	return atomic_read(&node->active) >= 0;
++}
++
++/**
++ * kdbus_node_is_deactivated() - test whether a node was already deactivated
++ * @node:	node to test
++ *
++ * This checks whether kdbus_node_deactivate() was called on @node. Note that
++ * this might be true even if you never deactivated the node directly, but only
++ * one of its ancestors.
++ *
++ * Note that even if this returns 'false', the node might get deactivated
++ * immediately after the call returns.
++ *
++ * Return: true if @node was already deactivated, false if not
++ */
++bool kdbus_node_is_deactivated(struct kdbus_node *node)
++{
++	int v;
++
++	v = atomic_read(&node->active);
++	return v != KDBUS_NODE_NEW && v < 0;
++}
++
++/**
++ * kdbus_node_activate() - activate a node
++ * @node:	node to activate
++ *
++ * This marks @node as active if, and only if, the node wasn't activated nor
++ * deactivated, yet, and the parent is still active. Any but the first call to
++ * kdbus_node_activate() is a no-op.
++ * If you called kdbus_node_deactivate() before, then even the first call to
++ * kdbus_node_activate() will be a no-op.
++ *
++ * This call doesn't give any lifetime guarantees. The node might get
++ * deactivated immediately after this call returns. Or the parent might already
++ * be deactivated, which will make this call a no-op.
++ *
++ * If this call successfully activated a node, it will take an object reference
++ * to it. This reference is dropped after the node is deactivated. Therefore,
++ * the object owner can safely drop their reference to @node iff they know that
++ * its parent node will get deactivated at some point. Once the parent node is
++ * deactivated, it will deactivate all its child and thus drop this reference
++ * again.
++ *
++ * Return: True if this call successfully activated the node, otherwise false.
++ *         Note that this might return false, even if the node is still active
++ *         (eg., if you called this a second time).
++ */
++bool kdbus_node_activate(struct kdbus_node *node)
++{
++	bool res = false;
++
++	mutex_lock(&node->lock);
++	if (atomic_read(&node->active) == KDBUS_NODE_NEW) {
++		atomic_sub(KDBUS_NODE_NEW, &node->active);
++		/* activated nodes have ref +1 */
++		kdbus_node_ref(node);
++		res = true;
++	}
++	mutex_unlock(&node->lock);
++
++	return res;
++}
++
++/**
++ * kdbus_node_deactivate() - deactivate a node
++ * @node:	The node to deactivate.
++ *
++ * This function recursively deactivates this node and all its children. It
++ * returns only once all children and the node itself were recursively disabled
++ * (even if you call this function multiple times in parallel).
++ *
++ * It is safe to call this function on _any_ node that was initialized _any_
++ * number of times.
++ *
++ * This call may sleep, as it waits for all active references to be dropped.
++ */
++void kdbus_node_deactivate(struct kdbus_node *node)
++{
++	struct kdbus_node *pos, *child;
++	struct rb_node *rb;
++	int v_pre, v_post;
++
++	pos = node;
++
++	/*
++	 * To avoid recursion, we perform back-tracking while deactivating
++	 * nodes. For each node we enter, we first mark the active-counter as
++	 * deactivated by adding BIAS. If the node as children, we set the first
++	 * child as current position and start over. If the node has no
++	 * children, we drain the node by waiting for all active refs to be
++	 * dropped and then releasing the node.
++	 *
++	 * After the node is released, we set its parent as current position
++	 * and start over. If the current position was the initial node, we're
++	 * done.
++	 *
++	 * Note that this function can be called in parallel by multiple
++	 * callers. We make sure that each node is only released once, and any
++	 * racing caller will wait until the other thread fully released that
++	 * node.
++	 */
++
++	for (;;) {
++		/*
++		 * Add BIAS to node->active to mark it as inactive. If it was
++		 * never active before, immediately mark it as RELEASE_INACTIVE
++		 * so we remember this state.
++		 * We cannot remember v_pre as we might iterate into the
++		 * children, overwriting v_pre, before we can release our node.
++		 */
++		mutex_lock(&pos->lock);
++		v_pre = atomic_read(&pos->active);
++		if (v_pre >= 0)
++			atomic_add_return(KDBUS_NODE_BIAS, &pos->active);
++		else if (v_pre == KDBUS_NODE_NEW)
++			atomic_set(&pos->active, KDBUS_NODE_RELEASE_DIRECT);
++		mutex_unlock(&pos->lock);
++
++		/* wait until all active references were dropped */
++		wait_event(pos->waitq,
++			   atomic_read(&pos->active) <= KDBUS_NODE_BIAS);
++
++		mutex_lock(&pos->lock);
++		/* recurse into first child if any */
++		rb = rb_first(&pos->children);
++		if (rb) {
++			child = kdbus_node_ref(kdbus_node_from_rb(rb));
++			mutex_unlock(&pos->lock);
++			pos = child;
++			continue;
++		}
++
++		/* mark object as RELEASE */
++		v_post = atomic_read(&pos->active);
++		if (v_post == KDBUS_NODE_BIAS ||
++		    v_post == KDBUS_NODE_RELEASE_DIRECT)
++			atomic_set(&pos->active, KDBUS_NODE_RELEASE);
++		mutex_unlock(&pos->lock);
++
++		/*
++		 * If this is the thread that marked the object as RELEASE, we
++		 * perform the actual release. Otherwise, we wait until the
++		 * release is done and the node is marked as DRAINED.
++		 */
++		if (v_post == KDBUS_NODE_BIAS ||
++		    v_post == KDBUS_NODE_RELEASE_DIRECT) {
++			if (pos->release_cb)
++				pos->release_cb(pos, v_post == KDBUS_NODE_BIAS);
++
++			if (pos->parent) {
++				mutex_lock(&pos->parent->lock);
++				if (!RB_EMPTY_NODE(&pos->rb)) {
++					rb_erase(&pos->rb,
++						 &pos->parent->children);
++					RB_CLEAR_NODE(&pos->rb);
++				}
++				mutex_unlock(&pos->parent->lock);
++			}
++
++			/* mark as DRAINED */
++			atomic_set(&pos->active, KDBUS_NODE_DRAINED);
++			wake_up_all(&pos->waitq);
++
++			/* drop VFS cache */
++			kdbus_fs_flush(pos);
++
++			/*
++			 * If the node was activated and someone subtracted BIAS
++			 * from it to deactivate it, we, and only us, are
++			 * responsible to release the extra ref-count that was
++			 * taken once in kdbus_node_activate().
++			 * If the node was never activated, no-one ever
++			 * subtracted BIAS, but instead skipped that state and
++			 * immediately went to NODE_RELEASE_DIRECT. In that case
++			 * we must not drop the reference.
++			 */
++			if (v_post == KDBUS_NODE_BIAS)
++				kdbus_node_unref(pos);
++		} else {
++			/* wait until object is DRAINED */
++			wait_event(pos->waitq,
++			    atomic_read(&pos->active) == KDBUS_NODE_DRAINED);
++		}
++
++		/*
++		 * We're done with the current node. Continue on its parent
++		 * again, which will try deactivating its next child, or itself
++		 * if no child is left.
++		 * If we've reached our initial node again, we are done and
++		 * can safely return.
++		 */
++		if (pos == node)
++			break;
++
++		child = pos;
++		pos = pos->parent;
++		kdbus_node_unref(child);
++	}
++}
++
++/**
++ * kdbus_node_acquire() - Acquire an active ref on a node
++ * @node:	The node
++ *
++ * This acquires an active-reference to @node. This will only succeed if the
++ * node is active. You must release this active reference via
++ * kdbus_node_release() again.
++ *
++ * See the introduction to "active references" for more details.
++ *
++ * Return: %true if @node was non-NULL and active
++ */
++bool kdbus_node_acquire(struct kdbus_node *node)
++{
++	return node && atomic_inc_unless_negative(&node->active);
++}
++
++/**
++ * kdbus_node_release() - Release an active ref on a node
++ * @node:	The node
++ *
++ * This releases an active reference that was previously acquired via
++ * kdbus_node_acquire(). See kdbus_node_acquire() for details.
++ */
++void kdbus_node_release(struct kdbus_node *node)
++{
++	if (node && atomic_dec_return(&node->active) == KDBUS_NODE_BIAS)
++		wake_up(&node->waitq);
++}
++
++/**
++ * kdbus_node_find_child() - Find child by name
++ * @node:	parent node to search through
++ * @name:	name of child node
++ *
++ * This searches through all children of @node for a child-node with name @name.
++ * If not found, or if the child is deactivated, NULL is returned. Otherwise,
++ * the child is acquired and a new reference is returned.
++ *
++ * If you're done with the child, you need to release it and drop your
++ * reference.
++ *
++ * This function does not acquire the parent node. However, if the parent was
++ * already deactivated, then kdbus_node_deactivate() will, at some point, also
++ * deactivate the child. Therefore, we can rely on the explicit ordering during
++ * deactivation.
++ *
++ * Return: Reference to acquired child node, or NULL if not found / not active.
++ */
++struct kdbus_node *kdbus_node_find_child(struct kdbus_node *node,
++					 const char *name)
++{
++	struct kdbus_node *child;
++	struct rb_node *rb;
++	unsigned int hash;
++	int ret;
++
++	hash = kdbus_node_name_hash(name);
++
++	mutex_lock(&node->lock);
++	rb = node->children.rb_node;
++	while (rb) {
++		child = kdbus_node_from_rb(rb);
++		ret = kdbus_node_name_compare(hash, name, child);
++		if (ret < 0)
++			rb = rb->rb_left;
++		else if (ret > 0)
++			rb = rb->rb_right;
++		else
++			break;
++	}
++	if (rb && kdbus_node_acquire(child))
++		kdbus_node_ref(child);
++	else
++		child = NULL;
++	mutex_unlock(&node->lock);
++
++	return child;
++}
++
++static struct kdbus_node *node_find_closest_unlocked(struct kdbus_node *node,
++						     unsigned int hash,
++						     const char *name)
++{
++	struct kdbus_node *n, *pos = NULL;
++	struct rb_node *rb;
++	int res;
++
++	/*
++	 * Find the closest child with ``node->hash >= hash'', or, if @name is
++	 * valid, ``node->name >= name'' (where '>=' is the lex. order).
++	 */
++
++	rb = node->children.rb_node;
++	while (rb) {
++		n = kdbus_node_from_rb(rb);
++
++		if (name)
++			res = kdbus_node_name_compare(hash, name, n);
++		else
++			res = hash - n->hash;
++
++		if (res <= 0) {
++			rb = rb->rb_left;
++			pos = n;
++		} else { /* ``hash > n->hash'', ``name > n->name'' */
++			rb = rb->rb_right;
++		}
++	}
++
++	return pos;
++}
++
++/**
++ * kdbus_node_find_closest() - Find closest child-match
++ * @node:	parent node to search through
++ * @hash:	hash value to find closest match for
++ *
++ * Find the closest child of @node with a hash greater than or equal to @hash.
++ * The closest match is the left-most child of @node with this property. Which
++ * means, it is the first child with that hash returned by
++ * kdbus_node_next_child(), if you'd iterate the whole parent node.
++ *
++ * Return: Reference to acquired child, or NULL if none found.
++ */
++struct kdbus_node *kdbus_node_find_closest(struct kdbus_node *node,
++					   unsigned int hash)
++{
++	struct kdbus_node *child;
++	struct rb_node *rb;
++
++	mutex_lock(&node->lock);
++
++	child = node_find_closest_unlocked(node, hash, NULL);
++	while (child && !kdbus_node_acquire(child)) {
++		rb = rb_next(&child->rb);
++		if (rb)
++			child = kdbus_node_from_rb(rb);
++		else
++			child = NULL;
++	}
++	kdbus_node_ref(child);
++
++	mutex_unlock(&node->lock);
++
++	return child;
++}
++
++/**
++ * kdbus_node_next_child() - Acquire next child
++ * @node:	parent node
++ * @prev:	previous child-node position or NULL
++ *
++ * This function returns a reference to the next active child of @node, after
++ * the passed position @prev. If @prev is NULL, a reference to the first active
++ * child is returned. If no more active children are found, NULL is returned.
++ *
++ * This function acquires the next child it returns. If you're done with the
++ * returned pointer, you need to release _and_ unref it.
++ *
++ * The passed in pointer @prev is not modified by this function, and it does
++ * *not* have to be active. If @prev was acquired via different means, or if it
++ * was unlinked from its parent before you pass it in, then this iterator will
++ * still return the next active child (it will have to search through the
++ * rb-tree based on the node-name, though).
++ * However, @prev must not be linked to a different parent than @node!
++ *
++ * Return: Reference to next acquired child, or NULL if at the end.
++ */
++struct kdbus_node *kdbus_node_next_child(struct kdbus_node *node,
++					 struct kdbus_node *prev)
++{
++	struct kdbus_node *pos = NULL;
++	struct rb_node *rb;
++
++	mutex_lock(&node->lock);
++
++	if (!prev) {
++		/*
++		 * New iteration; find first node in rb-tree and try to acquire
++		 * it. If we got it, directly return it as first element.
++		 * Otherwise, the loop below will find the next active node.
++		 */
++		rb = rb_first(&node->children);
++		if (!rb)
++			goto exit;
++		pos = kdbus_node_from_rb(rb);
++		if (kdbus_node_acquire(pos))
++			goto exit;
++	} else if (RB_EMPTY_NODE(&prev->rb)) {
++		/*
++		 * The current iterator is no longer linked to the rb-tree. Use
++		 * its hash value and name to find the next _higher_ node and
++		 * acquire it. If we got it, return it as next element.
++		 * Otherwise, the loop below will find the next active node.
++		 */
++		pos = node_find_closest_unlocked(node, prev->hash, prev->name);
++		if (!pos)
++			goto exit;
++		if (kdbus_node_acquire(pos))
++			goto exit;
++	} else {
++		/*
++		 * The current iterator is still linked to the parent. Set it
++		 * as current position and use the loop below to find the next
++		 * active element.
++		 */
++		pos = prev;
++	}
++
++	/* @pos was already returned or is inactive; find next active node */
++	do {
++		rb = rb_next(&pos->rb);
++		if (rb)
++			pos = kdbus_node_from_rb(rb);
++		else
++			pos = NULL;
++	} while (pos && !kdbus_node_acquire(pos));
++
++exit:
++	/* @pos is NULL or acquired. Take ref if non-NULL and return it */
++	kdbus_node_ref(pos);
++	mutex_unlock(&node->lock);
++	return pos;
++}
+diff --git a/ipc/kdbus/node.h b/ipc/kdbus/node.h
+new file mode 100644
+index 0000000..970e02b
+--- /dev/null
++++ b/ipc/kdbus/node.h
+@@ -0,0 +1,86 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_NODE_H
++#define __KDBUS_NODE_H
++
++#include <linux/atomic.h>
++#include <linux/kernel.h>
++#include <linux/mutex.h>
++#include <linux/wait.h>
++
++struct kdbus_node;
++
++enum kdbus_node_type {
++	KDBUS_NODE_DOMAIN,
++	KDBUS_NODE_CONTROL,
++	KDBUS_NODE_BUS,
++	KDBUS_NODE_ENDPOINT,
++};
++
++typedef void (*kdbus_node_free_t) (struct kdbus_node *node);
++typedef void (*kdbus_node_release_t) (struct kdbus_node *node, bool was_active);
++
++struct kdbus_node {
++	atomic_t refcnt;
++	atomic_t active;
++	wait_queue_head_t waitq;
++
++	/* static members */
++	unsigned int type;
++	kdbus_node_free_t free_cb;
++	kdbus_node_release_t release_cb;
++	umode_t mode;
++	kuid_t uid;
++	kgid_t gid;
++
++	/* valid once linked */
++	char *name;
++	unsigned int hash;
++	unsigned int id;
++	struct kdbus_node *parent; /* may be NULL */
++
++	/* valid iff active */
++	struct mutex lock;
++	struct rb_node rb;
++	struct rb_root children;
++};
++
++#define kdbus_node_from_rb(_node) rb_entry((_node), struct kdbus_node, rb)
++
++extern struct ida kdbus_node_ida;
++
++void kdbus_node_init(struct kdbus_node *node, unsigned int type);
++
++int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent,
++		    const char *name);
++
++struct kdbus_node *kdbus_node_ref(struct kdbus_node *node);
++struct kdbus_node *kdbus_node_unref(struct kdbus_node *node);
++
++bool kdbus_node_is_active(struct kdbus_node *node);
++bool kdbus_node_is_deactivated(struct kdbus_node *node);
++bool kdbus_node_activate(struct kdbus_node *node);
++void kdbus_node_deactivate(struct kdbus_node *node);
++
++bool kdbus_node_acquire(struct kdbus_node *node);
++void kdbus_node_release(struct kdbus_node *node);
++
++struct kdbus_node *kdbus_node_find_child(struct kdbus_node *node,
++					 const char *name);
++struct kdbus_node *kdbus_node_find_closest(struct kdbus_node *node,
++					   unsigned int hash);
++struct kdbus_node *kdbus_node_next_child(struct kdbus_node *node,
++					 struct kdbus_node *prev);
++
++#endif
+diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c
+new file mode 100644
+index 0000000..375758c
+--- /dev/null
++++ b/ipc/kdbus/notify.c
+@@ -0,0 +1,204 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "domain.h"
++#include "endpoint.h"
++#include "item.h"
++#include "message.h"
++#include "notify.h"
++
++static inline void kdbus_notify_add_tail(struct kdbus_staging *staging,
++					 struct kdbus_bus *bus)
++{
++	spin_lock(&bus->notify_lock);
++	list_add_tail(&staging->notify_entry, &bus->notify_list);
++	spin_unlock(&bus->notify_lock);
++}
++
++static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id,
++			      u64 cookie, u64 msg_type)
++{
++	struct kdbus_staging *s;
++
++	s = kdbus_staging_new_kernel(bus, id, cookie, 0, msg_type);
++	if (IS_ERR(s))
++		return PTR_ERR(s);
++
++	kdbus_notify_add_tail(s, bus);
++	return 0;
++}
++
++/**
++ * kdbus_notify_reply_timeout() - queue a timeout reply
++ * @bus:		Bus which queues the messages
++ * @id:			The destination's connection ID
++ * @cookie:		The cookie to set in the reply.
++ *
++ * Queues a message that has a KDBUS_ITEM_REPLY_TIMEOUT item attached.
++ *
++ * Return: 0 on success, negative errno on failure.
++ */
++int kdbus_notify_reply_timeout(struct kdbus_bus *bus, u64 id, u64 cookie)
++{
++	return kdbus_notify_reply(bus, id, cookie, KDBUS_ITEM_REPLY_TIMEOUT);
++}
++
++/**
++ * kdbus_notify_reply_dead() - queue a 'dead' reply
++ * @bus:		Bus which queues the messages
++ * @id:			The destination's connection ID
++ * @cookie:		The cookie to set in the reply.
++ *
++ * Queues a message that has a KDBUS_ITEM_REPLY_DEAD item attached.
++ *
++ * Return: 0 on success, negative errno on failure.
++ */
++int kdbus_notify_reply_dead(struct kdbus_bus *bus, u64 id, u64 cookie)
++{
++	return kdbus_notify_reply(bus, id, cookie, KDBUS_ITEM_REPLY_DEAD);
++}
++
++/**
++ * kdbus_notify_name_change() - queue a notification about a name owner change
++ * @bus:		Bus which queues the messages
++ * @type:		The type if the notification; KDBUS_ITEM_NAME_ADD,
++ *			KDBUS_ITEM_NAME_CHANGE or KDBUS_ITEM_NAME_REMOVE
++ * @old_id:		The id of the connection that used to own the name
++ * @new_id:		The id of the new owner connection
++ * @old_flags:		The flags to pass in the KDBUS_ITEM flags field for
++ *			the old owner
++ * @new_flags:		The flags to pass in the KDBUS_ITEM flags field for
++ *			the new owner
++ * @name:		The name that was removed or assigned to a new owner
++ *
++ * Return: 0 on success, negative errno on failure.
++ */
++int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type,
++			     u64 old_id, u64 new_id,
++			     u64 old_flags, u64 new_flags,
++			     const char *name)
++{
++	size_t name_len, extra_size;
++	struct kdbus_staging *s;
++
++	name_len = strlen(name) + 1;
++	extra_size = sizeof(struct kdbus_notify_name_change) + name_len;
++
++	s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
++				     extra_size, type);
++	if (IS_ERR(s))
++		return PTR_ERR(s);
++
++	s->notify->name_change.old_id.id = old_id;
++	s->notify->name_change.old_id.flags = old_flags;
++	s->notify->name_change.new_id.id = new_id;
++	s->notify->name_change.new_id.flags = new_flags;
++	memcpy(s->notify->name_change.name, name, name_len);
++
++	kdbus_notify_add_tail(s, bus);
++	return 0;
++}
++
++/**
++ * kdbus_notify_id_change() - queue a notification about a unique ID change
++ * @bus:		Bus which queues the messages
++ * @type:		The type if the notification; KDBUS_ITEM_ID_ADD or
++ *			KDBUS_ITEM_ID_REMOVE
++ * @id:			The id of the connection that was added or removed
++ * @flags:		The flags to pass in the KDBUS_ITEM flags field
++ *
++ * Return: 0 on success, negative errno on failure.
++ */
++int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags)
++{
++	struct kdbus_staging *s;
++	size_t extra_size;
++
++	extra_size = sizeof(struct kdbus_notify_id_change);
++	s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
++				     extra_size, type);
++	if (IS_ERR(s))
++		return PTR_ERR(s);
++
++	s->notify->id_change.id = id;
++	s->notify->id_change.flags = flags;
++
++	kdbus_notify_add_tail(s, bus);
++	return 0;
++}
++
++/**
++ * kdbus_notify_flush() - send a list of collected messages
++ * @bus:		Bus which queues the messages
++ *
++ * The list is empty after sending the messages.
++ */
++void kdbus_notify_flush(struct kdbus_bus *bus)
++{
++	LIST_HEAD(notify_list);
++	struct kdbus_staging *s, *tmp;
++
++	mutex_lock(&bus->notify_flush_lock);
++	down_read(&bus->name_registry->rwlock);
++
++	spin_lock(&bus->notify_lock);
++	list_splice_init(&bus->notify_list, &notify_list);
++	spin_unlock(&bus->notify_lock);
++
++	list_for_each_entry_safe(s, tmp, &notify_list, notify_entry) {
++		if (s->msg->dst_id != KDBUS_DST_ID_BROADCAST) {
++			struct kdbus_conn *conn;
++
++			conn = kdbus_bus_find_conn_by_id(bus, s->msg->dst_id);
++			if (conn) {
++				kdbus_bus_eavesdrop(bus, NULL, s);
++				kdbus_conn_entry_insert(NULL, conn, s, NULL,
++							NULL);
++				kdbus_conn_unref(conn);
++			}
++		} else {
++			kdbus_bus_broadcast(bus, NULL, s);
++		}
++
++		list_del(&s->notify_entry);
++		kdbus_staging_free(s);
++	}
++
++	up_read(&bus->name_registry->rwlock);
++	mutex_unlock(&bus->notify_flush_lock);
++}
++
++/**
++ * kdbus_notify_free() - free a list of collected messages
++ * @bus:		Bus which queues the messages
++ */
++void kdbus_notify_free(struct kdbus_bus *bus)
++{
++	struct kdbus_staging *s, *tmp;
++
++	list_for_each_entry_safe(s, tmp, &bus->notify_list, notify_entry) {
++		list_del(&s->notify_entry);
++		kdbus_staging_free(s);
++	}
++}
+diff --git a/ipc/kdbus/notify.h b/ipc/kdbus/notify.h
+new file mode 100644
+index 0000000..03df464
+--- /dev/null
++++ b/ipc/kdbus/notify.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_NOTIFY_H
++#define __KDBUS_NOTIFY_H
++
++struct kdbus_bus;
++
++int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags);
++int kdbus_notify_reply_timeout(struct kdbus_bus *bus, u64 id, u64 cookie);
++int kdbus_notify_reply_dead(struct kdbus_bus *bus, u64 id, u64 cookie);
++int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type,
++			     u64 old_id, u64 new_id,
++			     u64 old_flags, u64 new_flags,
++			     const char *name);
++void kdbus_notify_flush(struct kdbus_bus *bus);
++void kdbus_notify_free(struct kdbus_bus *bus);
++
++#endif
+diff --git a/ipc/kdbus/policy.c b/ipc/kdbus/policy.c
+new file mode 100644
+index 0000000..f2618e15
+--- /dev/null
++++ b/ipc/kdbus/policy.c
+@@ -0,0 +1,489 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/dcache.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/mutex.h>
++#include <linux/sched.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "domain.h"
++#include "item.h"
++#include "names.h"
++#include "policy.h"
++
++#define KDBUS_POLICY_HASH_SIZE	64
++
++/**
++ * struct kdbus_policy_db_entry_access - a database entry access item
++ * @type:		One of KDBUS_POLICY_ACCESS_* types
++ * @access:		Access to grant. One of KDBUS_POLICY_*
++ * @uid:		For KDBUS_POLICY_ACCESS_USER, the global uid
++ * @gid:		For KDBUS_POLICY_ACCESS_GROUP, the global gid
++ * @list:		List entry item for the entry's list
++ *
++ * This is the internal version of struct kdbus_policy_db_access.
++ */
++struct kdbus_policy_db_entry_access {
++	u8 type;		/* USER, GROUP, WORLD */
++	u8 access;		/* OWN, TALK, SEE */
++	union {
++		kuid_t uid;	/* global uid */
++		kgid_t gid;	/* global gid */
++	};
++	struct list_head list;
++};
++
++/**
++ * struct kdbus_policy_db_entry - a policy database entry
++ * @name:		The name to match the policy entry against
++ * @hentry:		The hash entry for the database's entries_hash
++ * @access_list:	List head for keeping tracks of the entry's
++ *			access items.
++ * @owner:		The owner of this entry. Can be a kdbus_conn or
++ *			a kdbus_ep object.
++ * @wildcard:		The name is a wildcard, such as ending on '.*'
++ */
++struct kdbus_policy_db_entry {
++	char *name;
++	struct hlist_node hentry;
++	struct list_head access_list;
++	const void *owner;
++	bool wildcard:1;
++};
++
++static void kdbus_policy_entry_free(struct kdbus_policy_db_entry *e)
++{
++	struct kdbus_policy_db_entry_access *a, *tmp;
++
++	list_for_each_entry_safe(a, tmp, &e->access_list, list) {
++		list_del(&a->list);
++		kfree(a);
++	}
++
++	kfree(e->name);
++	kfree(e);
++}
++
++static unsigned int kdbus_strnhash(const char *str, size_t len)
++{
++	unsigned long hash = init_name_hash();
++
++	while (len--)
++		hash = partial_name_hash(*str++, hash);
++
++	return end_name_hash(hash);
++}
++
++static const struct kdbus_policy_db_entry *
++kdbus_policy_lookup(struct kdbus_policy_db *db, const char *name, u32 hash)
++{
++	struct kdbus_policy_db_entry *e;
++	const char *dot;
++	size_t len;
++
++	/* find exact match */
++	hash_for_each_possible(db->entries_hash, e, hentry, hash)
++		if (strcmp(e->name, name) == 0 && !e->wildcard)
++			return e;
++
++	/* find wildcard match */
++
++	dot = strrchr(name, '.');
++	if (!dot)
++		return NULL;
++
++	len = dot - name;
++	hash = kdbus_strnhash(name, len);
++
++	hash_for_each_possible(db->entries_hash, e, hentry, hash)
++		if (e->wildcard && !strncmp(e->name, name, len) &&
++		    !e->name[len])
++			return e;
++
++	return NULL;
++}
++
++/**
++ * kdbus_policy_db_clear - release all memory from a policy db
++ * @db:		The policy database
++ */
++void kdbus_policy_db_clear(struct kdbus_policy_db *db)
++{
++	struct kdbus_policy_db_entry *e;
++	struct hlist_node *tmp;
++	unsigned int i;
++
++	/* purge entries */
++	down_write(&db->entries_rwlock);
++	hash_for_each_safe(db->entries_hash, i, tmp, e, hentry) {
++		hash_del(&e->hentry);
++		kdbus_policy_entry_free(e);
++	}
++	up_write(&db->entries_rwlock);
++}
++
++/**
++ * kdbus_policy_db_init() - initialize a new policy database
++ * @db:		The location of the database
++ *
++ * This initializes a new policy-db. The underlying memory must have been
++ * cleared to zero by the caller.
++ */
++void kdbus_policy_db_init(struct kdbus_policy_db *db)
++{
++	hash_init(db->entries_hash);
++	init_rwsem(&db->entries_rwlock);
++}
++
++/**
++ * kdbus_policy_query_unlocked() - Query the policy database
++ * @db:		Policy database
++ * @cred:	Credentials to test against
++ * @name:	Name to query
++ * @hash:	Hash value of @name
++ *
++ * Same as kdbus_policy_query() but requires the caller to lock the policy
++ * database against concurrent writes.
++ *
++ * Return: The highest KDBUS_POLICY_* access type found, or -EPERM if none.
++ */
++int kdbus_policy_query_unlocked(struct kdbus_policy_db *db,
++				const struct cred *cred, const char *name,
++				unsigned int hash)
++{
++	struct kdbus_policy_db_entry_access *a;
++	const struct kdbus_policy_db_entry *e;
++	int i, highest = -EPERM;
++
++	e = kdbus_policy_lookup(db, name, hash);
++	if (!e)
++		return -EPERM;
++
++	list_for_each_entry(a, &e->access_list, list) {
++		if ((int)a->access <= highest)
++			continue;
++
++		switch (a->type) {
++		case KDBUS_POLICY_ACCESS_USER:
++			if (uid_eq(cred->euid, a->uid))
++				highest = a->access;
++			break;
++		case KDBUS_POLICY_ACCESS_GROUP:
++			if (gid_eq(cred->egid, a->gid)) {
++				highest = a->access;
++				break;
++			}
++
++			for (i = 0; i < cred->group_info->ngroups; i++) {
++				kgid_t gid = GROUP_AT(cred->group_info, i);
++
++				if (gid_eq(gid, a->gid)) {
++					highest = a->access;
++					break;
++				}
++			}
++
++			break;
++		case KDBUS_POLICY_ACCESS_WORLD:
++			highest = a->access;
++			break;
++		}
++
++		/* OWN is the highest possible policy */
++		if (highest >= KDBUS_POLICY_OWN)
++			break;
++	}
++
++	return highest;
++}
++
++/**
++ * kdbus_policy_query() - Query the policy database
++ * @db:		Policy database
++ * @cred:	Credentials to test against
++ * @name:	Name to query
++ * @hash:	Hash value of @name
++ *
++ * Query the policy database @db for the access rights of @cred to the name
++ * @name. The access rights of @cred are returned, or -EPERM if no access is
++ * granted.
++ *
++ * This call effectively searches for the highest access-right granted to
++ * @cred. The caller should really cache those as policy lookups are rather
++ * expensive.
++ *
++ * Return: The highest KDBUS_POLICY_* access type found, or -EPERM if none.
++ */
++int kdbus_policy_query(struct kdbus_policy_db *db, const struct cred *cred,
++		       const char *name, unsigned int hash)
++{
++	int ret;
++
++	down_read(&db->entries_rwlock);
++	ret = kdbus_policy_query_unlocked(db, cred, name, hash);
++	up_read(&db->entries_rwlock);
++
++	return ret;
++}
++
++static void __kdbus_policy_remove_owner(struct kdbus_policy_db *db,
++					const void *owner)
++{
++	struct kdbus_policy_db_entry *e;
++	struct hlist_node *tmp;
++	int i;
++
++	hash_for_each_safe(db->entries_hash, i, tmp, e, hentry)
++		if (e->owner == owner) {
++			hash_del(&e->hentry);
++			kdbus_policy_entry_free(e);
++		}
++}
++
++/**
++ * kdbus_policy_remove_owner() - remove all entries related to a connection
++ * @db:		The policy database
++ * @owner:	The connection which items to remove
++ */
++void kdbus_policy_remove_owner(struct kdbus_policy_db *db,
++			       const void *owner)
++{
++	down_write(&db->entries_rwlock);
++	__kdbus_policy_remove_owner(db, owner);
++	up_write(&db->entries_rwlock);
++}
++
++/*
++ * Convert user provided policy access to internal kdbus policy
++ * access
++ */
++static struct kdbus_policy_db_entry_access *
++kdbus_policy_make_access(const struct kdbus_policy_access *uaccess)
++{
++	int ret;
++	struct kdbus_policy_db_entry_access *a;
++
++	a = kzalloc(sizeof(*a), GFP_KERNEL);
++	if (!a)
++		return ERR_PTR(-ENOMEM);
++
++	ret = -EINVAL;
++	switch (uaccess->access) {
++	case KDBUS_POLICY_SEE:
++	case KDBUS_POLICY_TALK:
++	case KDBUS_POLICY_OWN:
++		a->access = uaccess->access;
++		break;
++	default:
++		goto err;
++	}
++
++	switch (uaccess->type) {
++	case KDBUS_POLICY_ACCESS_USER:
++		a->uid = make_kuid(current_user_ns(), uaccess->id);
++		if (!uid_valid(a->uid))
++			goto err;
++
++		break;
++	case KDBUS_POLICY_ACCESS_GROUP:
++		a->gid = make_kgid(current_user_ns(), uaccess->id);
++		if (!gid_valid(a->gid))
++			goto err;
++
++		break;
++	case KDBUS_POLICY_ACCESS_WORLD:
++		break;
++	default:
++		goto err;
++	}
++
++	a->type = uaccess->type;
++
++	return a;
++
++err:
++	kfree(a);
++	return ERR_PTR(ret);
++}
++
++/**
++ * kdbus_policy_set() - set a connection's policy rules
++ * @db:				The policy database
++ * @items:			A list of kdbus_item elements that contain both
++ *				names and access rules to set.
++ * @items_size:			The total size of the items.
++ * @max_policies:		The maximum number of policy entries to allow.
++ *				Pass 0 for no limit.
++ * @allow_wildcards:		Boolean value whether wildcard entries (such
++ *				ending on '.*') should be allowed.
++ * @owner:			The owner of the new policy items.
++ *
++ * This function sets a new set of policies for a given owner. The names and
++ * access rules are gathered by walking the list of items passed in as
++ * argument. An item of type KDBUS_ITEM_NAME is expected before any number of
++ * KDBUS_ITEM_POLICY_ACCESS items. If there are more repetitions of this
++ * pattern than denoted in @max_policies, -EINVAL is returned.
++ *
++ * In order to allow atomic replacement of rules, the function first removes
++ * all entries that have been created for the given owner previously.
++ *
++ * Callers to this function must make sure that the owner is a custom
++ * endpoint, or if the endpoint is a default endpoint, then it must be
++ * either a policy holder or an activator.
++ *
++ * Return: 0 on success, negative errno on failure.
++ */
++int kdbus_policy_set(struct kdbus_policy_db *db,
++		     const struct kdbus_item *items,
++		     size_t items_size,
++		     size_t max_policies,
++		     bool allow_wildcards,
++		     const void *owner)
++{
++	struct kdbus_policy_db_entry_access *a;
++	struct kdbus_policy_db_entry *e, *p;
++	const struct kdbus_item *item;
++	struct hlist_node *tmp;
++	HLIST_HEAD(entries);
++	HLIST_HEAD(restore);
++	size_t count = 0;
++	int i, ret = 0;
++	u32 hash;
++
++	/* Walk the list of items and look for new policies */
++	e = NULL;
++	KDBUS_ITEMS_FOREACH(item, items, items_size) {
++		switch (item->type) {
++		case KDBUS_ITEM_NAME: {
++			size_t len;
++
++			if (max_policies && ++count > max_policies) {
++				ret = -E2BIG;
++				goto exit;
++			}
++
++			if (!kdbus_name_is_valid(item->str, true)) {
++				ret = -EINVAL;
++				goto exit;
++			}
++
++			e = kzalloc(sizeof(*e), GFP_KERNEL);
++			if (!e) {
++				ret = -ENOMEM;
++				goto exit;
++			}
++
++			INIT_LIST_HEAD(&e->access_list);
++			e->owner = owner;
++			hlist_add_head(&e->hentry, &entries);
++
++			e->name = kstrdup(item->str, GFP_KERNEL);
++			if (!e->name) {
++				ret = -ENOMEM;
++				goto exit;
++			}
++
++			/*
++			 * If a supplied name ends with an '.*', cut off that
++			 * part, only store anything before it, and mark the
++			 * entry as wildcard.
++			 */
++			len = strlen(e->name);
++			if (len > 2 &&
++			    e->name[len - 3] == '.' &&
++			    e->name[len - 2] == '*') {
++				if (!allow_wildcards) {
++					ret = -EINVAL;
++					goto exit;
++				}
++
++				e->name[len - 3] = '\0';
++				e->wildcard = true;
++			}
++
++			break;
++		}
++
++		case KDBUS_ITEM_POLICY_ACCESS:
++			if (!e) {
++				ret = -EINVAL;
++				goto exit;
++			}
++
++			a = kdbus_policy_make_access(&item->policy_access);
++			if (IS_ERR(a)) {
++				ret = PTR_ERR(a);
++				goto exit;
++			}
++
++			list_add_tail(&a->list, &e->access_list);
++			break;
++		}
++	}
++
++	down_write(&db->entries_rwlock);
++
++	/* remember previous entries to restore in case of failure */
++	hash_for_each_safe(db->entries_hash, i, tmp, e, hentry)
++		if (e->owner == owner) {
++			hash_del(&e->hentry);
++			hlist_add_head(&e->hentry, &restore);
++		}
++
++	hlist_for_each_entry_safe(e, tmp, &entries, hentry) {
++		/* prevent duplicates */
++		hash = kdbus_strhash(e->name);
++		hash_for_each_possible(db->entries_hash, p, hentry, hash)
++			if (strcmp(e->name, p->name) == 0 &&
++			    e->wildcard == p->wildcard) {
++				ret = -EEXIST;
++				goto restore;
++			}
++
++		hlist_del(&e->hentry);
++		hash_add(db->entries_hash, &e->hentry, hash);
++	}
++
++restore:
++	/* if we failed, flush all entries we added so far */
++	if (ret < 0)
++		__kdbus_policy_remove_owner(db, owner);
++
++	/* if we failed, restore entries, otherwise release them */
++	hlist_for_each_entry_safe(e, tmp, &restore, hentry) {
++		hlist_del(&e->hentry);
++		if (ret < 0) {
++			hash = kdbus_strhash(e->name);
++			hash_add(db->entries_hash, &e->hentry, hash);
++		} else {
++			kdbus_policy_entry_free(e);
++		}
++	}
++
++	up_write(&db->entries_rwlock);
++
++exit:
++	hlist_for_each_entry_safe(e, tmp, &entries, hentry) {
++		hlist_del(&e->hentry);
++		kdbus_policy_entry_free(e);
++	}
++
++	return ret;
++}
+diff --git a/ipc/kdbus/policy.h b/ipc/kdbus/policy.h
+new file mode 100644
+index 0000000..15dd7bc
+--- /dev/null
++++ b/ipc/kdbus/policy.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_POLICY_H
++#define __KDBUS_POLICY_H
++
++#include <linux/hashtable.h>
++#include <linux/rwsem.h>
++
++struct kdbus_conn;
++struct kdbus_item;
++
++/**
++ * struct kdbus_policy_db - policy database
++ * @entries_hash:	Hashtable of entries
++ * @entries_rwlock:	Mutex to protect the database's access entries
++ */
++struct kdbus_policy_db {
++	DECLARE_HASHTABLE(entries_hash, 6);
++	struct rw_semaphore entries_rwlock;
++};
++
++void kdbus_policy_db_init(struct kdbus_policy_db *db);
++void kdbus_policy_db_clear(struct kdbus_policy_db *db);
++
++int kdbus_policy_query_unlocked(struct kdbus_policy_db *db,
++				const struct cred *cred, const char *name,
++				unsigned int hash);
++int kdbus_policy_query(struct kdbus_policy_db *db, const struct cred *cred,
++		       const char *name, unsigned int hash);
++
++void kdbus_policy_remove_owner(struct kdbus_policy_db *db,
++			       const void *owner);
++int kdbus_policy_set(struct kdbus_policy_db *db,
++		     const struct kdbus_item *items,
++		     size_t items_size,
++		     size_t max_policies,
++		     bool allow_wildcards,
++		     const void *owner);
++
++#endif
+diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c
+new file mode 100644
+index 0000000..63ccd55
+--- /dev/null
++++ b/ipc/kdbus/pool.c
+@@ -0,0 +1,728 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/aio.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/highmem.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/pagemap.h>
++#include <linux/rbtree.h>
++#include <linux/sched.h>
++#include <linux/shmem_fs.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/uio.h>
++
++#include "pool.h"
++#include "util.h"
++
++/**
++ * struct kdbus_pool - the receiver's buffer
++ * @f:			The backing shmem file
++ * @size:		The size of the file
++ * @accounted_size:	Currently accounted memory in bytes
++ * @lock:		Pool data lock
++ * @slices:		All slices sorted by address
++ * @slices_busy:	Tree of allocated slices
++ * @slices_free:	Tree of free slices
++ *
++ * The receiver's buffer, managed as a pool of allocated and free
++ * slices containing the queued messages.
++ *
++ * Messages sent with KDBUS_CMD_SEND are copied directly by the
++ * sending process into the receiver's pool.
++ *
++ * Messages received with KDBUS_CMD_RECV just return the offset
++ * to the data placed in the pool.
++ *
++ * The internally allocated memory needs to be returned by the receiver
++ * with KDBUS_CMD_FREE.
++ */
++struct kdbus_pool {
++	struct file *f;
++	size_t size;
++	size_t accounted_size;
++	struct mutex lock;
++
++	struct list_head slices;
++	struct rb_root slices_busy;
++	struct rb_root slices_free;
++};
++
++/**
++ * struct kdbus_pool_slice - allocated element in kdbus_pool
++ * @pool:		Pool this slice belongs to
++ * @off:		Offset of slice in the shmem file
++ * @size:		Size of slice
++ * @entry:		Entry in "all slices" list
++ * @rb_node:		Entry in free or busy list
++ * @free:		Unused slice
++ * @accounted:		Accounted as queue slice
++ * @ref_kernel:		Kernel holds a reference
++ * @ref_user:		Userspace holds a reference
++ *
++ * The pool has one or more slices, always spanning the entire size of the
++ * pool.
++ *
++ * Every slice is an element in a list sorted by the buffer address, to
++ * provide access to the next neighbor slice.
++ *
++ * Every slice is member in either the busy or the free tree. The free
++ * tree is organized by slice size, the busy tree organized by buffer
++ * offset.
++ */
++struct kdbus_pool_slice {
++	struct kdbus_pool *pool;
++	size_t off;
++	size_t size;
++
++	struct list_head entry;
++	struct rb_node rb_node;
++
++	bool free:1;
++	bool accounted:1;
++	bool ref_kernel:1;
++	bool ref_user:1;
++};
++
++static struct kdbus_pool_slice *kdbus_pool_slice_new(struct kdbus_pool *pool,
++						     size_t off, size_t size)
++{
++	struct kdbus_pool_slice *slice;
++
++	slice = kzalloc(sizeof(*slice), GFP_KERNEL);
++	if (!slice)
++		return NULL;
++
++	slice->pool = pool;
++	slice->off = off;
++	slice->size = size;
++	slice->free = true;
++	return slice;
++}
++
++/* insert a slice into the free tree */
++static void kdbus_pool_add_free_slice(struct kdbus_pool *pool,
++				      struct kdbus_pool_slice *slice)
++{
++	struct rb_node **n;
++	struct rb_node *pn = NULL;
++
++	n = &pool->slices_free.rb_node;
++	while (*n) {
++		struct kdbus_pool_slice *pslice;
++
++		pn = *n;
++		pslice = rb_entry(pn, struct kdbus_pool_slice, rb_node);
++		if (slice->size < pslice->size)
++			n = &pn->rb_left;
++		else
++			n = &pn->rb_right;
++	}
++
++	rb_link_node(&slice->rb_node, pn, n);
++	rb_insert_color(&slice->rb_node, &pool->slices_free);
++}
++
++/* insert a slice into the busy tree */
++static void kdbus_pool_add_busy_slice(struct kdbus_pool *pool,
++				      struct kdbus_pool_slice *slice)
++{
++	struct rb_node **n;
++	struct rb_node *pn = NULL;
++
++	n = &pool->slices_busy.rb_node;
++	while (*n) {
++		struct kdbus_pool_slice *pslice;
++
++		pn = *n;
++		pslice = rb_entry(pn, struct kdbus_pool_slice, rb_node);
++		if (slice->off < pslice->off)
++			n = &pn->rb_left;
++		else if (slice->off > pslice->off)
++			n = &pn->rb_right;
++		else
++			BUG();
++	}
++
++	rb_link_node(&slice->rb_node, pn, n);
++	rb_insert_color(&slice->rb_node, &pool->slices_busy);
++}
++
++static struct kdbus_pool_slice *kdbus_pool_find_slice(struct kdbus_pool *pool,
++						      size_t off)
++{
++	struct rb_node *n;
++
++	n = pool->slices_busy.rb_node;
++	while (n) {
++		struct kdbus_pool_slice *s;
++
++		s = rb_entry(n, struct kdbus_pool_slice, rb_node);
++		if (off < s->off)
++			n = n->rb_left;
++		else if (off > s->off)
++			n = n->rb_right;
++		else
++			return s;
++	}
++
++	return NULL;
++}
++
++/**
++ * kdbus_pool_slice_alloc() - allocate memory from a pool
++ * @pool:	The receiver's pool
++ * @size:	The number of bytes to allocate
++ * @accounted:	Whether this slice should be accounted for
++ *
++ * The returned slice is used for kdbus_pool_slice_release() to
++ * free the allocated memory. If either @kvec or @iovec is non-NULL, the data
++ * will be copied from kernel or userspace memory into the new slice at
++ * offset 0.
++ *
++ * Return: the allocated slice on success, ERR_PTR on failure.
++ */
++struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool,
++						size_t size, bool accounted)
++{
++	size_t slice_size = KDBUS_ALIGN8(size);
++	struct rb_node *n, *found = NULL;
++	struct kdbus_pool_slice *s;
++	int ret = 0;
++
++	if (WARN_ON(!size))
++		return ERR_PTR(-EINVAL);
++
++	/* search a free slice with the closest matching size */
++	mutex_lock(&pool->lock);
++	n = pool->slices_free.rb_node;
++	while (n) {
++		s = rb_entry(n, struct kdbus_pool_slice, rb_node);
++		if (slice_size < s->size) {
++			found = n;
++			n = n->rb_left;
++		} else if (slice_size > s->size) {
++			n = n->rb_right;
++		} else {
++			found = n;
++			break;
++		}
++	}
++
++	/* no slice with the minimum size found in the pool */
++	if (!found) {
++		ret = -EXFULL;
++		goto exit_unlock;
++	}
++
++	/* no exact match, use the closest one */
++	if (!n) {
++		struct kdbus_pool_slice *s_new;
++
++		s = rb_entry(found, struct kdbus_pool_slice, rb_node);
++
++		/* split-off the remainder of the size to its own slice */
++		s_new = kdbus_pool_slice_new(pool, s->off + slice_size,
++					     s->size - slice_size);
++		if (!s_new) {
++			ret = -ENOMEM;
++			goto exit_unlock;
++		}
++
++		list_add(&s_new->entry, &s->entry);
++		kdbus_pool_add_free_slice(pool, s_new);
++
++		/* adjust our size now that we split-off another slice */
++		s->size = slice_size;
++	}
++
++	/* move slice from free to the busy tree */
++	rb_erase(found, &pool->slices_free);
++	kdbus_pool_add_busy_slice(pool, s);
++
++	WARN_ON(s->ref_kernel || s->ref_user);
++
++	s->ref_kernel = true;
++	s->free = false;
++	s->accounted = accounted;
++	if (accounted)
++		pool->accounted_size += s->size;
++	mutex_unlock(&pool->lock);
++
++	return s;
++
++exit_unlock:
++	mutex_unlock(&pool->lock);
++	return ERR_PTR(ret);
++}
++
++static void __kdbus_pool_slice_release(struct kdbus_pool_slice *slice)
++{
++	struct kdbus_pool *pool = slice->pool;
++
++	/* don't free the slice if either has a reference */
++	if (slice->ref_kernel || slice->ref_user)
++		return;
++
++	if (WARN_ON(slice->free))
++		return;
++
++	rb_erase(&slice->rb_node, &pool->slices_busy);
++
++	/* merge with the next free slice */
++	if (!list_is_last(&slice->entry, &pool->slices)) {
++		struct kdbus_pool_slice *s;
++
++		s = list_entry(slice->entry.next,
++			       struct kdbus_pool_slice, entry);
++		if (s->free) {
++			rb_erase(&s->rb_node, &pool->slices_free);
++			list_del(&s->entry);
++			slice->size += s->size;
++			kfree(s);
++		}
++	}
++
++	/* merge with previous free slice */
++	if (pool->slices.next != &slice->entry) {
++		struct kdbus_pool_slice *s;
++
++		s = list_entry(slice->entry.prev,
++			       struct kdbus_pool_slice, entry);
++		if (s->free) {
++			rb_erase(&s->rb_node, &pool->slices_free);
++			list_del(&slice->entry);
++			s->size += slice->size;
++			kfree(slice);
++			slice = s;
++		}
++	}
++
++	slice->free = true;
++	kdbus_pool_add_free_slice(pool, slice);
++}
++
++/**
++ * kdbus_pool_slice_release() - drop kernel-reference on allocated slice
++ * @slice:		Slice allocated from the pool
++ *
++ * This releases the kernel-reference on the given slice. If the
++ * kernel-reference and the user-reference on a slice are dropped, the slice is
++ * returned to the pool.
++ *
++ * So far, we do not implement full ref-counting on slices. Each, kernel and
++ * user-space can have exactly one reference to a slice. If both are dropped at
++ * the same time, the slice is released.
++ */
++void kdbus_pool_slice_release(struct kdbus_pool_slice *slice)
++{
++	struct kdbus_pool *pool;
++
++	if (!slice)
++		return;
++
++	/* @slice may be freed, so keep local ptr to @pool */
++	pool = slice->pool;
++
++	mutex_lock(&pool->lock);
++	/* kernel must own a ref to @slice to drop it */
++	WARN_ON(!slice->ref_kernel);
++	slice->ref_kernel = false;
++	/* no longer kernel-owned, de-account slice */
++	if (slice->accounted && !WARN_ON(pool->accounted_size < slice->size))
++		pool->accounted_size -= slice->size;
++	__kdbus_pool_slice_release(slice);
++	mutex_unlock(&pool->lock);
++}
++
++/**
++ * kdbus_pool_release_offset() - release a public offset
++ * @pool:		pool to operate on
++ * @off:		offset to release
++ *
++ * This should be called whenever user-space frees a slice given to them. It
++ * verifies the slice is available and public, and then drops it. It ensures
++ * correct locking and barriers against queues.
++ *
++ * Return: 0 on success, ENXIO if the offset is invalid or not public.
++ */
++int kdbus_pool_release_offset(struct kdbus_pool *pool, size_t off)
++{
++	struct kdbus_pool_slice *slice;
++	int ret = 0;
++
++	/* 'pool->size' is used as dummy offset for empty slices */
++	if (off == pool->size)
++		return 0;
++
++	mutex_lock(&pool->lock);
++	slice = kdbus_pool_find_slice(pool, off);
++	if (slice && slice->ref_user) {
++		slice->ref_user = false;
++		__kdbus_pool_slice_release(slice);
++	} else {
++		ret = -ENXIO;
++	}
++	mutex_unlock(&pool->lock);
++
++	return ret;
++}
++
++/**
++ * kdbus_pool_publish_empty() - publish empty slice to user-space
++ * @pool:		pool to operate on
++ * @off:		output storage for offset, or NULL
++ * @size:		output storage for size, or NULL
++ *
++ * This is the same as kdbus_pool_slice_publish(), but uses a dummy slice with
++ * size 0. The returned offset points to the end of the pool and is never
++ * returned on real slices.
++ */
++void kdbus_pool_publish_empty(struct kdbus_pool *pool, u64 *off, u64 *size)
++{
++	if (off)
++		*off = pool->size;
++	if (size)
++		*size = 0;
++}
++
++/**
++ * kdbus_pool_slice_publish() - publish slice to user-space
++ * @slice:		The slice
++ * @out_offset:		Output storage for offset, or NULL
++ * @out_size:		Output storage for size, or NULL
++ *
++ * This prepares a slice to be published to user-space.
++ *
++ * This call combines the following operations:
++ *   * the memory region is flushed so the user's memory view is consistent
++ *   * the slice is marked as referenced by user-space, so user-space has to
++ *     call KDBUS_CMD_FREE to release it
++ *   * the offset and size of the slice are written to the given output
++ *     arguments, if non-NULL
++ */
++void kdbus_pool_slice_publish(struct kdbus_pool_slice *slice,
++			      u64 *out_offset, u64 *out_size)
++{
++	mutex_lock(&slice->pool->lock);
++	/* kernel must own a ref to @slice to gain a user-space ref */
++	WARN_ON(!slice->ref_kernel);
++	slice->ref_user = true;
++	mutex_unlock(&slice->pool->lock);
++
++	if (out_offset)
++		*out_offset = slice->off;
++	if (out_size)
++		*out_size = slice->size;
++}
++
++/**
++ * kdbus_pool_slice_offset() - Get a slice's offset inside the pool
++ * @slice:	Slice to return the offset of
++ *
++ * Return: The internal offset @slice inside the pool.
++ */
++off_t kdbus_pool_slice_offset(const struct kdbus_pool_slice *slice)
++{
++	return slice->off;
++}
++
++/**
++ * kdbus_pool_slice_size() - get size of a pool slice
++ * @slice:	slice to query
++ *
++ * Return: size of the given slice
++ */
++size_t kdbus_pool_slice_size(const struct kdbus_pool_slice *slice)
++{
++	return slice->size;
++}
++
++/**
++ * kdbus_pool_new() - create a new pool
++ * @name:		Name of the (deleted) file which shows up in
++ *			/proc, used for debugging
++ * @size:		Maximum size of the pool
++ *
++ * Return: a new kdbus_pool on success, ERR_PTR on failure.
++ */
++struct kdbus_pool *kdbus_pool_new(const char *name, size_t size)
++{
++	struct kdbus_pool_slice *s;
++	struct kdbus_pool *p;
++	struct file *f;
++	char *n = NULL;
++	int ret;
++
++	p = kzalloc(sizeof(*p), GFP_KERNEL);
++	if (!p)
++		return ERR_PTR(-ENOMEM);
++
++	if (name) {
++		n = kasprintf(GFP_KERNEL, KBUILD_MODNAME "-conn:%s", name);
++		if (!n) {
++			ret = -ENOMEM;
++			goto exit_free;
++		}
++	}
++
++	f = shmem_file_setup(n ?: KBUILD_MODNAME "-conn", size, 0);
++	kfree(n);
++
++	if (IS_ERR(f)) {
++		ret = PTR_ERR(f);
++		goto exit_free;
++	}
++
++	ret = get_write_access(file_inode(f));
++	if (ret < 0)
++		goto exit_put_shmem;
++
++	/* allocate first slice spanning the entire pool */
++	s = kdbus_pool_slice_new(p, 0, size);
++	if (!s) {
++		ret = -ENOMEM;
++		goto exit_put_write;
++	}
++
++	p->f = f;
++	p->size = size;
++	p->slices_free = RB_ROOT;
++	p->slices_busy = RB_ROOT;
++	mutex_init(&p->lock);
++
++	INIT_LIST_HEAD(&p->slices);
++	list_add(&s->entry, &p->slices);
++
++	kdbus_pool_add_free_slice(p, s);
++	return p;
++
++exit_put_write:
++	put_write_access(file_inode(f));
++exit_put_shmem:
++	fput(f);
++exit_free:
++	kfree(p);
++	return ERR_PTR(ret);
++}
++
++/**
++ * kdbus_pool_free() - destroy pool
++ * @pool:		The receiver's pool
++ */
++void kdbus_pool_free(struct kdbus_pool *pool)
++{
++	struct kdbus_pool_slice *s, *tmp;
++
++	if (!pool)
++		return;
++
++	list_for_each_entry_safe(s, tmp, &pool->slices, entry) {
++		list_del(&s->entry);
++		kfree(s);
++	}
++
++	put_write_access(file_inode(pool->f));
++	fput(pool->f);
++	kfree(pool);
++}
++
++/**
++ * kdbus_pool_accounted() - retrieve accounting information
++ * @pool:		pool to query
++ * @size:		output for overall pool size
++ * @acc:		output for currently accounted size
++ *
++ * This returns accounting information of the pool. Note that the data might
++ * change after the function returns, as the pool lock is dropped. You need to
++ * protect the data via other means, if you need reliable accounting.
++ */
++void kdbus_pool_accounted(struct kdbus_pool *pool, size_t *size, size_t *acc)
++{
++	mutex_lock(&pool->lock);
++	if (size)
++		*size = pool->size;
++	if (acc)
++		*acc = pool->accounted_size;
++	mutex_unlock(&pool->lock);
++}
++
++/**
++ * kdbus_pool_slice_copy_iovec() - copy user memory to a slice
++ * @slice:		The slice to write to
++ * @off:		Offset in the slice to write to
++ * @iov:		iovec array, pointing to data to copy
++ * @iov_len:		Number of elements in @iov
++ * @total_len:		Total number of bytes described in members of @iov
++ *
++ * User memory referenced by @iov will be copied into @slice at offset @off.
++ *
++ * Return: the numbers of bytes copied, negative errno on failure.
++ */
++ssize_t
++kdbus_pool_slice_copy_iovec(const struct kdbus_pool_slice *slice, loff_t off,
++			    struct iovec *iov, size_t iov_len, size_t total_len)
++{
++	struct iov_iter iter;
++	ssize_t len;
++
++	if (WARN_ON(off + total_len > slice->size))
++		return -EFAULT;
++
++	off += slice->off;
++	iov_iter_init(&iter, WRITE, iov, iov_len, total_len);
++	len = vfs_iter_write(slice->pool->f, &iter, &off);
++
++	return (len >= 0 && len != total_len) ? -EFAULT : len;
++}
++
++/**
++ * kdbus_pool_slice_copy_kvec() - copy kernel memory to a slice
++ * @slice:		The slice to write to
++ * @off:		Offset in the slice to write to
++ * @kvec:		kvec array, pointing to data to copy
++ * @kvec_len:		Number of elements in @kvec
++ * @total_len:		Total number of bytes described in members of @kvec
++ *
++ * Kernel memory referenced by @kvec will be copied into @slice at offset @off.
++ *
++ * Return: the numbers of bytes copied, negative errno on failure.
++ */
++ssize_t kdbus_pool_slice_copy_kvec(const struct kdbus_pool_slice *slice,
++				   loff_t off, struct kvec *kvec,
++				   size_t kvec_len, size_t total_len)
++{
++	struct iov_iter iter;
++	mm_segment_t old_fs;
++	ssize_t len;
++
++	if (WARN_ON(off + total_len > slice->size))
++		return -EFAULT;
++
++	off += slice->off;
++	iov_iter_kvec(&iter, WRITE | ITER_KVEC, kvec, kvec_len, total_len);
++
++	old_fs = get_fs();
++	set_fs(get_ds());
++	len = vfs_iter_write(slice->pool->f, &iter, &off);
++	set_fs(old_fs);
++
++	return (len >= 0 && len != total_len) ? -EFAULT : len;
++}
++
++/**
++ * kdbus_pool_slice_copy() - copy data from one slice into another
++ * @slice_dst:		destination slice
++ * @slice_src:		source slice
++ *
++ * Return: 0 on success, negative error number on failure.
++ */
++int kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice_dst,
++			  const struct kdbus_pool_slice *slice_src)
++{
++	struct file *f_src = slice_src->pool->f;
++	struct file *f_dst = slice_dst->pool->f;
++	struct inode *i_dst = file_inode(f_dst);
++	struct address_space *mapping_dst = f_dst->f_mapping;
++	const struct address_space_operations *aops = mapping_dst->a_ops;
++	unsigned long len = slice_src->size;
++	loff_t off_src = slice_src->off;
++	loff_t off_dst = slice_dst->off;
++	mm_segment_t old_fs;
++	int ret = 0;
++
++	if (WARN_ON(slice_src->size != slice_dst->size) ||
++	    WARN_ON(slice_src->free || slice_dst->free))
++		return -EINVAL;
++
++	mutex_lock(&i_dst->i_mutex);
++	old_fs = get_fs();
++	set_fs(get_ds());
++	while (len > 0) {
++		unsigned long page_off;
++		unsigned long copy_len;
++		char __user *kaddr;
++		struct page *page;
++		ssize_t n_read;
++		void *fsdata;
++		long status;
++
++		page_off = off_dst & (PAGE_CACHE_SIZE - 1);
++		copy_len = min_t(unsigned long,
++				 PAGE_CACHE_SIZE - page_off, len);
++
++		status = aops->write_begin(f_dst, mapping_dst, off_dst,
++					   copy_len, 0, &page, &fsdata);
++		if (unlikely(status < 0)) {
++			ret = status;
++			break;
++		}
++
++		kaddr = (char __force __user *)kmap(page) + page_off;
++		n_read = __vfs_read(f_src, kaddr, copy_len, &off_src);
++		kunmap(page);
++		mark_page_accessed(page);
++		flush_dcache_page(page);
++
++		if (unlikely(n_read != copy_len)) {
++			ret = -EFAULT;
++			break;
++		}
++
++		status = aops->write_end(f_dst, mapping_dst, off_dst,
++					 copy_len, copy_len, page, fsdata);
++		if (unlikely(status != copy_len)) {
++			ret = -EFAULT;
++			break;
++		}
++
++		off_dst += copy_len;
++		len -= copy_len;
++	}
++	set_fs(old_fs);
++	mutex_unlock(&i_dst->i_mutex);
++
++	return ret;
++}
++
++/**
++ * kdbus_pool_mmap() -  map the pool into the process
++ * @pool:		The receiver's pool
++ * @vma:		passed by mmap() syscall
++ *
++ * Return: the result of the mmap() call, negative errno on failure.
++ */
++int kdbus_pool_mmap(const struct kdbus_pool *pool, struct vm_area_struct *vma)
++{
++	/* deny write access to the pool */
++	if (vma->vm_flags & VM_WRITE)
++		return -EPERM;
++	vma->vm_flags &= ~VM_MAYWRITE;
++
++	/* do not allow to map more than the size of the file */
++	if ((vma->vm_end - vma->vm_start) > pool->size)
++		return -EFAULT;
++
++	/* replace the connection file with our shmem file */
++	if (vma->vm_file)
++		fput(vma->vm_file);
++	vma->vm_file = get_file(pool->f);
++
++	return pool->f->f_op->mmap(pool->f, vma);
++}
+diff --git a/ipc/kdbus/pool.h b/ipc/kdbus/pool.h
+new file mode 100644
+index 0000000..a903821
+--- /dev/null
++++ b/ipc/kdbus/pool.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_POOL_H
++#define __KDBUS_POOL_H
++
++#include <linux/uio.h>
++
++struct kdbus_pool;
++struct kdbus_pool_slice;
++
++struct kdbus_pool *kdbus_pool_new(const char *name, size_t size);
++void kdbus_pool_free(struct kdbus_pool *pool);
++void kdbus_pool_accounted(struct kdbus_pool *pool, size_t *size, size_t *acc);
++int kdbus_pool_mmap(const struct kdbus_pool *pool, struct vm_area_struct *vma);
++int kdbus_pool_release_offset(struct kdbus_pool *pool, size_t off);
++void kdbus_pool_publish_empty(struct kdbus_pool *pool, u64 *off, u64 *size);
++
++struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool,
++						size_t size, bool accounted);
++void kdbus_pool_slice_release(struct kdbus_pool_slice *slice);
++void kdbus_pool_slice_publish(struct kdbus_pool_slice *slice,
++			      u64 *out_offset, u64 *out_size);
++off_t kdbus_pool_slice_offset(const struct kdbus_pool_slice *slice);
++size_t kdbus_pool_slice_size(const struct kdbus_pool_slice *slice);
++int kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice_dst,
++			  const struct kdbus_pool_slice *slice_src);
++ssize_t kdbus_pool_slice_copy_kvec(const struct kdbus_pool_slice *slice,
++				   loff_t off, struct kvec *kvec,
++				   size_t kvec_count, size_t total_len);
++ssize_t kdbus_pool_slice_copy_iovec(const struct kdbus_pool_slice *slice,
++				    loff_t off, struct iovec *iov,
++				    size_t iov_count, size_t total_len);
++
++#endif
+diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
+new file mode 100644
+index 0000000..f9c44d7
+--- /dev/null
++++ b/ipc/kdbus/queue.c
+@@ -0,0 +1,363 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/audit.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/hashtable.h>
++#include <linux/idr.h>
++#include <linux/init.h>
++#include <linux/math64.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/syscalls.h>
++#include <linux/uio.h>
++
++#include "util.h"
++#include "domain.h"
++#include "connection.h"
++#include "item.h"
++#include "message.h"
++#include "metadata.h"
++#include "queue.h"
++#include "reply.h"
++
++/**
++ * kdbus_queue_init() - initialize data structure related to a queue
++ * @queue:	The queue to initialize
++ */
++void kdbus_queue_init(struct kdbus_queue *queue)
++{
++	INIT_LIST_HEAD(&queue->msg_list);
++	queue->msg_prio_queue = RB_ROOT;
++}
++
++/**
++ * kdbus_queue_peek() - Retrieves an entry from a queue
++ * @queue:		The queue
++ * @priority:		The minimum priority of the entry to peek
++ * @use_priority:	Boolean flag whether or not to peek by priority
++ *
++ * Look for a entry in a queue, either by priority, or the oldest one (FIFO).
++ * The entry is not freed, put off the queue's lists or anything else.
++ *
++ * Return: the peeked queue entry on success, NULL if no suitable msg is found
++ */
++struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue,
++					   s64 priority, bool use_priority)
++{
++	struct kdbus_queue_entry *e;
++
++	if (list_empty(&queue->msg_list))
++		return NULL;
++
++	if (use_priority) {
++		/* get next entry with highest priority */
++		e = rb_entry(queue->msg_prio_highest,
++			     struct kdbus_queue_entry, prio_node);
++
++		/* no entry with the requested priority */
++		if (e->priority > priority)
++			return NULL;
++	} else {
++		/* ignore the priority, return the next entry in the entry */
++		e = list_first_entry(&queue->msg_list,
++				     struct kdbus_queue_entry, entry);
++	}
++
++	return e;
++}
++
++static void kdbus_queue_entry_link(struct kdbus_queue_entry *entry)
++{
++	struct kdbus_queue *queue = &entry->conn->queue;
++	struct rb_node **n, *pn = NULL;
++	bool highest = true;
++
++	lockdep_assert_held(&entry->conn->lock);
++	if (WARN_ON(!list_empty(&entry->entry)))
++		return;
++
++	/* sort into priority entry tree */
++	n = &queue->msg_prio_queue.rb_node;
++	while (*n) {
++		struct kdbus_queue_entry *e;
++
++		pn = *n;
++		e = rb_entry(pn, struct kdbus_queue_entry, prio_node);
++
++		/* existing node for this priority, add to its list */
++		if (likely(entry->priority == e->priority)) {
++			list_add_tail(&entry->prio_entry, &e->prio_entry);
++			goto prio_done;
++		}
++
++		if (entry->priority < e->priority) {
++			n = &pn->rb_left;
++		} else {
++			n = &pn->rb_right;
++			highest = false;
++		}
++	}
++
++	/* cache highest-priority entry */
++	if (highest)
++		queue->msg_prio_highest = &entry->prio_node;
++
++	/* new node for this priority */
++	rb_link_node(&entry->prio_node, pn, n);
++	rb_insert_color(&entry->prio_node, &queue->msg_prio_queue);
++	INIT_LIST_HEAD(&entry->prio_entry);
++
++prio_done:
++	/* add to unsorted fifo list */
++	list_add_tail(&entry->entry, &queue->msg_list);
++}
++
++static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry)
++{
++	struct kdbus_queue *queue = &entry->conn->queue;
++
++	lockdep_assert_held(&entry->conn->lock);
++	if (list_empty(&entry->entry))
++		return;
++
++	list_del_init(&entry->entry);
++
++	if (list_empty(&entry->prio_entry)) {
++		/*
++		 * Single entry for this priority, update cached
++		 * highest-priority entry, remove the tree node.
++		 */
++		if (queue->msg_prio_highest == &entry->prio_node)
++			queue->msg_prio_highest = rb_next(&entry->prio_node);
++
++		rb_erase(&entry->prio_node, &queue->msg_prio_queue);
++	} else {
++		struct kdbus_queue_entry *q;
++
++		/*
++		 * Multiple entries for this priority entry, get next one in
++		 * the list. Update cached highest-priority entry, store the
++		 * new one as the tree node.
++		 */
++		q = list_first_entry(&entry->prio_entry,
++				     struct kdbus_queue_entry, prio_entry);
++		list_del(&entry->prio_entry);
++
++		if (queue->msg_prio_highest == &entry->prio_node)
++			queue->msg_prio_highest = &q->prio_node;
++
++		rb_replace_node(&entry->prio_node, &q->prio_node,
++				&queue->msg_prio_queue);
++	}
++}
++
++/**
++ * kdbus_queue_entry_new() - allocate a queue entry
++ * @src:	source connection, or NULL
++ * @dst:	destination connection
++ * @s:		staging object carrying the message
++ *
++ * Allocates a queue entry based on a given msg and allocate space for
++ * the message payload and the requested metadata in the connection's pool.
++ * The entry is not actually added to the queue's lists at this point.
++ *
++ * Return: the allocated entry on success, or an ERR_PTR on failures.
++ */
++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src,
++						struct kdbus_conn *dst,
++						struct kdbus_staging *s)
++{
++	struct kdbus_queue_entry *entry;
++	int ret;
++
++	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++	if (!entry)
++		return ERR_PTR(-ENOMEM);
++
++	INIT_LIST_HEAD(&entry->entry);
++	entry->priority = s->msg->priority;
++	entry->conn = kdbus_conn_ref(dst);
++	entry->gaps = kdbus_gaps_ref(s->gaps);
++
++	entry->slice = kdbus_staging_emit(s, src, dst);
++	if (IS_ERR(entry->slice)) {
++		ret = PTR_ERR(entry->slice);
++		entry->slice = NULL;
++		goto error;
++	}
++
++	entry->user = src ? kdbus_user_ref(src->user) : NULL;
++	return entry;
++
++error:
++	kdbus_queue_entry_free(entry);
++	return ERR_PTR(ret);
++}
++
++/**
++ * kdbus_queue_entry_free() - free resources of an entry
++ * @entry:	The entry to free
++ *
++ * Removes resources allocated by a queue entry, along with the entry itself.
++ * Note that the entry's slice is not freed at this point.
++ */
++void kdbus_queue_entry_free(struct kdbus_queue_entry *entry)
++{
++	if (!entry)
++		return;
++
++	lockdep_assert_held(&entry->conn->lock);
++
++	kdbus_queue_entry_unlink(entry);
++	kdbus_reply_unref(entry->reply);
++
++	if (entry->slice) {
++		kdbus_conn_quota_dec(entry->conn, entry->user,
++				     kdbus_pool_slice_size(entry->slice),
++				     entry->gaps ? entry->gaps->n_fds : 0);
++		kdbus_pool_slice_release(entry->slice);
++	}
++
++	kdbus_user_unref(entry->user);
++	kdbus_gaps_unref(entry->gaps);
++	kdbus_conn_unref(entry->conn);
++	kfree(entry);
++}
++
++/**
++ * kdbus_queue_entry_install() - install message components into the
++ *				 receiver's process
++ * @entry:		The queue entry to install
++ * @return_flags:	Pointer to store the return flags for userspace
++ * @install_fds:	Whether or not to install associated file descriptors
++ *
++ * Return: 0 on success.
++ */
++int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
++			      u64 *return_flags, bool install_fds)
++{
++	bool incomplete_fds = false;
++	int ret;
++
++	lockdep_assert_held(&entry->conn->lock);
++
++	ret = kdbus_gaps_install(entry->gaps, entry->slice, &incomplete_fds);
++	if (ret < 0)
++		return ret;
++
++	if (incomplete_fds)
++		*return_flags |= KDBUS_RECV_RETURN_INCOMPLETE_FDS;
++	return 0;
++}
++
++/**
++ * kdbus_queue_entry_enqueue() - enqueue an entry
++ * @entry:		entry to enqueue
++ * @reply:		reply to link to this entry (or NULL if none)
++ *
++ * This enqueues an unqueued entry into the message queue of the linked
++ * connection. It also binds a reply object to the entry so we can remember it
++ * when the message is moved.
++ *
++ * Once this call returns (and the connection lock is released), this entry can
++ * be dequeued by the target connection. Note that the entry will not be removed
++ * from the queue until it is destroyed.
++ */
++void kdbus_queue_entry_enqueue(struct kdbus_queue_entry *entry,
++			       struct kdbus_reply *reply)
++{
++	lockdep_assert_held(&entry->conn->lock);
++
++	if (WARN_ON(entry->reply) || WARN_ON(!list_empty(&entry->entry)))
++		return;
++
++	entry->reply = kdbus_reply_ref(reply);
++	kdbus_queue_entry_link(entry);
++}
++
++/**
++ * kdbus_queue_entry_move() - move queue entry
++ * @e:		queue entry to move
++ * @dst:	destination connection to queue the entry on
++ *
++ * This moves a queue entry onto a different connection. It allocates a new
++ * slice on the target connection and copies the message over. If the copy
++ * succeeded, we move the entry from @src to @dst.
++ *
++ * On failure, the entry is left untouched.
++ *
++ * The queue entry must be queued right now, and after the call succeeds it will
++ * be queued on the destination, but no longer on the source.
++ *
++ * The caller must hold the connection lock of the source *and* destination.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_queue_entry_move(struct kdbus_queue_entry *e,
++			   struct kdbus_conn *dst)
++{
++	struct kdbus_pool_slice *slice = NULL;
++	struct kdbus_conn *src = e->conn;
++	size_t size, fds;
++	int ret;
++
++	lockdep_assert_held(&src->lock);
++	lockdep_assert_held(&dst->lock);
++
++	if (WARN_ON(list_empty(&e->entry)))
++		return -EINVAL;
++	if (src == dst)
++		return 0;
++
++	size = kdbus_pool_slice_size(e->slice);
++	fds = e->gaps ? e->gaps->n_fds : 0;
++
++	ret = kdbus_conn_quota_inc(dst, e->user, size, fds);
++	if (ret < 0)
++		return ret;
++
++	slice = kdbus_pool_slice_alloc(dst->pool, size, true);
++	if (IS_ERR(slice)) {
++		ret = PTR_ERR(slice);
++		slice = NULL;
++		goto error;
++	}
++
++	ret = kdbus_pool_slice_copy(slice, e->slice);
++	if (ret < 0)
++		goto error;
++
++	kdbus_queue_entry_unlink(e);
++	kdbus_conn_quota_dec(src, e->user, size, fds);
++	kdbus_pool_slice_release(e->slice);
++	kdbus_conn_unref(e->conn);
++
++	e->slice = slice;
++	e->conn = kdbus_conn_ref(dst);
++	kdbus_queue_entry_link(e);
++
++	return 0;
++
++error:
++	kdbus_pool_slice_release(slice);
++	kdbus_conn_quota_dec(dst, e->user, size, fds);
++	return ret;
++}
+diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h
+new file mode 100644
+index 0000000..bf686d1
+--- /dev/null
++++ b/ipc/kdbus/queue.h
+@@ -0,0 +1,84 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_QUEUE_H
++#define __KDBUS_QUEUE_H
++
++#include <linux/list.h>
++#include <linux/rbtree.h>
++
++struct kdbus_conn;
++struct kdbus_pool_slice;
++struct kdbus_reply;
++struct kdbus_staging;
++struct kdbus_user;
++
++/**
++ * struct kdbus_queue - a connection's message queue
++ * @msg_list:		List head for kdbus_queue_entry objects
++ * @msg_prio_queue:	RB tree root for messages, sorted by priority
++ * @msg_prio_highest:	Link to the RB node referencing the message with the
++ *			highest priority in the tree.
++ */
++struct kdbus_queue {
++	struct list_head msg_list;
++	struct rb_root msg_prio_queue;
++	struct rb_node *msg_prio_highest;
++};
++
++/**
++ * struct kdbus_queue_entry - messages waiting to be read
++ * @entry:		Entry in the connection's list
++ * @prio_node:		Entry in the priority queue tree
++ * @prio_entry:		Queue tree node entry in the list of one priority
++ * @priority:		Message priority
++ * @dst_name_id:	The sequence number of the name this message is
++ *			addressed to, 0 for messages sent to an ID
++ * @conn:		Connection this entry is queued on
++ * @gaps:		Gaps object to fill message gaps at RECV time
++ * @user:		User used for accounting
++ * @slice:		Slice in the receiver's pool for the message
++ * @reply:		The reply block if a reply to this message is expected
++ */
++struct kdbus_queue_entry {
++	struct list_head entry;
++	struct rb_node prio_node;
++	struct list_head prio_entry;
++
++	s64 priority;
++	u64 dst_name_id;
++
++	struct kdbus_conn *conn;
++	struct kdbus_gaps *gaps;
++	struct kdbus_user *user;
++	struct kdbus_pool_slice *slice;
++	struct kdbus_reply *reply;
++};
++
++void kdbus_queue_init(struct kdbus_queue *queue);
++struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue,
++					   s64 priority, bool use_priority);
++
++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src,
++						struct kdbus_conn *dst,
++						struct kdbus_staging *s);
++void kdbus_queue_entry_free(struct kdbus_queue_entry *entry);
++int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
++			      u64 *return_flags, bool install_fds);
++void kdbus_queue_entry_enqueue(struct kdbus_queue_entry *entry,
++			       struct kdbus_reply *reply);
++int kdbus_queue_entry_move(struct kdbus_queue_entry *entry,
++			   struct kdbus_conn *dst);
++
++#endif /* __KDBUS_QUEUE_H */
+diff --git a/ipc/kdbus/reply.c b/ipc/kdbus/reply.c
+new file mode 100644
+index 0000000..e6791d8
+--- /dev/null
++++ b/ipc/kdbus/reply.c
+@@ -0,0 +1,252 @@
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++#include <linux/uio.h>
++
++#include "bus.h"
++#include "connection.h"
++#include "endpoint.h"
++#include "message.h"
++#include "metadata.h"
++#include "names.h"
++#include "domain.h"
++#include "item.h"
++#include "notify.h"
++#include "policy.h"
++#include "reply.h"
++#include "util.h"
++
++/**
++ * kdbus_reply_new() - Allocate and set up a new kdbus_reply object
++ * @reply_src:		The connection a reply is expected from
++ * @reply_dst:		The connection this reply object belongs to
++ * @msg:		Message associated with the reply
++ * @name_entry:		Name entry used to send the message
++ * @sync:		Whether or not to make this reply synchronous
++ *
++ * Allocate and fill a new kdbus_reply object.
++ *
++ * Return: New kdbus_conn object on success, ERR_PTR on error.
++ */
++struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src,
++				    struct kdbus_conn *reply_dst,
++				    const struct kdbus_msg *msg,
++				    struct kdbus_name_entry *name_entry,
++				    bool sync)
++{
++	struct kdbus_reply *r;
++	int ret;
++
++	if (atomic_inc_return(&reply_dst->request_count) >
++	    KDBUS_CONN_MAX_REQUESTS_PENDING) {
++		ret = -EMLINK;
++		goto exit_dec_request_count;
++	}
++
++	r = kzalloc(sizeof(*r), GFP_KERNEL);
++	if (!r) {
++		ret = -ENOMEM;
++		goto exit_dec_request_count;
++	}
++
++	kref_init(&r->kref);
++	INIT_LIST_HEAD(&r->entry);
++	r->reply_src = kdbus_conn_ref(reply_src);
++	r->reply_dst = kdbus_conn_ref(reply_dst);
++	r->cookie = msg->cookie;
++	r->name_id = name_entry ? name_entry->name_id : 0;
++	r->deadline_ns = msg->timeout_ns;
++
++	if (sync) {
++		r->sync = true;
++		r->waiting = true;
++	}
++
++	return r;
++
++exit_dec_request_count:
++	atomic_dec(&reply_dst->request_count);
++	return ERR_PTR(ret);
++}
++
++static void __kdbus_reply_free(struct kref *kref)
++{
++	struct kdbus_reply *reply =
++		container_of(kref, struct kdbus_reply, kref);
++
++	atomic_dec(&reply->reply_dst->request_count);
++	kdbus_conn_unref(reply->reply_src);
++	kdbus_conn_unref(reply->reply_dst);
++	kfree(reply);
++}
++
++/**
++ * kdbus_reply_ref() - Increase reference on kdbus_reply
++ * @r:		The reply, may be %NULL
++ *
++ * Return: The reply object with an extra reference
++ */
++struct kdbus_reply *kdbus_reply_ref(struct kdbus_reply *r)
++{
++	if (r)
++		kref_get(&r->kref);
++	return r;
++}
++
++/**
++ * kdbus_reply_unref() - Decrease reference on kdbus_reply
++ * @r:		The reply, may be %NULL
++ *
++ * Return: NULL
++ */
++struct kdbus_reply *kdbus_reply_unref(struct kdbus_reply *r)
++{
++	if (r)
++		kref_put(&r->kref, __kdbus_reply_free);
++	return NULL;
++}
++
++/**
++ * kdbus_reply_link() - Link reply object into target connection
++ * @r:		Reply to link
++ */
++void kdbus_reply_link(struct kdbus_reply *r)
++{
++	if (WARN_ON(!list_empty(&r->entry)))
++		return;
++
++	list_add(&r->entry, &r->reply_dst->reply_list);
++	kdbus_reply_ref(r);
++}
++
++/**
++ * kdbus_reply_unlink() - Unlink reply object from target connection
++ * @r:		Reply to unlink
++ */
++void kdbus_reply_unlink(struct kdbus_reply *r)
++{
++	if (!list_empty(&r->entry)) {
++		list_del_init(&r->entry);
++		kdbus_reply_unref(r);
++	}
++}
++
++/**
++ * kdbus_sync_reply_wakeup() - Wake a synchronously blocking reply
++ * @reply:	The reply object
++ * @err:	Error code to set on the remote side
++ *
++ * Wake up remote peer (method origin) with the appropriate synchronous reply
++ * code.
++ */
++void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err)
++{
++	if (WARN_ON(!reply->sync))
++		return;
++
++	reply->waiting = false;
++	reply->err = err;
++	wake_up_interruptible(&reply->reply_dst->wait);
++}
++
++/**
++ * kdbus_reply_find() - Find the corresponding reply object
++ * @replying:	The replying connection or NULL
++ * @reply_dst:	The connection the reply will be sent to
++ *		(method origin)
++ * @cookie:	The cookie of the requesting message
++ *
++ * Lookup a reply object that should be sent as a reply by
++ * @replying to @reply_dst with the given cookie.
++ *
++ * Callers must take the @reply_dst lock.
++ *
++ * Return: the corresponding reply object or NULL if not found
++ */
++struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying,
++				     struct kdbus_conn *reply_dst,
++				     u64 cookie)
++{
++	struct kdbus_reply *r;
++
++	list_for_each_entry(r, &reply_dst->reply_list, entry) {
++		if (r->cookie == cookie &&
++		    (!replying || r->reply_src == replying))
++			return r;
++	}
++
++	return NULL;
++}
++
++/**
++ * kdbus_reply_list_scan_work() - Worker callback to scan the replies of a
++ *				  connection for exceeded timeouts
++ * @work:		Work struct of the connection to scan
++ *
++ * Walk the list of replies stored with a connection and look for entries
++ * that have exceeded their timeout. If such an entry is found, a timeout
++ * notification is sent to the waiting peer, and the reply is removed from
++ * the list.
++ *
++ * The work is rescheduled to the nearest timeout found during the list
++ * iteration.
++ */
++void kdbus_reply_list_scan_work(struct work_struct *work)
++{
++	struct kdbus_conn *conn =
++		container_of(work, struct kdbus_conn, work.work);
++	struct kdbus_reply *reply, *reply_tmp;
++	u64 deadline = ~0ULL;
++	u64 now;
++
++	now = ktime_get_ns();
++
++	mutex_lock(&conn->lock);
++	if (!kdbus_conn_active(conn)) {
++		mutex_unlock(&conn->lock);
++		return;
++	}
++
++	list_for_each_entry_safe(reply, reply_tmp, &conn->reply_list, entry) {
++		/*
++		 * If the reply block is waiting for synchronous I/O,
++		 * the timeout is handled by wait_event_*_timeout(),
++		 * so we don't have to care for it here.
++		 */
++		if (reply->sync && !reply->interrupted)
++			continue;
++
++		WARN_ON(reply->reply_dst != conn);
++
++		if (reply->deadline_ns > now) {
++			/* remember next timeout */
++			if (deadline > reply->deadline_ns)
++				deadline = reply->deadline_ns;
++
++			continue;
++		}
++
++		/*
++		 * A zero deadline means the connection died, was
++		 * cleaned up already and the notification was sent.
++		 * Don't send notifications for reply trackers that were
++		 * left in an interrupted syscall state.
++		 */
++		if (reply->deadline_ns != 0 && !reply->interrupted)
++			kdbus_notify_reply_timeout(conn->ep->bus, conn->id,
++						   reply->cookie);
++
++		kdbus_reply_unlink(reply);
++	}
++
++	/* rearm delayed work with next timeout */
++	if (deadline != ~0ULL)
++		schedule_delayed_work(&conn->work,
++				      nsecs_to_jiffies(deadline - now));
++
++	mutex_unlock(&conn->lock);
++
++	kdbus_notify_flush(conn->ep->bus);
++}
+diff --git a/ipc/kdbus/reply.h b/ipc/kdbus/reply.h
+new file mode 100644
+index 0000000..68d5232
+--- /dev/null
++++ b/ipc/kdbus/reply.h
+@@ -0,0 +1,68 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_REPLY_H
++#define __KDBUS_REPLY_H
++
++/**
++ * struct kdbus_reply - an entry of kdbus_conn's list of replies
++ * @kref:		Ref-count of this object
++ * @entry:		The entry of the connection's reply_list
++ * @reply_src:		The connection the reply will be sent from
++ * @reply_dst:		The connection the reply will be sent to
++ * @queue_entry:	The queue entry item that is prepared by the replying
++ *			connection
++ * @deadline_ns:	The deadline of the reply, in nanoseconds
++ * @cookie:		The cookie of the requesting message
++ * @name_id:		ID of the well-known name the original msg was sent to
++ * @sync:		The reply block is waiting for synchronous I/O
++ * @waiting:		The condition to synchronously wait for
++ * @interrupted:	The sync reply was left in an interrupted state
++ * @err:		The error code for the synchronous reply
++ */
++struct kdbus_reply {
++	struct kref kref;
++	struct list_head entry;
++	struct kdbus_conn *reply_src;
++	struct kdbus_conn *reply_dst;
++	struct kdbus_queue_entry *queue_entry;
++	u64 deadline_ns;
++	u64 cookie;
++	u64 name_id;
++	bool sync:1;
++	bool waiting:1;
++	bool interrupted:1;
++	int err;
++};
++
++struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src,
++				    struct kdbus_conn *reply_dst,
++				    const struct kdbus_msg *msg,
++				    struct kdbus_name_entry *name_entry,
++				    bool sync);
++
++struct kdbus_reply *kdbus_reply_ref(struct kdbus_reply *r);
++struct kdbus_reply *kdbus_reply_unref(struct kdbus_reply *r);
++
++void kdbus_reply_link(struct kdbus_reply *r);
++void kdbus_reply_unlink(struct kdbus_reply *r);
++
++struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying,
++				     struct kdbus_conn *reply_dst,
++				     u64 cookie);
++
++void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err);
++void kdbus_reply_list_scan_work(struct work_struct *work);
++
++#endif /* __KDBUS_REPLY_H */
+diff --git a/ipc/kdbus/util.c b/ipc/kdbus/util.c
+new file mode 100644
+index 0000000..72b1883
+--- /dev/null
++++ b/ipc/kdbus/util.c
+@@ -0,0 +1,156 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/capability.h>
++#include <linux/cred.h>
++#include <linux/ctype.h>
++#include <linux/err.h>
++#include <linux/file.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/uaccess.h>
++#include <linux/uio.h>
++#include <linux/user_namespace.h>
++
++#include "limits.h"
++#include "util.h"
++
++/**
++ * kdbus_copy_from_user() - copy aligned data from user-space
++ * @dest:	target buffer in kernel memory
++ * @user_ptr:	user-provided source buffer
++ * @size:	memory size to copy from user
++ *
++ * This copies @size bytes from @user_ptr into the kernel, just like
++ * copy_from_user() does. But we enforce an 8-byte alignment and reject any
++ * unaligned user-space pointers.
++ *
++ * Return: 0 on success, negative error code on failure.
++ */
++int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size)
++{
++	if (!KDBUS_IS_ALIGNED8((uintptr_t)user_ptr))
++		return -EFAULT;
++
++	if (copy_from_user(dest, user_ptr, size))
++		return -EFAULT;
++
++	return 0;
++}
++
++/**
++ * kdbus_verify_uid_prefix() - verify UID prefix of a user-supplied name
++ * @name:	user-supplied name to verify
++ * @user_ns:	user-namespace to act in
++ * @kuid:	Kernel internal uid of user
++ *
++ * This verifies that the user-supplied name @name has their UID as prefix. This
++ * is the default name-spacing policy we enforce on user-supplied names for
++ * public kdbus entities like buses and endpoints.
++ *
++ * The user must supply names prefixed with "<UID>-", whereas the UID is
++ * interpreted in the user-namespace of the domain. If the user fails to supply
++ * such a prefixed name, we reject it.
++ *
++ * Return: 0 on success, negative error code on failure
++ */
++int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns,
++			    kuid_t kuid)
++{
++	uid_t uid;
++	char prefix[16];
++
++	/*
++	 * The kuid must have a mapping into the userns of the domain
++	 * otherwise do not allow creation of buses nor endpoints.
++	 */
++	uid = from_kuid(user_ns, kuid);
++	if (uid == (uid_t) -1)
++		return -EINVAL;
++
++	snprintf(prefix, sizeof(prefix), "%u-", uid);
++	if (strncmp(name, prefix, strlen(prefix)) != 0)
++		return -EINVAL;
++
++	return 0;
++}
++
++/**
++ * kdbus_sanitize_attach_flags() - Sanitize attach flags from user-space
++ * @flags:		Attach flags provided by userspace
++ * @attach_flags:	A pointer where to store the valid attach flags
++ *
++ * Convert attach-flags provided by user-space into a valid mask. If the mask
++ * is invalid, an error is returned. The sanitized attach flags are stored in
++ * the output parameter.
++ *
++ * Return: 0 on success, negative error on failure.
++ */
++int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags)
++{
++	/* 'any' degrades to 'all' for compatibility */
++	if (flags == _KDBUS_ATTACH_ANY)
++		flags = _KDBUS_ATTACH_ALL;
++
++	/* reject unknown attach flags */
++	if (flags & ~_KDBUS_ATTACH_ALL)
++		return -EINVAL;
++
++	*attach_flags = flags;
++	return 0;
++}
++
++/**
++ * kdbus_kvec_set - helper utility to assemble kvec arrays
++ * @kvec:	kvec entry to use
++ * @src:	Source address to set in @kvec
++ * @len:	Number of bytes in @src
++ * @total_len:	Pointer to total length variable
++ *
++ * Set @src and @len in @kvec, and increase @total_len by @len.
++ */
++void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len)
++{
++	kvec->iov_base = src;
++	kvec->iov_len = len;
++	*total_len += len;
++}
++
++static const char * const zeros = "\0\0\0\0\0\0\0";
++
++/**
++ * kdbus_kvec_pad - conditionally write a padding kvec
++ * @kvec:	kvec entry to use
++ * @len:	Total length used for kvec array
++ *
++ * Check if the current total byte length of the array in @len is aligned to
++ * 8 bytes. If it isn't, fill @kvec with padding information and increase @len
++ * by the number of bytes stored in @kvec.
++ *
++ * Return: the number of added padding bytes.
++ */
++size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len)
++{
++	size_t pad = KDBUS_ALIGN8(*len) - *len;
++
++	if (!pad)
++		return 0;
++
++	kvec->iov_base = (void *)zeros;
++	kvec->iov_len = pad;
++
++	*len += pad;
++
++	return pad;
++}
+diff --git a/ipc/kdbus/util.h b/ipc/kdbus/util.h
+new file mode 100644
+index 0000000..5297166
+--- /dev/null
++++ b/ipc/kdbus/util.h
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ * Copyright (C) 2013-2015 Linux Foundation
++ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __KDBUS_UTIL_H
++#define __KDBUS_UTIL_H
++
++#include <linux/dcache.h>
++#include <linux/ioctl.h>
++
++#include <uapi/linux/kdbus.h>
++
++/* all exported addresses are 64 bit */
++#define KDBUS_PTR(addr) ((void __user *)(uintptr_t)(addr))
++
++/* all exported sizes are 64 bit and data aligned to 64 bit */
++#define KDBUS_ALIGN8(s) ALIGN((s), 8)
++#define KDBUS_IS_ALIGNED8(s) (IS_ALIGNED(s, 8))
++
++/**
++ * kdbus_member_set_user - write a structure member to user memory
++ * @_s:		Variable to copy from
++ * @_b:		Buffer to write to
++ * @_t:		Structure type
++ * @_m:		Member name in the passed structure
++ *
++ * Return: the result of copy_to_user()
++ */
++#define kdbus_member_set_user(_s, _b, _t, _m)				\
++({									\
++	u64 __user *_sz =						\
++		(void __user *)((u8 __user *)(_b) + offsetof(_t, _m));	\
++	copy_to_user(_sz, _s, FIELD_SIZEOF(_t, _m));			\
++})
++
++/**
++ * kdbus_strhash - calculate a hash
++ * @str:	String
++ *
++ * Return: hash value
++ */
++static inline unsigned int kdbus_strhash(const char *str)
++{
++	unsigned long hash = init_name_hash();
++
++	while (*str)
++		hash = partial_name_hash(*str++, hash);
++
++	return end_name_hash(hash);
++}
++
++int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns,
++			    kuid_t kuid);
++int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags);
++
++int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size);
++
++struct kvec;
++
++void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len);
++size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len);
++
++#endif
+diff --git a/samples/Kconfig b/samples/Kconfig
+index 224ebb4..a4c6b2f 100644
+--- a/samples/Kconfig
++++ b/samples/Kconfig
+@@ -55,6 +55,13 @@ config SAMPLE_KDB
+ 	  Build an example of how to dynamically add the hello
+ 	  command to the kdb shell.
+ 
++config SAMPLE_KDBUS
++	bool "Build kdbus API example"
++	depends on KDBUS
++	help
++	  Build an example of how the kdbus API can be used from
++	  userspace.
++
+ config SAMPLE_RPMSG_CLIENT
+ 	tristate "Build rpmsg client sample -- loadable modules only"
+ 	depends on RPMSG && m
+diff --git a/samples/Makefile b/samples/Makefile
+index f00257b..f0ad51e 100644
+--- a/samples/Makefile
++++ b/samples/Makefile
+@@ -1,4 +1,5 @@
+ # Makefile for Linux samples code
+ 
+ obj-$(CONFIG_SAMPLES)	+= kobject/ kprobes/ trace_events/ livepatch/ \
+-			   hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/
++			   hw_breakpoint/ kfifo/ kdb/ kdbus/ hidraw/ rpmsg/ \
++			   seccomp/
+diff --git a/samples/kdbus/.gitignore b/samples/kdbus/.gitignore
+new file mode 100644
+index 0000000..ee07d98
+--- /dev/null
++++ b/samples/kdbus/.gitignore
+@@ -0,0 +1 @@
++kdbus-workers
+diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile
+new file mode 100644
+index 0000000..137f842
+--- /dev/null
++++ b/samples/kdbus/Makefile
+@@ -0,0 +1,9 @@
++# kbuild trick to avoid linker error. Can be omitted if a module is built.
++obj- := dummy.o
++
++hostprogs-$(CONFIG_SAMPLE_KDBUS) += kdbus-workers
++
++always := $(hostprogs-y)
++
++HOSTCFLAGS_kdbus-workers.o += -I$(objtree)/usr/include
++HOSTLOADLIBES_kdbus-workers := -lrt
+diff --git a/samples/kdbus/kdbus-api.h b/samples/kdbus/kdbus-api.h
+new file mode 100644
+index 0000000..7f3abae
+--- /dev/null
++++ b/samples/kdbus/kdbus-api.h
+@@ -0,0 +1,114 @@
++#ifndef KDBUS_API_H
++#define KDBUS_API_H
++
++#include <sys/ioctl.h>
++#include <linux/kdbus.h>
++
++#define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
++#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
++#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
++#define KDBUS_ITEM_NEXT(item) \
++	(typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size))
++#define KDBUS_FOREACH(iter, first, _size)				\
++	for ((iter) = (first);						\
++	     ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) &&	\
++	       ((uint8_t *)(iter) >= (uint8_t *)(first));		\
++	     (iter) = (void *)((uint8_t *)(iter) + KDBUS_ALIGN8((iter)->size)))
++
++static inline int kdbus_cmd_bus_make(int control_fd, struct kdbus_cmd *cmd)
++{
++	int ret = ioctl(control_fd, KDBUS_CMD_BUS_MAKE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_endpoint_make(int bus_fd, struct kdbus_cmd *cmd)
++{
++	int ret = ioctl(bus_fd, KDBUS_CMD_ENDPOINT_MAKE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_endpoint_update(int ep_fd, struct kdbus_cmd *cmd)
++{
++	int ret = ioctl(ep_fd, KDBUS_CMD_ENDPOINT_UPDATE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_hello(int bus_fd, struct kdbus_cmd_hello *cmd)
++{
++	int ret = ioctl(bus_fd, KDBUS_CMD_HELLO, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_update(int fd, struct kdbus_cmd *cmd)
++{
++	int ret = ioctl(fd, KDBUS_CMD_UPDATE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_byebye(int conn_fd, struct kdbus_cmd *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_BYEBYE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_free(int conn_fd, struct kdbus_cmd_free *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_FREE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_conn_info(int conn_fd, struct kdbus_cmd_info *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_CONN_INFO, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_bus_creator_info(int conn_fd, struct kdbus_cmd_info *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_BUS_CREATOR_INFO, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_list(int fd, struct kdbus_cmd_list *cmd)
++{
++	int ret = ioctl(fd, KDBUS_CMD_LIST, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_send(int conn_fd, struct kdbus_cmd_send *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_SEND, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_recv(int conn_fd, struct kdbus_cmd_recv *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_RECV, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_name_acquire(int conn_fd, struct kdbus_cmd *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_NAME_ACQUIRE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_name_release(int conn_fd, struct kdbus_cmd *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_NAME_RELEASE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_match_add(int conn_fd, struct kdbus_cmd_match *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_MATCH_ADD, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++static inline int kdbus_cmd_match_remove(int conn_fd, struct kdbus_cmd_match *cmd)
++{
++	int ret = ioctl(conn_fd, KDBUS_CMD_MATCH_REMOVE, cmd);
++	return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
++}
++
++#endif /* KDBUS_API_H */
+diff --git a/samples/kdbus/kdbus-workers.c b/samples/kdbus/kdbus-workers.c
+new file mode 100644
+index 0000000..5a6dfdc
+--- /dev/null
++++ b/samples/kdbus/kdbus-workers.c
+@@ -0,0 +1,1346 @@
++/*
++ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++/*
++ * Example: Workers
++ * This program computes prime-numbers based on the sieve of Eratosthenes. The
++ * master sets up a shared memory region and spawns workers which clear out the
++ * non-primes. The master reacts to keyboard input and to client-requests to
++ * control what each worker does. Note that this is in no way meant as efficient
++ * way to compute primes. It should only serve as example how a master/worker
++ * concept can be implemented with kdbus used as control messages.
++ *
++ * The main process is called the 'master'. It creates a new, private bus which
++ * will be used between the master and its workers to communicate. The master
++ * then spawns a fixed number of workers. Whenever a worker dies (detected via
++ * SIGCHLD), the master spawns a new worker. When done, the master waits for all
++ * workers to exit, prints a status report and exits itself.
++ *
++ * The master process does *not* keep track of its workers. Instead, this
++ * example implements a PULL model. That is, the master acquires a well-known
++ * name on the bus which each worker uses to request tasks from the master. If
++ * there are no more tasks, the master will return an empty task-list, which
++ * casues a worker to exit immediately.
++ *
++ * As tasks can be computationally expensive, we support cancellation. Whenever
++ * the master process is interrupted, it will drop its well-known name on the
++ * bus. This causes kdbus to broadcast a name-change notification. The workers
++ * check for broadcast messages regularly and will exit if they receive one.
++ *
++ * This example exists of 4 objects:
++ *  * master: The master object contains the context of the master process. This
++ *            process manages the prime-context, spawns workers and assigns
++ *            prime-ranges to each worker to compute.
++ *            The master itself does not do any prime-computations itself.
++ *  * child:  The child object contains the context of a worker. It inherits the
++ *            prime context from its parent (the master) and then creates a new
++ *            bus context to request prime-ranges to compute.
++ *  * prime:  The "prime" object is used to abstract how we compute primes. When
++ *            allocated, it prepares a memory region to hold 1 bit for each
++ *            natural number up to a fixed maximum ('MAX_PRIMES').
++ *            The memory region is backed by a memfd which we share between
++ *            processes. Each worker now gets assigned a range of natural
++ *            numbers which it clears multiples of off the memory region. The
++ *            master process is responsible of distributing all natural numbers
++ *            up to the fixed maximum to its workers.
++ *  * bus:    The bus object is an abstraction of the kdbus API. It is pretty
++ *            straightfoward and only manages the connection-fd plus the
++ *            memory-mapped pool in a single object.
++ *
++ * This example is in reversed order, which should make it easier to read
++ * top-down, but requires some forward-declarations. Just ignore those.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/syscall.h>
++
++/* glibc < 2.7 does not ship sys/signalfd.h */
++/* we require kernels with __NR_memfd_create */
++#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 7 && defined(__NR_memfd_create)
++
++#include <ctype.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <linux/memfd.h>
++#include <signal.h>
++#include <stdbool.h>
++#include <stddef.h>
++#include <stdint.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <sys/poll.h>
++#include <sys/signalfd.h>
++#include <sys/time.h>
++#include <sys/wait.h>
++#include <time.h>
++#include <unistd.h>
++#include "kdbus-api.h"
++
++/* FORWARD DECLARATIONS */
++
++#define POOL_SIZE (16 * 1024 * 1024)
++#define MAX_PRIMES (2UL << 24)
++#define WORKER_COUNT (16)
++#define PRIME_STEPS (65536 * 4)
++
++static const char *arg_busname = "example-workers";
++static const char *arg_modname = "kdbus";
++static const char *arg_master = "org.freedesktop.master";
++
++static int err_assert(int r_errno, const char *msg, const char *func, int line,
++		      const char *file)
++{
++	r_errno = (r_errno != 0) ? -abs(r_errno) : -EFAULT;
++	if (r_errno < 0) {
++		errno = -r_errno;
++		fprintf(stderr, "ERR: %s: %m (%s:%d in %s)\n",
++			msg, func, line, file);
++	}
++	return r_errno;
++}
++
++#define err_r(_r, _msg) err_assert((_r), (_msg), __func__, __LINE__, __FILE__)
++#define err(_msg) err_r(errno, (_msg))
++
++struct prime;
++struct bus;
++struct master;
++struct child;
++
++struct prime {
++	int fd;
++	uint8_t *area;
++	size_t max;
++	size_t done;
++	size_t status;
++};
++
++static int prime_new(struct prime **out);
++static void prime_free(struct prime *p);
++static bool prime_done(struct prime *p);
++static void prime_consume(struct prime *p, size_t amount);
++static int prime_run(struct prime *p, struct bus *cancel, size_t number);
++static void prime_print(struct prime *p);
++
++struct bus {
++	int fd;
++	uint8_t *pool;
++};
++
++static int bus_open_connection(struct bus **out, uid_t uid, const char *name,
++			       uint64_t recv_flags);
++static void bus_close_connection(struct bus *b);
++static void bus_poool_free_slice(struct bus *b, uint64_t offset);
++static int bus_acquire_name(struct bus *b, const char *name);
++static int bus_install_name_loss_match(struct bus *b, const char *name);
++static int bus_poll(struct bus *b);
++static int bus_make(uid_t uid, const char *name);
++
++struct master {
++	size_t n_workers;
++	size_t max_workers;
++
++	int signal_fd;
++	int control_fd;
++
++	struct prime *prime;
++	struct bus *bus;
++};
++
++static int master_new(struct master **out);
++static void master_free(struct master *m);
++static int master_run(struct master *m);
++static int master_poll(struct master *m);
++static int master_handle_stdin(struct master *m);
++static int master_handle_signal(struct master *m);
++static int master_handle_bus(struct master *m);
++static int master_reply(struct master *m, const struct kdbus_msg *msg);
++static int master_waitpid(struct master *m);
++static int master_spawn(struct master *m);
++
++struct child {
++	struct bus *bus;
++	struct prime *prime;
++};
++
++static int child_new(struct child **out, struct prime *p);
++static void child_free(struct child *c);
++static int child_run(struct child *c);
++
++/* END OF FORWARD DECLARATIONS */
++
++/*
++ * This is the main entrypoint of this example. It is pretty straightforward. We
++ * create a master object, run the computation, print a status report and then
++ * exit. Nothing particularly interesting here, so lets look into the master
++ * object...
++ */
++int main(int argc, char **argv)
++{
++	struct master *m = NULL;
++	int r;
++
++	r = master_new(&m);
++	if (r < 0)
++		goto out;
++
++	r = master_run(m);
++	if (r < 0)
++		goto out;
++
++	if (0)
++		prime_print(m->prime);
++
++out:
++	master_free(m);
++	if (r < 0 && r != -EINTR)
++		fprintf(stderr, "failed\n");
++	else
++		fprintf(stderr, "done\n");
++	return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
++}
++
++/*
++ * ...this will allocate a new master context. It keeps track of the current
++ * number of children/workers that are running, manages a signalfd to track
++ * SIGCHLD, and creates a private kdbus bus. Afterwards, it opens its connection
++ * to the bus and acquires a well known-name (arg_master).
++ */
++static int master_new(struct master **out)
++{
++	struct master *m;
++	sigset_t smask;
++	int r;
++
++	m = calloc(1, sizeof(*m));
++	if (!m)
++		return err("cannot allocate master");
++
++	m->max_workers = WORKER_COUNT;
++	m->signal_fd = -1;
++	m->control_fd = -1;
++
++	/* Block SIGINT and SIGCHLD signals */
++	sigemptyset(&smask);
++	sigaddset(&smask, SIGINT);
++	sigaddset(&smask, SIGCHLD);
++	sigprocmask(SIG_BLOCK, &smask, NULL);
++
++	m->signal_fd = signalfd(-1, &smask, SFD_CLOEXEC);
++	if (m->signal_fd < 0) {
++		r = err("cannot create signalfd");
++		goto error;
++	}
++
++	r = prime_new(&m->prime);
++	if (r < 0)
++		goto error;
++
++	m->control_fd = bus_make(getuid(), arg_busname);
++	if (m->control_fd < 0) {
++		r = m->control_fd;
++		goto error;
++	}
++
++	/*
++	 * Open a bus connection for the master, and require each received
++	 * message to have a metadata item of type KDBUS_ITEM_PIDS attached.
++	 * The current UID is needed to compute the name of the bus node to
++	 * connect to.
++	 */
++	r = bus_open_connection(&m->bus, getuid(),
++				arg_busname, KDBUS_ATTACH_PIDS);
++	if (r < 0)
++		goto error;
++
++	/*
++	 * Acquire a well-known name on the bus, so children can address
++	 * messages to the master using KDBUS_DST_ID_NAME as destination-ID
++	 * of messages.
++	 */
++	r = bus_acquire_name(m->bus, arg_master);
++	if (r < 0)
++		goto error;
++
++	*out = m;
++	return 0;
++
++error:
++	master_free(m);
++	return r;
++}
++
++/* pretty straightforward destructor of a master object */
++static void master_free(struct master *m)
++{
++	if (!m)
++		return;
++
++	bus_close_connection(m->bus);
++	if (m->control_fd >= 0)
++		close(m->control_fd);
++	prime_free(m->prime);
++	if (m->signal_fd >= 0)
++		close(m->signal_fd);
++	free(m);
++}
++
++static int master_run(struct master *m)
++{
++	int res, r = 0;
++
++	while (!prime_done(m->prime)) {
++		while (m->n_workers < m->max_workers) {
++			r = master_spawn(m);
++			if (r < 0)
++				break;
++		}
++
++		r = master_poll(m);
++		if (r < 0)
++			break;
++	}
++
++	if (r < 0) {
++		bus_close_connection(m->bus);
++		m->bus = NULL;
++	}
++
++	while (m->n_workers > 0) {
++		res = master_poll(m);
++		if (res < 0) {
++			if (m->bus) {
++				bus_close_connection(m->bus);
++				m->bus = NULL;
++			}
++			r = res;
++		}
++	}
++
++	return r == -EINTR ? 0 : r;
++}
++
++static int master_poll(struct master *m)
++{
++	struct pollfd fds[3] = {};
++	int r = 0, n = 0;
++
++	/*
++	 * Add stdin, the eventfd and the connection owner file descriptor to
++	 * the pollfd table, and handle incoming traffic on the latter in
++	 * master_handle_bus().
++	 */
++	fds[n].fd = STDIN_FILENO;
++	fds[n++].events = POLLIN;
++	fds[n].fd = m->signal_fd;
++	fds[n++].events = POLLIN;
++	if (m->bus) {
++		fds[n].fd = m->bus->fd;
++		fds[n++].events = POLLIN;
++	}
++
++	r = poll(fds, n, -1);
++	if (r < 0)
++		return err("poll() failed");
++
++	if (fds[0].revents & POLLIN)
++		r = master_handle_stdin(m);
++	else if (fds[0].revents)
++		r = err("ERR/HUP on stdin");
++	if (r < 0)
++		return r;
++
++	if (fds[1].revents & POLLIN)
++		r = master_handle_signal(m);
++	else if (fds[1].revents)
++		r = err("ERR/HUP on signalfd");
++	if (r < 0)
++		return r;
++
++	if (fds[2].revents & POLLIN)
++		r = master_handle_bus(m);
++	else if (fds[2].revents)
++		r = err("ERR/HUP on bus");
++
++	return r;
++}
++
++static int master_handle_stdin(struct master *m)
++{
++	char buf[128];
++	ssize_t l;
++	int r = 0;
++
++	l = read(STDIN_FILENO, buf, sizeof(buf));
++	if (l < 0)
++		return err("cannot read stdin");
++	if (l == 0)
++		return err_r(-EINVAL, "EOF on stdin");
++
++	while (l-- > 0) {
++		switch (buf[l]) {
++		case 'q':
++			/* quit */
++			r = -EINTR;
++			break;
++		case '\n':
++		case ' ':
++			/* ignore */
++			break;
++		default:
++			if (isgraph(buf[l]))
++				fprintf(stderr, "invalid input '%c'\n", buf[l]);
++			else
++				fprintf(stderr, "invalid input 0x%x\n", buf[l]);
++			break;
++		}
++	}
++
++	return r;
++}
++
++static int master_handle_signal(struct master *m)
++{
++	struct signalfd_siginfo val;
++	ssize_t l;
++
++	l = read(m->signal_fd, &val, sizeof(val));
++	if (l < 0)
++		return err("cannot read signalfd");
++	if (l != sizeof(val))
++		return err_r(-EINVAL, "invalid data from signalfd");
++
++	switch (val.ssi_signo) {
++	case SIGCHLD:
++		return master_waitpid(m);
++	case SIGINT:
++		return err_r(-EINTR, "interrupted");
++	default:
++		return err_r(-EINVAL, "caught invalid signal");
++	}
++}
++
++static int master_handle_bus(struct master *m)
++{
++	struct kdbus_cmd_recv recv = { .size = sizeof(recv) };
++	const struct kdbus_msg *msg = NULL;
++	const struct kdbus_item *item;
++	const struct kdbus_vec *vec = NULL;
++	int r = 0;
++
++	/*
++	 * To receive a message, the KDBUS_CMD_RECV ioctl is used.
++	 * It takes an argument of type 'struct kdbus_cmd_recv', which
++	 * will contain information on the received message when the call
++	 * returns. See kdbus.message(7).
++	 */
++	r = kdbus_cmd_recv(m->bus->fd, &recv);
++	/*
++	 * EAGAIN is returned when there is no message waiting on this
++	 * connection. This is not an error - simply bail out.
++	 */
++	if (r == -EAGAIN)
++		return 0;
++	if (r < 0)
++		return err_r(r, "cannot receive message");
++
++	/*
++	 * Messages received by a connection are stored inside the connection's
++	 * pool, at an offset that has been returned in the 'recv' command
++	 * struct above. The value describes the relative offset from the
++	 * start address of the pool. A message is described with
++	 * 'struct kdbus_msg'. See kdbus.message(7).
++	 */
++	msg = (void *)(m->bus->pool + recv.msg.offset);
++
++	/*
++	 * A messages describes its actual payload in an array of items.
++	 * KDBUS_FOREACH() is a simple iterator that walks such an array.
++	 * struct kdbus_msg has a field to denote its total size, which is
++	 * needed to determine the number of items in the array.
++	 */
++	KDBUS_FOREACH(item, msg->items,
++		      msg->size - offsetof(struct kdbus_msg, items)) {
++		/*
++		 * An item of type PAYLOAD_OFF describes in-line memory
++		 * stored in the pool at a described offset. That offset is
++		 * relative to the start address of the message header.
++		 * This example program only expects one single item of that
++		 * type, remembers the struct kdbus_vec member of the item
++		 * when it sees it, and bails out if there is more than one
++		 * of them.
++		 */
++		if (item->type == KDBUS_ITEM_PAYLOAD_OFF) {
++			if (vec) {
++				r = err_r(-EEXIST,
++					  "message with multiple vecs");
++				break;
++			}
++			vec = &item->vec;
++			if (vec->size != 1) {
++				r = err_r(-EINVAL, "invalid message size");
++				break;
++			}
++
++		/*
++		 * MEMFDs are transported as items of type PAYLOAD_MEMFD.
++		 * If such an item is attached, a new file descriptor was
++		 * installed into the task when KDBUS_CMD_RECV was called, and
++		 * its number is stored in item->memfd.fd.
++		 * Implementers *must* handle this item type and close the
++		 * file descriptor when no longer needed in order to prevent
++		 * file descriptor exhaustion. This example program just bails
++		 * out with an error in this case, as memfds are not expected
++		 * in this context.
++		 */
++		} else if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD) {
++			r = err_r(-EINVAL, "message with memfd");
++			break;
++		}
++	}
++	if (r < 0)
++		goto exit;
++	if (!vec) {
++		r = err_r(-EINVAL, "empty message");
++		goto exit;
++	}
++
++	switch (*((const uint8_t *)msg + vec->offset)) {
++	case 'r': {
++		r = master_reply(m, msg);
++		break;
++	}
++	default:
++		r = err_r(-EINVAL, "invalid message type");
++		break;
++	}
++
++exit:
++	/*
++	 * We are done with the memory slice that was given to us through
++	 * recv.msg.offset. Tell the kernel it can use it for other content
++	 * in the future. See kdbus.pool(7).
++	 */
++	bus_poool_free_slice(m->bus, recv.msg.offset);
++	return r;
++}
++
++static int master_reply(struct master *m, const struct kdbus_msg *msg)
++{
++	struct kdbus_cmd_send cmd;
++	struct kdbus_item *item;
++	struct kdbus_msg *reply;
++	size_t size, status, p[2];
++	int r;
++
++	/*
++	 * This functions sends a message over kdbus. To do this, it uses the
++	 * KDBUS_CMD_SEND ioctl, which takes a command struct argument of type
++	 * 'struct kdbus_cmd_send'. This struct stores a pointer to the actual
++	 * message to send. See kdbus.message(7).
++	 */
++	p[0] = m->prime->done;
++	p[1] = prime_done(m->prime) ? 0 : PRIME_STEPS;
++
++	size = sizeof(*reply);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
++
++	/* Prepare the message to send */
++	reply = alloca(size);
++	memset(reply, 0, size);
++	reply->size = size;
++
++	/* Each message has a cookie that can be used to send replies */
++	reply->cookie = 1;
++
++	/* The payload_type is arbitrary, but it must be non-zero */
++	reply->payload_type = 0xdeadbeef;
++
++	/*
++	 * We are sending a reply. Let the kernel know the cookie of the
++	 * message we are replying to.
++	 */
++	reply->cookie_reply = msg->cookie;
++
++	/*
++	 * Messages can either be directed to a well-known name (stored as
++	 * string) or to a unique name (stored as number). This example does
++	 * the latter. If the message would be directed to a well-known name
++	 * instead, the message's dst_id field would be set to
++	 * KDBUS_DST_ID_NAME, and the name would be attaches in an item of type
++	 * KDBUS_ITEM_DST_NAME. See below for an example, and also refer to
++	 * kdbus.message(7).
++	 */
++	reply->dst_id = msg->src_id;
++
++	/* Our message has exactly one item to store its payload */
++	item = reply->items;
++	item->type = KDBUS_ITEM_PAYLOAD_VEC;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
++	item->vec.address = (uintptr_t)p;
++	item->vec.size = sizeof(p);
++
++	/*
++	 * Now prepare the command struct, and reference the message we want
++	 * to send.
++	 */
++	memset(&cmd, 0, sizeof(cmd));
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)reply;
++
++	/*
++	 * Finally, employ the command on the connection owner
++	 * file descriptor.
++	 */
++	r = kdbus_cmd_send(m->bus->fd, &cmd);
++	if (r < 0)
++		return err_r(r, "cannot send reply");
++
++	if (p[1]) {
++		prime_consume(m->prime, p[1]);
++		status = m->prime->done * 10000 / m->prime->max;
++		if (status != m->prime->status) {
++			m->prime->status = status;
++			fprintf(stderr, "status: %7.3lf%%\n",
++				(double)status / 100);
++		}
++	}
++
++	return 0;
++}
++
++static int master_waitpid(struct master *m)
++{
++	pid_t pid;
++	int r;
++
++	while ((pid = waitpid(-1, &r, WNOHANG)) > 0) {
++		if (m->n_workers > 0)
++			--m->n_workers;
++		if (!WIFEXITED(r))
++			r = err_r(-EINVAL, "child died unexpectedly");
++		else if (WEXITSTATUS(r) != 0)
++			r = err_r(-WEXITSTATUS(r), "child failed");
++	}
++
++	return r;
++}
++
++static int master_spawn(struct master *m)
++{
++	struct child *c = NULL;
++	struct prime *p = NULL;
++	pid_t pid;
++	int r;
++
++	/* Spawn off one child and call child_run() inside it */
++
++	pid = fork();
++	if (pid < 0)
++		return err("cannot fork");
++	if (pid > 0) {
++		/* parent */
++		++m->n_workers;
++		return 0;
++	}
++
++	/* child */
++
++	p = m->prime;
++	m->prime = NULL;
++	master_free(m);
++
++	r = child_new(&c, p);
++	if (r < 0)
++		goto exit;
++
++	r = child_run(c);
++
++exit:
++	child_free(c);
++	exit(abs(r));
++}
++
++static int child_new(struct child **out, struct prime *p)
++{
++	struct child *c;
++	int r;
++
++	c = calloc(1, sizeof(*c));
++	if (!c)
++		return err("cannot allocate child");
++
++	c->prime = p;
++
++	/*
++	 * Open a connection to the bus and require each received message to
++	 * carry a list of the well-known names the sendind connection currently
++	 * owns. The current UID is needed in order to determine the name of the
++	 * bus node to connect to.
++	 */
++	r = bus_open_connection(&c->bus, getuid(),
++				arg_busname, KDBUS_ATTACH_NAMES);
++	if (r < 0)
++		goto error;
++
++	/*
++	 * Install a kdbus match so the child's connection gets notified when
++	 * the master loses its well-known name.
++	 */
++	r = bus_install_name_loss_match(c->bus, arg_master);
++	if (r < 0)
++		goto error;
++
++	*out = c;
++	return 0;
++
++error:
++	child_free(c);
++	return r;
++}
++
++static void child_free(struct child *c)
++{
++	if (!c)
++		return;
++
++	bus_close_connection(c->bus);
++	prime_free(c->prime);
++	free(c);
++}
++
++static int child_run(struct child *c)
++{
++	struct kdbus_cmd_send cmd;
++	struct kdbus_item *item;
++	struct kdbus_vec *vec = NULL;
++	struct kdbus_msg *msg;
++	struct timespec spec;
++	size_t n, steps, size;
++	int r = 0;
++
++	/*
++	 * Let's send a message to the master and ask for work. To do this,
++	 * we use the KDBUS_CMD_SEND ioctl, which takes an argument of type
++	 * 'struct kdbus_cmd_send'. This struct stores a pointer to the actual
++	 * message to send. See kdbus.message(7).
++	 */
++	size = sizeof(*msg);
++	size += KDBUS_ITEM_SIZE(strlen(arg_master) + 1);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
++
++	msg = alloca(size);
++	memset(msg, 0, size);
++	msg->size = size;
++
++	/*
++	 * Tell the kernel that we expect a reply to this message. This means
++	 * that
++	 *
++	 * a) The remote peer will gain temporary permission to talk to us
++	 *    even if it would not be allowed to normally.
++	 *
++	 * b) A timeout value is required.
++	 *
++	 *    For asynchronous send commands, if no reply is received, we will
++	 *    get a kernel notification with an item of type
++	 *    KDBUS_ITEM_REPLY_TIMEOUT attached.
++	 *
++	 *    For synchronous send commands (which this example does), the
++	 *    ioctl will block until a reply is received or the timeout is
++	 *    exceeded.
++	 */
++	msg->flags = KDBUS_MSG_EXPECT_REPLY;
++
++	/* Set our cookie. Replies must use this cookie to send their reply. */
++	msg->cookie = 1;
++
++	/* The payload_type is arbitrary, but it must be non-zero */
++	msg->payload_type = 0xdeadbeef;
++
++	/*
++	 * We are sending our message to the current owner of a well-known
++	 * name. This makes an item of type KDBUS_ITEM_DST_NAME mandatory.
++	 */
++	msg->dst_id = KDBUS_DST_ID_NAME;
++
++	/*
++	 * Set the reply timeout to 5 seconds. Timeouts are always set in
++	 * absolute timestamps, based con CLOCK_MONOTONIC. See kdbus.message(7).
++	 */
++	clock_gettime(CLOCK_MONOTONIC_COARSE, &spec);
++	msg->timeout_ns += (5 + spec.tv_sec) * 1000ULL * 1000ULL * 1000ULL;
++	msg->timeout_ns += spec.tv_nsec;
++
++	/*
++	 * Fill the appended items. First, set the well-known name of the
++	 * destination we want to talk to.
++	 */
++	item = msg->items;
++	item->type = KDBUS_ITEM_DST_NAME;
++	item->size = KDBUS_ITEM_HEADER_SIZE + strlen(arg_master) + 1;
++	strcpy(item->str, arg_master);
++
++	/*
++	 * The 2nd item contains a vector to memory we want to send. It
++	 * can be content of any type. In our case, we're sending a one-byte
++	 * string only. The memory referenced by this item will be copied into
++	 * the pool of the receiver connection, and does not need to be valid
++	 * after the command is employed.
++	 */
++	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)"r";
++	item->vec.size = 1;
++
++	/* Set up the command struct and reference the message we prepared */
++	memset(&cmd, 0, sizeof(cmd));
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	/*
++	 * The send commands knows a mode in which it will block until a
++	 * reply to a message is received. This example uses that mode.
++	 * The pool offset to the received reply will be stored in the command
++	 * struct after the send command returned. See below.
++	 */
++	cmd.flags = KDBUS_SEND_SYNC_REPLY;
++
++	/*
++	 * Finally, employ the command on the connection owner
++	 * file descriptor.
++	 */
++	r = kdbus_cmd_send(c->bus->fd, &cmd);
++	if (r == -ESRCH || r == -EPIPE || r == -ECONNRESET)
++		return 0;
++	if (r < 0)
++		return err_r(r, "cannot send request to master");
++
++	/*
++	 * The command was sent with the KDBUS_SEND_SYNC_REPLY flag set,
++	 * and returned successfully, which means that cmd.reply.offset now
++	 * points to a message inside our connection's pool where the reply
++	 * is found. This is equivalent to receiving the reply with
++	 * KDBUS_CMD_RECV, but it doesn't require waiting for the reply with
++	 * poll() and also saves the ioctl to receive the message.
++	 */
++	msg = (void *)(c->bus->pool + cmd.reply.offset);
++
++	/*
++	 * A messages describes its actual payload in an array of items.
++	 * KDBUS_FOREACH() is a simple iterator that walks such an array.
++	 * struct kdbus_msg has a field to denote its total size, which is
++	 * needed to determine the number of items in the array.
++	 */
++	KDBUS_FOREACH(item, msg->items,
++		      msg->size - offsetof(struct kdbus_msg, items)) {
++		/*
++		 * An item of type PAYLOAD_OFF describes in-line memory
++		 * stored in the pool at a described offset. That offset is
++		 * relative to the start address of the message header.
++		 * This example program only expects one single item of that
++		 * type, remembers the struct kdbus_vec member of the item
++		 * when it sees it, and bails out if there is more than one
++		 * of them.
++		 */
++		if (item->type == KDBUS_ITEM_PAYLOAD_OFF) {
++			if (vec) {
++				r = err_r(-EEXIST,
++					  "message with multiple vecs");
++				break;
++			}
++			vec = &item->vec;
++			if (vec->size != 2 * sizeof(size_t)) {
++				r = err_r(-EINVAL, "invalid message size");
++				break;
++			}
++		/*
++		 * MEMFDs are transported as items of type PAYLOAD_MEMFD.
++		 * If such an item is attached, a new file descriptor was
++		 * installed into the task when KDBUS_CMD_RECV was called, and
++		 * its number is stored in item->memfd.fd.
++		 * Implementers *must* handle this item type close the
++		 * file descriptor when no longer needed in order to prevent
++		 * file descriptor exhaustion. This example program just bails
++		 * out with an error in this case, as memfds are not expected
++		 * in this context.
++		 */
++		} else if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD) {
++			r = err_r(-EINVAL, "message with memfd");
++			break;
++		}
++	}
++	if (r < 0)
++		goto exit;
++	if (!vec) {
++		r = err_r(-EINVAL, "empty message");
++		goto exit;
++	}
++
++	n = ((size_t *)((const uint8_t *)msg + vec->offset))[0];
++	steps = ((size_t *)((const uint8_t *)msg + vec->offset))[1];
++
++	while (steps-- > 0) {
++		++n;
++		r = prime_run(c->prime, c->bus, n);
++		if (r < 0)
++			break;
++		r = bus_poll(c->bus);
++		if (r != 0) {
++			r = r < 0 ? r : -EINTR;
++			break;
++		}
++	}
++
++exit:
++	/*
++	 * We are done with the memory slice that was given to us through
++	 * cmd.reply.offset. Tell the kernel it can use it for other content
++	 * in the future. See kdbus.pool(7).
++	 */
++	bus_poool_free_slice(c->bus, cmd.reply.offset);
++	return r;
++}
++
++/*
++ * Prime Computation
++ *
++ */
++
++static int prime_new(struct prime **out)
++{
++	struct prime *p;
++	int r;
++
++	p = calloc(1, sizeof(*p));
++	if (!p)
++		return err("cannot allocate prime memory");
++
++	p->fd = -1;
++	p->area = MAP_FAILED;
++	p->max = MAX_PRIMES;
++
++	/*
++	 * Prepare and map a memfd to store the bit-fields for the number
++	 * ranges we want to perform the prime detection on.
++	 */
++	p->fd = syscall(__NR_memfd_create, "prime-area", MFD_CLOEXEC);
++	if (p->fd < 0) {
++		r = err("cannot create memfd");
++		goto error;
++	}
++
++	r = ftruncate(p->fd, p->max / 8 + 1);
++	if (r < 0) {
++		r = err("cannot ftruncate area");
++		goto error;
++	}
++
++	p->area = mmap(NULL, p->max / 8 + 1, PROT_READ | PROT_WRITE,
++		       MAP_SHARED, p->fd, 0);
++	if (p->area == MAP_FAILED) {
++		r = err("cannot mmap memfd");
++		goto error;
++	}
++
++	*out = p;
++	return 0;
++
++error:
++	prime_free(p);
++	return r;
++}
++
++static void prime_free(struct prime *p)
++{
++	if (!p)
++		return;
++
++	if (p->area != MAP_FAILED)
++		munmap(p->area, p->max / 8 + 1);
++	if (p->fd >= 0)
++		close(p->fd);
++	free(p);
++}
++
++static bool prime_done(struct prime *p)
++{
++	return p->done >= p->max;
++}
++
++static void prime_consume(struct prime *p, size_t amount)
++{
++	p->done += amount;
++}
++
++static int prime_run(struct prime *p, struct bus *cancel, size_t number)
++{
++	size_t i, n = 0;
++	int r;
++
++	if (number < 2 || number > 65535)
++		return 0;
++
++	for (i = number * number;
++	     i < p->max && i > number;
++	     i += number) {
++		p->area[i / 8] |= 1 << (i % 8);
++
++		if (!(++n % (1 << 20))) {
++			r = bus_poll(cancel);
++			if (r != 0)
++				return r < 0 ? r : -EINTR;
++		}
++	}
++
++	return 0;
++}
++
++static void prime_print(struct prime *p)
++{
++	size_t i, l = 0;
++
++	fprintf(stderr, "PRIMES:");
++	for (i = 0; i < p->max; ++i) {
++		if (!(p->area[i / 8] & (1 << (i % 8))))
++			fprintf(stderr, "%c%7zu", !(l++ % 16) ? '\n' : ' ', i);
++	}
++	fprintf(stderr, "\nEND\n");
++}
++
++static int bus_open_connection(struct bus **out, uid_t uid, const char *name,
++			       uint64_t recv_flags)
++{
++	struct kdbus_cmd_hello hello;
++	char path[128];
++	struct bus *b;
++	int r;
++
++	/*
++	 * The 'bus' object is our representation of a kdbus connection which
++	 * stores two details: the connection owner file descriptor, and the
++	 * mmap()ed memory of its associated pool. See kdbus.connection(7) and
++	 * kdbus.pool(7).
++	 */
++	b = calloc(1, sizeof(*b));
++	if (!b)
++		return err("cannot allocate bus memory");
++
++	b->fd = -1;
++	b->pool = MAP_FAILED;
++
++	/* Compute the name of the bus node to connect to. */
++	snprintf(path, sizeof(path), "/sys/fs/%s/%lu-%s/bus",
++		 arg_modname, (unsigned long)uid, name);
++	b->fd = open(path, O_RDWR | O_CLOEXEC);
++	if (b->fd < 0) {
++		r = err("cannot open bus");
++		goto error;
++	}
++
++	/*
++	 * To make a connection to the bus, the KDBUS_CMD_HELLO ioctl is used.
++	 * It takes an argument of type 'struct kdbus_cmd_hello'.
++	 */
++	memset(&hello, 0, sizeof(hello));
++	hello.size = sizeof(hello);
++
++	/*
++	 * Specify a mask of metadata attach flags, describing metadata items
++	 * that this new connection allows to be sent.
++	 */
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++
++	/*
++	 * Specify a mask of metadata attach flags, describing metadata items
++	 * that this new connection wants to be receive along with each message.
++	 */
++	hello.attach_flags_recv = recv_flags;
++
++	/*
++	 * A connection may choose the size of its pool, but the number has to
++	 * comply with two rules: a) it must be greater than 0, and b) it must
++	 * be a mulitple of PAGE_SIZE. See kdbus.pool(7).
++	 */
++	hello.pool_size = POOL_SIZE;
++
++	/*
++	 * Now employ the command on the file descriptor opened above.
++	 * This command will turn the file descriptor into a connection-owner
++	 * file descriptor that controls the life-time of the connection; once
++	 * it's closed, the connection is shut down.
++	 */
++	r = kdbus_cmd_hello(b->fd, &hello);
++	if (r < 0) {
++		err_r(r, "HELLO failed");
++		goto error;
++	}
++
++	bus_poool_free_slice(b, hello.offset);
++
++	/*
++	 * Map the pool of the connection. Its size has been set in the
++	 * command struct above. See kdbus.pool(7).
++	 */
++	b->pool = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, b->fd, 0);
++	if (b->pool == MAP_FAILED) {
++		r = err("cannot mmap pool");
++		goto error;
++	}
++
++	*out = b;
++	return 0;
++
++error:
++	bus_close_connection(b);
++	return r;
++}
++
++static void bus_close_connection(struct bus *b)
++{
++	if (!b)
++		return;
++
++	/*
++	 * A bus connection is closed by simply calling close() on the
++	 * connection owner file descriptor. The unique name and all owned
++	 * well-known names of the conneciton will disappear.
++	 * See kdbus.connection(7).
++	 */
++	if (b->pool != MAP_FAILED)
++		munmap(b->pool, POOL_SIZE);
++	if (b->fd >= 0)
++		close(b->fd);
++	free(b);
++}
++
++static void bus_poool_free_slice(struct bus *b, uint64_t offset)
++{
++	struct kdbus_cmd_free cmd = {
++		.size = sizeof(cmd),
++		.offset = offset,
++	};
++	int r;
++
++	/*
++	 * Once we're done with a piece of pool memory that was returned
++	 * by a command, we have to call the KDBUS_CMD_FREE ioctl on it so it
++	 * can be reused. The command takes an argument of type
++	 * 'struct kdbus_cmd_free', in which the pool offset of the slice to
++	 * free is stored. The ioctl is employed on the connection owner
++	 * file descriptor. See kdbus.pool(7),
++	 */
++	r = kdbus_cmd_free(b->fd, &cmd);
++	if (r < 0)
++		err_r(r, "cannot free pool slice");
++}
++
++static int bus_acquire_name(struct bus *b, const char *name)
++{
++	struct kdbus_item *item;
++	struct kdbus_cmd *cmd;
++	size_t size;
++	int r;
++
++	/*
++	 * This function acquires a well-known name on the bus through the
++	 * KDBUS_CMD_NAME_ACQUIRE ioctl. This ioctl takes an argument of type
++	 * 'struct kdbus_cmd', which is assembled below. See kdbus.name(7).
++	 */
++	size = sizeof(*cmd);
++	size += KDBUS_ITEM_SIZE(strlen(name) + 1);
++
++	cmd = alloca(size);
++	memset(cmd, 0, size);
++	cmd->size = size;
++
++	/*
++	 * The command requires an item of type KDBUS_ITEM_NAME, and its
++	 * content must be a valid bus name.
++	 */
++	item = cmd->items;
++	item->type = KDBUS_ITEM_NAME;
++	item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
++	strcpy(item->str, name);
++
++	/*
++	 * Employ the command on the connection owner file descriptor.
++	 */
++	r = kdbus_cmd_name_acquire(b->fd, cmd);
++	if (r < 0)
++		return err_r(r, "cannot acquire name");
++
++	return 0;
++}
++
++static int bus_install_name_loss_match(struct bus *b, const char *name)
++{
++	struct kdbus_cmd_match *match;
++	struct kdbus_item *item;
++	size_t size;
++	int r;
++
++	/*
++	 * In order to install a match for signal messages, we have to
++	 * assemble a 'struct kdbus_cmd_match' and use it along with the
++	 * KDBUS_CMD_MATCH_ADD ioctl. See kdbus.match(7).
++	 */
++	size = sizeof(*match);
++	size += KDBUS_ITEM_SIZE(sizeof(item->name_change) + strlen(name) + 1);
++
++	match = alloca(size);
++	memset(match, 0, size);
++	match->size = size;
++
++	/*
++	 * A match is comprised of many 'rules', each of which describes a
++	 * mandatory detail of the message. All rules of a match must be
++	 * satified in order to make a message pass.
++	 */
++	item = match->items;
++
++	/*
++	 * In this case, we're interested in notifications that inform us
++	 * about a well-known name being removed from the bus.
++	 */
++	item->type = KDBUS_ITEM_NAME_REMOVE;
++	item->size = KDBUS_ITEM_HEADER_SIZE +
++			sizeof(item->name_change) + strlen(name) + 1;
++
++	/*
++	 * We could limit the match further and require a specific unique-ID
++	 * to be the new or the old owner of the name. In this case, however,
++	 * we don't, and allow 'any' id.
++	 */
++	item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
++	item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
++
++	/* Copy in the well-known name we're interested in */
++	strcpy(item->name_change.name, name);
++
++	/*
++	 * Add the match through the KDBUS_CMD_MATCH_ADD ioctl, employed on
++	 * the connection owner fd.
++	 */
++	r = kdbus_cmd_match_add(b->fd, match);
++	if (r < 0)
++		return err_r(r, "cannot add match");
++
++	return 0;
++}
++
++static int bus_poll(struct bus *b)
++{
++	struct pollfd fds[1] = {};
++	int r;
++
++	/*
++	 * A connection endpoint supports poll() and will wake-up the
++	 * task with POLLIN set once a message has arrived.
++	 */
++	fds[0].fd = b->fd;
++	fds[0].events = POLLIN;
++	r = poll(fds, sizeof(fds) / sizeof(*fds), 0);
++	if (r < 0)
++		return err("cannot poll bus");
++	return !!(fds[0].revents & POLLIN);
++}
++
++static int bus_make(uid_t uid, const char *name)
++{
++	struct kdbus_item *item;
++	struct kdbus_cmd *make;
++	char path[128], busname[128];
++	size_t size;
++	int r, fd;
++
++	/*
++	 * Compute the full path to the 'control' node. 'arg_modname' may be
++	 * set to a different value than 'kdbus' for development purposes.
++	 * The 'control' node is the primary entry point to kdbus that must be
++	 * used in order to create a bus. See kdbus(7) and kdbus.bus(7).
++	 */
++	snprintf(path, sizeof(path), "/sys/fs/%s/control", arg_modname);
++
++	/*
++	 * Compute the bus name. A valid bus name must always be prefixed with
++	 * the EUID of the currently running process in order to avoid name
++	 * conflicts. See kdbus.bus(7).
++	 */
++	snprintf(busname, sizeof(busname), "%lu-%s", (unsigned long)uid, name);
++
++	fd = open(path, O_RDWR | O_CLOEXEC);
++	if (fd < 0)
++		return err("cannot open control file");
++
++	/*
++	 * The KDBUS_CMD_BUS_MAKE ioctl takes an argument of type
++	 * 'struct kdbus_cmd', and expects at least two items attached to
++	 * it: one to decribe the bloom parameters to be propagated to
++	 * connections of the bus, and the name of the bus that was computed
++	 * above. Assemble this struct now, and fill it with values.
++	 */
++	size = sizeof(*make);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_parameter));
++	size += KDBUS_ITEM_SIZE(strlen(busname) + 1);
++
++	make = alloca(size);
++	memset(make, 0, size);
++	make->size = size;
++
++	/*
++	 * Each item has a 'type' and 'size' field, and must be stored at an
++	 * 8-byte aligned address. The KDBUS_ITEM_NEXT macro is used to advance
++	 * the pointer. See kdbus.item(7) for more details.
++	 */
++	item = make->items;
++	item->type = KDBUS_ITEM_BLOOM_PARAMETER;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->bloom_parameter);
++	item->bloom_parameter.size = 8;
++	item->bloom_parameter.n_hash = 1;
++
++	/* The name of the new bus is stored in the next item. */
++	item = KDBUS_ITEM_NEXT(item);
++	item->type = KDBUS_ITEM_MAKE_NAME;
++	item->size = KDBUS_ITEM_HEADER_SIZE + strlen(busname) + 1;
++	strcpy(item->str, busname);
++
++	/*
++	 * Now create the bus via the KDBUS_CMD_BUS_MAKE ioctl and return the
++	 * fd that was used back to the caller of this function. This fd is now
++	 * called a 'bus owner file descriptor', and it controls the life-time
++	 * of the newly created bus; once the file descriptor is closed, the
++	 * bus goes away, and all connections are shut down. See kdbus.bus(7).
++	 */
++	r = kdbus_cmd_bus_make(fd, make);
++	if (r < 0) {
++		err_r(r, "cannot make bus");
++		close(fd);
++		return r;
++	}
++
++	return fd;
++}
++
++#else
++
++#warning "Skipping compilation due to unsupported libc version"
++
++int main(int argc, char **argv)
++{
++	fprintf(stderr,
++		"Compilation of %s was skipped due to unsupported libc.\n",
++		argv[0]);
++
++	return EXIT_FAILURE;
++}
++
++#endif /* libc sanity check */
+diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
+index 95abddc..b57100c 100644
+--- a/tools/testing/selftests/Makefile
++++ b/tools/testing/selftests/Makefile
+@@ -5,6 +5,7 @@ TARGETS += exec
+ TARGETS += firmware
+ TARGETS += ftrace
+ TARGETS += kcmp
++TARGETS += kdbus
+ TARGETS += memfd
+ TARGETS += memory-hotplug
+ TARGETS += mount
+diff --git a/tools/testing/selftests/kdbus/.gitignore b/tools/testing/selftests/kdbus/.gitignore
+new file mode 100644
+index 0000000..d3ef42f
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/.gitignore
+@@ -0,0 +1 @@
++kdbus-test
+diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile
+new file mode 100644
+index 0000000..8f36cb5
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/Makefile
+@@ -0,0 +1,49 @@
++CFLAGS += -I../../../../usr/include/
++CFLAGS += -I../../../../samples/kdbus/
++CFLAGS += -I../../../../include/uapi/
++CFLAGS += -std=gnu99
++CFLAGS += -DKBUILD_MODNAME=\"kdbus\" -D_GNU_SOURCE
++LDLIBS = -pthread -lcap -lm
++
++OBJS= \
++	kdbus-enum.o		\
++	kdbus-util.o		\
++	kdbus-test.o		\
++	kdbus-test.o		\
++	test-activator.o	\
++	test-benchmark.o	\
++	test-bus.o		\
++	test-chat.o		\
++	test-connection.o	\
++	test-daemon.o		\
++	test-endpoint.o		\
++	test-fd.o		\
++	test-free.o		\
++	test-match.o		\
++	test-message.o		\
++	test-metadata-ns.o	\
++	test-monitor.o		\
++	test-names.o		\
++	test-policy.o		\
++	test-policy-ns.o	\
++	test-policy-priv.o	\
++	test-sync.o		\
++	test-timeout.o
++
++all: kdbus-test
++
++include ../lib.mk
++
++%.o: %.c kdbus-enum.h kdbus-test.h kdbus-util.h
++	$(CC) $(CFLAGS) -c $< -o $@
++
++kdbus-test: $(OBJS)
++	$(CC) $(CFLAGS) $^ $(LDLIBS) -o $@
++
++TEST_PROGS := kdbus-test
++
++run_tests:
++	./kdbus-test --tap
++
++clean:
++	rm -f *.o kdbus-test
+diff --git a/tools/testing/selftests/kdbus/kdbus-enum.c b/tools/testing/selftests/kdbus/kdbus-enum.c
+new file mode 100644
+index 0000000..4f1e579
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/kdbus-enum.c
+@@ -0,0 +1,94 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++struct kdbus_enum_table {
++	long long id;
++	const char *name;
++};
++
++#define TABLE(what) static struct kdbus_enum_table kdbus_table_##what[]
++#define ENUM(_id) { .id = _id, .name = STRINGIFY(_id) }
++#define LOOKUP(what)							\
++	const char *enum_##what(long long id)				\
++	{								\
++		for (size_t i = 0; i < ELEMENTSOF(kdbus_table_##what); i++) \
++			if (id == kdbus_table_##what[i].id)		\
++				return kdbus_table_##what[i].name;	\
++		return "UNKNOWN";					\
++	}
++
++TABLE(CMD) = {
++	ENUM(KDBUS_CMD_BUS_MAKE),
++	ENUM(KDBUS_CMD_ENDPOINT_MAKE),
++	ENUM(KDBUS_CMD_HELLO),
++	ENUM(KDBUS_CMD_SEND),
++	ENUM(KDBUS_CMD_RECV),
++	ENUM(KDBUS_CMD_LIST),
++	ENUM(KDBUS_CMD_NAME_RELEASE),
++	ENUM(KDBUS_CMD_CONN_INFO),
++	ENUM(KDBUS_CMD_MATCH_ADD),
++	ENUM(KDBUS_CMD_MATCH_REMOVE),
++};
++LOOKUP(CMD);
++
++TABLE(MSG) = {
++	ENUM(_KDBUS_ITEM_NULL),
++	ENUM(KDBUS_ITEM_PAYLOAD_VEC),
++	ENUM(KDBUS_ITEM_PAYLOAD_OFF),
++	ENUM(KDBUS_ITEM_PAYLOAD_MEMFD),
++	ENUM(KDBUS_ITEM_FDS),
++	ENUM(KDBUS_ITEM_BLOOM_PARAMETER),
++	ENUM(KDBUS_ITEM_BLOOM_FILTER),
++	ENUM(KDBUS_ITEM_DST_NAME),
++	ENUM(KDBUS_ITEM_MAKE_NAME),
++	ENUM(KDBUS_ITEM_ATTACH_FLAGS_SEND),
++	ENUM(KDBUS_ITEM_ATTACH_FLAGS_RECV),
++	ENUM(KDBUS_ITEM_ID),
++	ENUM(KDBUS_ITEM_NAME),
++	ENUM(KDBUS_ITEM_TIMESTAMP),
++	ENUM(KDBUS_ITEM_CREDS),
++	ENUM(KDBUS_ITEM_PIDS),
++	ENUM(KDBUS_ITEM_AUXGROUPS),
++	ENUM(KDBUS_ITEM_OWNED_NAME),
++	ENUM(KDBUS_ITEM_TID_COMM),
++	ENUM(KDBUS_ITEM_PID_COMM),
++	ENUM(KDBUS_ITEM_EXE),
++	ENUM(KDBUS_ITEM_CMDLINE),
++	ENUM(KDBUS_ITEM_CGROUP),
++	ENUM(KDBUS_ITEM_CAPS),
++	ENUM(KDBUS_ITEM_SECLABEL),
++	ENUM(KDBUS_ITEM_AUDIT),
++	ENUM(KDBUS_ITEM_CONN_DESCRIPTION),
++	ENUM(KDBUS_ITEM_NAME_ADD),
++	ENUM(KDBUS_ITEM_NAME_REMOVE),
++	ENUM(KDBUS_ITEM_NAME_CHANGE),
++	ENUM(KDBUS_ITEM_ID_ADD),
++	ENUM(KDBUS_ITEM_ID_REMOVE),
++	ENUM(KDBUS_ITEM_REPLY_TIMEOUT),
++	ENUM(KDBUS_ITEM_REPLY_DEAD),
++};
++LOOKUP(MSG);
++
++TABLE(PAYLOAD) = {
++	ENUM(KDBUS_PAYLOAD_KERNEL),
++	ENUM(KDBUS_PAYLOAD_DBUS),
++};
++LOOKUP(PAYLOAD);
+diff --git a/tools/testing/selftests/kdbus/kdbus-enum.h b/tools/testing/selftests/kdbus/kdbus-enum.h
+new file mode 100644
+index 0000000..ed28cca
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/kdbus-enum.h
+@@ -0,0 +1,15 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#pragma once
++
++const char *enum_CMD(long long id);
++const char *enum_MSG(long long id);
++const char *enum_MATCH(long long id);
++const char *enum_PAYLOAD(long long id);
+diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c
+new file mode 100644
+index 0000000..db57381
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/kdbus-test.c
+@@ -0,0 +1,905 @@
++#include <errno.h>
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <time.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <assert.h>
++#include <getopt.h>
++#include <stdbool.h>
++#include <signal.h>
++#include <sys/mount.h>
++#include <sys/prctl.h>
++#include <sys/wait.h>
++#include <sys/syscall.h>
++#include <sys/eventfd.h>
++#include <linux/sched.h>
++
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++enum {
++	TEST_CREATE_BUS		= 1 << 0,
++	TEST_CREATE_CONN	= 1 << 1,
++};
++
++struct kdbus_test {
++	const char *name;
++	const char *desc;
++	int (*func)(struct kdbus_test_env *env);
++	unsigned int flags;
++};
++
++struct kdbus_test_args {
++	bool mntns;
++	bool pidns;
++	bool userns;
++	char *uid_map;
++	char *gid_map;
++	int loop;
++	int wait;
++	int fork;
++	int tap_output;
++	char *module;
++	char *root;
++	char *test;
++	char *busname;
++};
++
++static const struct kdbus_test tests[] = {
++	{
++		.name	= "bus-make",
++		.desc	= "bus make functions",
++		.func	= kdbus_test_bus_make,
++		.flags	= 0,
++	},
++	{
++		.name	= "hello",
++		.desc	= "the HELLO command",
++		.func	= kdbus_test_hello,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "byebye",
++		.desc	= "the BYEBYE command",
++		.func	= kdbus_test_byebye,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "chat",
++		.desc	= "a chat pattern",
++		.func	= kdbus_test_chat,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "daemon",
++		.desc	= "a simple daemon",
++		.func	= kdbus_test_daemon,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "fd-passing",
++		.desc	= "file descriptor passing",
++		.func	= kdbus_test_fd_passing,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "endpoint",
++		.desc	= "custom endpoint",
++		.func	= kdbus_test_custom_endpoint,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "monitor",
++		.desc	= "monitor functionality",
++		.func	= kdbus_test_monitor,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "name-basics",
++		.desc	= "basic name registry functions",
++		.func	= kdbus_test_name_basic,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "name-conflict",
++		.desc	= "name registry conflict details",
++		.func	= kdbus_test_name_conflict,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "name-queue",
++		.desc	= "queuing of names",
++		.func	= kdbus_test_name_queue,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "name-takeover",
++		.desc	= "takeover of names",
++		.func	= kdbus_test_name_takeover,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "message-basic",
++		.desc	= "basic message handling",
++		.func	= kdbus_test_message_basic,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "message-prio",
++		.desc	= "handling of messages with priority",
++		.func	= kdbus_test_message_prio,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "message-quota",
++		.desc	= "message quotas are enforced",
++		.func	= kdbus_test_message_quota,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "memory-access",
++		.desc	= "memory access",
++		.func	= kdbus_test_memory_access,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "timeout",
++		.desc	= "timeout",
++		.func	= kdbus_test_timeout,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "sync-byebye",
++		.desc	= "synchronous replies vs. BYEBYE",
++		.func	= kdbus_test_sync_byebye,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "sync-reply",
++		.desc	= "synchronous replies",
++		.func	= kdbus_test_sync_reply,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "message-free",
++		.desc	= "freeing of memory",
++		.func	= kdbus_test_free,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "connection-info",
++		.desc	= "retrieving connection information",
++		.func	= kdbus_test_conn_info,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "connection-update",
++		.desc	= "updating connection information",
++		.func	= kdbus_test_conn_update,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "writable-pool",
++		.desc	= "verifying pools are never writable",
++		.func	= kdbus_test_writable_pool,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "policy",
++		.desc	= "policy",
++		.func	= kdbus_test_policy,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "policy-priv",
++		.desc	= "unprivileged bus access",
++		.func	= kdbus_test_policy_priv,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "policy-ns",
++		.desc	= "policy in user namespaces",
++		.func	= kdbus_test_policy_ns,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "metadata-ns",
++		.desc	= "metadata in different namespaces",
++		.func	= kdbus_test_metadata_ns,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "match-id-add",
++		.desc	= "adding of matches by id",
++		.func	= kdbus_test_match_id_add,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "match-id-remove",
++		.desc	= "removing of matches by id",
++		.func	= kdbus_test_match_id_remove,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "match-replace",
++		.desc	= "replace of matches with the same cookie",
++		.func	= kdbus_test_match_replace,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "match-name-add",
++		.desc	= "adding of matches by name",
++		.func	= kdbus_test_match_name_add,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "match-name-remove",
++		.desc	= "removing of matches by name",
++		.func	= kdbus_test_match_name_remove,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "match-name-change",
++		.desc	= "matching for name changes",
++		.func	= kdbus_test_match_name_change,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "match-bloom",
++		.desc	= "matching with bloom filters",
++		.func	= kdbus_test_match_bloom,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "activator",
++		.desc	= "activator connections",
++		.func	= kdbus_test_activator,
++		.flags	= TEST_CREATE_BUS | TEST_CREATE_CONN,
++	},
++	{
++		.name	= "benchmark",
++		.desc	= "benchmark",
++		.func	= kdbus_test_benchmark,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "benchmark-nomemfds",
++		.desc	= "benchmark without using memfds",
++		.func	= kdbus_test_benchmark_nomemfds,
++		.flags	= TEST_CREATE_BUS,
++	},
++	{
++		.name	= "benchmark-uds",
++		.desc	= "benchmark comparison to UDS",
++		.func	= kdbus_test_benchmark_uds,
++		.flags	= TEST_CREATE_BUS,
++	},
++};
++
++#define N_TESTS ((int) (sizeof(tests) / sizeof(tests[0])))
++
++static int test_prepare_env(const struct kdbus_test *t,
++			    const struct kdbus_test_args *args,
++			    struct kdbus_test_env *env)
++{
++	if (t->flags & TEST_CREATE_BUS) {
++		char *s;
++		char *n = NULL;
++		int ret;
++
++		asprintf(&s, "%s/control", args->root);
++
++		env->control_fd = open(s, O_RDWR);
++		free(s);
++		ASSERT_RETURN(env->control_fd >= 0);
++
++		if (!args->busname) {
++			n = unique_name("test-bus");
++			ASSERT_RETURN(n);
++		}
++
++		ret = kdbus_create_bus(env->control_fd,
++				       args->busname ?: n,
++				       _KDBUS_ATTACH_ALL, &s);
++		free(n);
++		ASSERT_RETURN(ret == 0);
++
++		asprintf(&env->buspath, "%s/%s/bus", args->root, s);
++		free(s);
++	}
++
++	if (t->flags & TEST_CREATE_CONN) {
++		env->conn = kdbus_hello(env->buspath, 0, NULL, 0);
++		ASSERT_RETURN(env->conn);
++	}
++
++	env->root = args->root;
++	env->module = args->module;
++
++	return 0;
++}
++
++void test_unprepare_env(const struct kdbus_test *t, struct kdbus_test_env *env)
++{
++	if (env->conn) {
++		kdbus_conn_free(env->conn);
++		env->conn = NULL;
++	}
++
++	if (env->control_fd >= 0) {
++		close(env->control_fd);
++		env->control_fd = -1;
++	}
++
++	if (env->buspath) {
++		free(env->buspath);
++		env->buspath = NULL;
++	}
++}
++
++static int test_run(const struct kdbus_test *t,
++		    const struct kdbus_test_args *kdbus_args,
++		    int wait)
++{
++	int ret;
++	struct kdbus_test_env env = {};
++
++	ret = test_prepare_env(t, kdbus_args, &env);
++	if (ret != TEST_OK)
++		return ret;
++
++	if (wait > 0) {
++		printf("Sleeping %d seconds before running test ...\n", wait);
++		sleep(wait);
++	}
++
++	ret = t->func(&env);
++	test_unprepare_env(t, &env);
++	return ret;
++}
++
++static int test_run_forked(const struct kdbus_test *t,
++			   const struct kdbus_test_args *kdbus_args,
++			   int wait)
++{
++	int ret;
++	pid_t pid;
++
++	pid = fork();
++	if (pid < 0) {
++		return TEST_ERR;
++	} else if (pid == 0) {
++		ret = test_run(t, kdbus_args, wait);
++		_exit(ret);
++	}
++
++	pid = waitpid(pid, &ret, 0);
++	if (pid <= 0)
++		return TEST_ERR;
++	else if (!WIFEXITED(ret))
++		return TEST_ERR;
++	else
++		return WEXITSTATUS(ret);
++}
++
++static void print_test_result(int ret)
++{
++	switch (ret) {
++	case TEST_OK:
++		printf("OK");
++		break;
++	case TEST_SKIP:
++		printf("SKIPPED");
++		break;
++	case TEST_ERR:
++		printf("ERROR");
++		break;
++	}
++}
++
++static int start_all_tests(struct kdbus_test_args *kdbus_args)
++{
++	int ret;
++	unsigned int fail_cnt = 0;
++	unsigned int skip_cnt = 0;
++	unsigned int ok_cnt = 0;
++	unsigned int i;
++
++	if (kdbus_args->tap_output) {
++		printf("1..%d\n", N_TESTS);
++		fflush(stdout);
++	}
++
++	kdbus_util_verbose = false;
++
++	for (i = 0; i < N_TESTS; i++) {
++		const struct kdbus_test *t = tests + i;
++
++		if (!kdbus_args->tap_output) {
++			unsigned int n;
++
++			printf("Testing %s (%s) ", t->desc, t->name);
++			for (n = 0; n < 60 - strlen(t->desc) - strlen(t->name); n++)
++				printf(".");
++			printf(" ");
++		}
++
++		ret = test_run_forked(t, kdbus_args, 0);
++		switch (ret) {
++		case TEST_OK:
++			ok_cnt++;
++			break;
++		case TEST_SKIP:
++			skip_cnt++;
++			break;
++		case TEST_ERR:
++			fail_cnt++;
++			break;
++		}
++
++		if (kdbus_args->tap_output) {
++			printf("%sok %d - %s%s (%s)\n",
++			       (ret == TEST_ERR) ? "not " : "", i + 1,
++			       (ret == TEST_SKIP) ? "# SKIP " : "",
++			       t->desc, t->name);
++			fflush(stdout);
++		} else {
++			print_test_result(ret);
++			printf("\n");
++		}
++	}
++
++	if (kdbus_args->tap_output)
++		printf("Failed %d/%d tests, %.2f%% okay\n", fail_cnt, N_TESTS,
++		       100.0 - (fail_cnt * 100.0) / ((float) N_TESTS));
++	else
++		printf("\nSUMMARY: %u tests passed, %u skipped, %u failed\n",
++		       ok_cnt, skip_cnt, fail_cnt);
++
++	return fail_cnt > 0 ? TEST_ERR : TEST_OK;
++}
++
++static int start_one_test(struct kdbus_test_args *kdbus_args)
++{
++	int i, ret;
++	bool test_found = false;
++
++	for (i = 0; i < N_TESTS; i++) {
++		const struct kdbus_test *t = tests + i;
++
++		if (strcmp(t->name, kdbus_args->test))
++			continue;
++
++		do {
++			test_found = true;
++			if (kdbus_args->fork)
++				ret = test_run_forked(t, kdbus_args,
++						      kdbus_args->wait);
++			else
++				ret = test_run(t, kdbus_args,
++					       kdbus_args->wait);
++
++			printf("Testing %s: ", t->desc);
++			print_test_result(ret);
++			printf("\n");
++
++			if (ret != TEST_OK)
++				break;
++		} while (kdbus_args->loop);
++
++		return ret;
++	}
++
++	if (!test_found) {
++		printf("Unknown test-id '%s'\n", kdbus_args->test);
++		return TEST_ERR;
++	}
++
++	return TEST_OK;
++}
++
++static void usage(const char *argv0)
++{
++	unsigned int i, j;
++
++	printf("Usage: %s [options]\n"
++	       "Options:\n"
++	       "\t-a, --tap		Output test results in TAP format\n"
++	       "\t-m, --module <module>	Kdbus module name\n"
++	       "\t-x, --loop		Run in a loop\n"
++	       "\t-f, --fork		Fork before running a test\n"
++	       "\t-h, --help		Print this help\n"
++	       "\t-r, --root <root>	Toplevel of the kdbus hierarchy\n"
++	       "\t-t, --test <test-id>	Run one specific test only, in verbose mode\n"
++	       "\t-b, --bus <busname>	Instead of generating a random bus name, take <busname>.\n"
++	       "\t-w, --wait <secs>	Wait <secs> before actually starting test\n"
++	       "\t    --mntns		New mount namespace\n"
++	       "\t    --pidns		New PID namespace\n"
++	       "\t    --userns		New user namespace\n"
++	       "\t    --uidmap uid_map	UID map for user namespace\n"
++	       "\t    --gidmap gid_map	GID map for user namespace\n"
++	       "\n", argv0);
++
++	printf("By default, all test are run once, and a summary is printed.\n"
++	       "Available tests for --test:\n\n");
++
++	for (i = 0; i < N_TESTS; i++) {
++		const struct kdbus_test *t = tests + i;
++
++		printf("\t%s", t->name);
++
++		for (j = 0; j < 24 - strlen(t->name); j++)
++			printf(" ");
++
++		printf("Test %s\n", t->desc);
++	}
++
++	printf("\n");
++	printf("Note that some tests may, if run specifically by --test, "
++	       "behave differently, and not terminate by themselves.\n");
++
++	exit(EXIT_FAILURE);
++}
++
++void print_kdbus_test_args(struct kdbus_test_args *args)
++{
++	if (args->userns || args->pidns || args->mntns)
++		printf("# Starting tests in new %s%s%s namespaces%s\n",
++			args->mntns ? "MOUNT " : "",
++			args->pidns ? "PID " : "",
++			args->userns ? "USER " : "",
++			args->mntns ? ", kdbusfs will be remounted" : "");
++	else
++		printf("# Starting tests in the same namespaces\n");
++}
++
++void print_metadata_support(void)
++{
++	bool no_meta_audit, no_meta_cgroups, no_meta_seclabel;
++
++	/*
++	 * KDBUS_ATTACH_CGROUP, KDBUS_ATTACH_AUDIT and
++	 * KDBUS_ATTACH_SECLABEL
++	 */
++	no_meta_audit = !config_auditsyscall_is_enabled();
++	no_meta_cgroups = !config_cgroups_is_enabled();
++	no_meta_seclabel = !config_security_is_enabled();
++
++	if (no_meta_audit | no_meta_cgroups | no_meta_seclabel)
++		printf("# Starting tests without %s%s%s metadata support\n",
++		       no_meta_audit ? "AUDIT " : "",
++		       no_meta_cgroups ? "CGROUP " : "",
++		       no_meta_seclabel ? "SECLABEL " : "");
++	else
++		printf("# Starting tests with full metadata support\n");
++}
++
++int run_tests(struct kdbus_test_args *kdbus_args)
++{
++	int ret;
++	static char control[4096];
++
++	snprintf(control, sizeof(control), "%s/control", kdbus_args->root);
++
++	if (access(control, W_OK) < 0) {
++		printf("Unable to locate control node at '%s'.\n",
++			control);
++		return TEST_ERR;
++	}
++
++	if (kdbus_args->test) {
++		ret = start_one_test(kdbus_args);
++	} else {
++		do {
++			ret = start_all_tests(kdbus_args);
++			if (ret != TEST_OK)
++				break;
++		} while (kdbus_args->loop);
++	}
++
++	return ret;
++}
++
++static void nop_handler(int sig) {}
++
++static int test_prepare_mounts(struct kdbus_test_args *kdbus_args)
++{
++	int ret;
++	char kdbusfs[64] = {'\0'};
++
++	snprintf(kdbusfs, sizeof(kdbusfs), "%sfs", kdbus_args->module);
++
++	/* make current mount slave */
++	ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL);
++	if (ret < 0) {
++		ret = -errno;
++		printf("error mount() root: %d (%m)\n", ret);
++		return ret;
++	}
++
++	/* Remount procfs since we need it in our tests */
++	if (kdbus_args->pidns) {
++		ret = mount("proc", "/proc", "proc",
++			    MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
++		if (ret < 0) {
++			ret = -errno;
++			printf("error mount() /proc : %d (%m)\n", ret);
++			return ret;
++		}
++	}
++
++	/* Remount kdbusfs */
++	ret = mount(kdbusfs, kdbus_args->root, kdbusfs,
++		    MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
++	if (ret < 0) {
++		ret = -errno;
++		printf("error mount() %s :%d (%m)\n", kdbusfs, ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++int run_tests_in_namespaces(struct kdbus_test_args *kdbus_args)
++{
++	int ret;
++	int efd = -1;
++	int status;
++	pid_t pid, rpid;
++	struct sigaction oldsa;
++	struct sigaction sa = {
++		.sa_handler = nop_handler,
++		.sa_flags = SA_NOCLDSTOP,
++	};
++
++	efd = eventfd(0, EFD_CLOEXEC);
++	if (efd < 0) {
++		ret = -errno;
++		printf("eventfd() failed: %d (%m)\n", ret);
++		return TEST_ERR;
++	}
++
++	ret = sigaction(SIGCHLD, &sa, &oldsa);
++	if (ret < 0) {
++		ret = -errno;
++		printf("sigaction() failed: %d (%m)\n", ret);
++		return TEST_ERR;
++	}
++
++	/* setup namespaces */
++	pid = syscall(__NR_clone, SIGCHLD|
++		      (kdbus_args->userns ? CLONE_NEWUSER : 0) |
++		      (kdbus_args->mntns ? CLONE_NEWNS : 0) |
++		      (kdbus_args->pidns ? CLONE_NEWPID : 0), NULL);
++	if (pid < 0) {
++		printf("clone() failed: %d (%m)\n", -errno);
++		return TEST_ERR;
++	}
++
++	if (pid == 0) {
++		eventfd_t event_status = 0;
++
++		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
++		if (ret < 0) {
++			ret = -errno;
++			printf("error prctl(): %d (%m)\n", ret);
++			_exit(TEST_ERR);
++		}
++
++		/* reset sighandlers of childs */
++		ret = sigaction(SIGCHLD, &oldsa, NULL);
++		if (ret < 0) {
++			ret = -errno;
++			printf("sigaction() failed: %d (%m)\n", ret);
++			_exit(TEST_ERR);
++		}
++
++		ret = eventfd_read(efd, &event_status);
++		if (ret < 0 || event_status != 1) {
++			printf("error eventfd_read()\n");
++			_exit(TEST_ERR);
++		}
++
++		if (kdbus_args->mntns) {
++			ret = test_prepare_mounts(kdbus_args);
++			if (ret < 0) {
++				printf("error preparing mounts\n");
++				_exit(TEST_ERR);
++			}
++		}
++
++		ret = run_tests(kdbus_args);
++		_exit(ret);
++	}
++
++	/* Setup userns mapping */
++	if (kdbus_args->userns) {
++		ret = userns_map_uid_gid(pid, kdbus_args->uid_map,
++					 kdbus_args->gid_map);
++		if (ret < 0) {
++			printf("error mapping uid and gid in userns\n");
++			eventfd_write(efd, 2);
++			return TEST_ERR;
++		}
++	}
++
++	ret = eventfd_write(efd, 1);
++	if (ret < 0) {
++		ret = -errno;
++		printf("error eventfd_write(): %d (%m)\n", ret);
++		return TEST_ERR;
++	}
++
++	rpid = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(rpid == pid, TEST_ERR);
++
++	close(efd);
++
++	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
++		return TEST_ERR;
++
++	return TEST_OK;
++}
++
++int start_tests(struct kdbus_test_args *kdbus_args)
++{
++	int ret;
++	bool namespaces;
++	static char fspath[4096];
++
++	namespaces = (kdbus_args->mntns || kdbus_args->pidns ||
++		      kdbus_args->userns);
++
++	/* for pidns we need mntns set */
++	if (kdbus_args->pidns && !kdbus_args->mntns) {
++		printf("Failed: please set both pid and mnt namesapces\n");
++		return TEST_ERR;
++	}
++
++	if (kdbus_args->userns) {
++		if (!config_user_ns_is_enabled()) {
++			printf("User namespace not supported\n");
++			return TEST_ERR;
++		}
++
++		if (!kdbus_args->uid_map || !kdbus_args->gid_map) {
++			printf("Failed: please specify uid or gid mapping\n");
++			return TEST_ERR;
++		}
++	}
++
++	print_kdbus_test_args(kdbus_args);
++	print_metadata_support();
++
++	/* setup kdbus paths */
++	if (!kdbus_args->module)
++		kdbus_args->module = "kdbus";
++
++	if (!kdbus_args->root) {
++		snprintf(fspath, sizeof(fspath), "/sys/fs/%s",
++			 kdbus_args->module);
++		kdbus_args->root = fspath;
++	}
++
++	/* Start tests */
++	if (namespaces)
++		ret = run_tests_in_namespaces(kdbus_args);
++	else
++		ret = run_tests(kdbus_args);
++
++	return ret;
++}
++
++int main(int argc, char *argv[])
++{
++	int t, ret = 0;
++	struct kdbus_test_args *kdbus_args;
++	enum {
++		ARG_MNTNS = 0x100,
++		ARG_PIDNS,
++		ARG_USERNS,
++		ARG_UIDMAP,
++		ARG_GIDMAP,
++	};
++
++	kdbus_args = malloc(sizeof(*kdbus_args));
++	if (!kdbus_args) {
++		printf("unable to malloc() kdbus_args\n");
++		return EXIT_FAILURE;
++	}
++
++	memset(kdbus_args, 0, sizeof(*kdbus_args));
++
++	static const struct option options[] = {
++		{ "loop",	no_argument,		NULL, 'x' },
++		{ "help",	no_argument,		NULL, 'h' },
++		{ "root",	required_argument,	NULL, 'r' },
++		{ "test",	required_argument,	NULL, 't' },
++		{ "bus",	required_argument,	NULL, 'b' },
++		{ "wait",	required_argument,	NULL, 'w' },
++		{ "fork",	no_argument,		NULL, 'f' },
++		{ "module",	required_argument,	NULL, 'm' },
++		{ "tap",	no_argument,		NULL, 'a' },
++		{ "mntns",	no_argument,		NULL, ARG_MNTNS },
++		{ "pidns",	no_argument,		NULL, ARG_PIDNS },
++		{ "userns",	no_argument,		NULL, ARG_USERNS },
++		{ "uidmap",	required_argument,	NULL, ARG_UIDMAP },
++		{ "gidmap",	required_argument,	NULL, ARG_GIDMAP },
++		{}
++	};
++
++	srand(time(NULL));
++
++	while ((t = getopt_long(argc, argv, "hxfm:r:t:b:w:a", options, NULL)) >= 0) {
++		switch (t) {
++		case 'x':
++			kdbus_args->loop = 1;
++			break;
++
++		case 'm':
++			kdbus_args->module = optarg;
++			break;
++
++		case 'r':
++			kdbus_args->root = optarg;
++			break;
++
++		case 't':
++			kdbus_args->test = optarg;
++			break;
++
++		case 'b':
++			kdbus_args->busname = optarg;
++			break;
++
++		case 'w':
++			kdbus_args->wait = strtol(optarg, NULL, 10);
++			break;
++
++		case 'f':
++			kdbus_args->fork = 1;
++			break;
++
++		case 'a':
++			kdbus_args->tap_output = 1;
++			break;
++
++		case ARG_MNTNS:
++			kdbus_args->mntns = true;
++			break;
++
++		case ARG_PIDNS:
++			kdbus_args->pidns = true;
++			break;
++
++		case ARG_USERNS:
++			kdbus_args->userns = true;
++			break;
++
++		case ARG_UIDMAP:
++			kdbus_args->uid_map = optarg;
++			break;
++
++		case ARG_GIDMAP:
++			kdbus_args->gid_map = optarg;
++			break;
++
++		default:
++		case 'h':
++			usage(argv[0]);
++		}
++	}
++
++	ret = start_tests(kdbus_args);
++	if (ret == TEST_ERR)
++		return EXIT_FAILURE;
++
++	free(kdbus_args);
++
++	return 0;
++}
+diff --git a/tools/testing/selftests/kdbus/kdbus-test.h b/tools/testing/selftests/kdbus/kdbus-test.h
+new file mode 100644
+index 0000000..ee937f9
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/kdbus-test.h
+@@ -0,0 +1,84 @@
++#ifndef _TEST_KDBUS_H_
++#define _TEST_KDBUS_H_
++
++struct kdbus_test_env {
++	char *buspath;
++	const char *root;
++	const char *module;
++	int control_fd;
++	struct kdbus_conn *conn;
++};
++
++enum {
++	TEST_OK,
++	TEST_SKIP,
++	TEST_ERR,
++};
++
++#define ASSERT_RETURN_VAL(cond, val)		\
++	if (!(cond)) {			\
++		fprintf(stderr,	"Assertion '%s' failed in %s(), %s:%d\n", \
++			#cond, __func__, __FILE__, __LINE__);	\
++		return val;	\
++	}
++
++#define ASSERT_EXIT_VAL(cond, val)		\
++	if (!(cond)) {			\
++		fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \
++			#cond, __func__, __FILE__, __LINE__);	\
++		_exit(val);	\
++	}
++
++#define ASSERT_BREAK(cond)		\
++	if (!(cond)) {			\
++		fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \
++			#cond, __func__, __FILE__, __LINE__);	\
++		break; \
++	}
++
++#define ASSERT_RETURN(cond)		\
++	ASSERT_RETURN_VAL(cond, TEST_ERR)
++
++#define ASSERT_EXIT(cond)		\
++	ASSERT_EXIT_VAL(cond, EXIT_FAILURE)
++
++int kdbus_test_activator(struct kdbus_test_env *env);
++int kdbus_test_benchmark(struct kdbus_test_env *env);
++int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env);
++int kdbus_test_benchmark_uds(struct kdbus_test_env *env);
++int kdbus_test_bus_make(struct kdbus_test_env *env);
++int kdbus_test_byebye(struct kdbus_test_env *env);
++int kdbus_test_chat(struct kdbus_test_env *env);
++int kdbus_test_conn_info(struct kdbus_test_env *env);
++int kdbus_test_conn_update(struct kdbus_test_env *env);
++int kdbus_test_daemon(struct kdbus_test_env *env);
++int kdbus_test_custom_endpoint(struct kdbus_test_env *env);
++int kdbus_test_fd_passing(struct kdbus_test_env *env);
++int kdbus_test_free(struct kdbus_test_env *env);
++int kdbus_test_hello(struct kdbus_test_env *env);
++int kdbus_test_match_bloom(struct kdbus_test_env *env);
++int kdbus_test_match_id_add(struct kdbus_test_env *env);
++int kdbus_test_match_id_remove(struct kdbus_test_env *env);
++int kdbus_test_match_replace(struct kdbus_test_env *env);
++int kdbus_test_match_name_add(struct kdbus_test_env *env);
++int kdbus_test_match_name_change(struct kdbus_test_env *env);
++int kdbus_test_match_name_remove(struct kdbus_test_env *env);
++int kdbus_test_message_basic(struct kdbus_test_env *env);
++int kdbus_test_message_prio(struct kdbus_test_env *env);
++int kdbus_test_message_quota(struct kdbus_test_env *env);
++int kdbus_test_memory_access(struct kdbus_test_env *env);
++int kdbus_test_metadata_ns(struct kdbus_test_env *env);
++int kdbus_test_monitor(struct kdbus_test_env *env);
++int kdbus_test_name_basic(struct kdbus_test_env *env);
++int kdbus_test_name_conflict(struct kdbus_test_env *env);
++int kdbus_test_name_queue(struct kdbus_test_env *env);
++int kdbus_test_name_takeover(struct kdbus_test_env *env);
++int kdbus_test_policy(struct kdbus_test_env *env);
++int kdbus_test_policy_ns(struct kdbus_test_env *env);
++int kdbus_test_policy_priv(struct kdbus_test_env *env);
++int kdbus_test_sync_byebye(struct kdbus_test_env *env);
++int kdbus_test_sync_reply(struct kdbus_test_env *env);
++int kdbus_test_timeout(struct kdbus_test_env *env);
++int kdbus_test_writable_pool(struct kdbus_test_env *env);
++
++#endif /* _TEST_KDBUS_H_ */
+diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c
+new file mode 100644
+index 0000000..82fa89b
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/kdbus-util.c
+@@ -0,0 +1,1612 @@
++/*
++ * Copyright (C) 2013-2015 Daniel Mack
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2014-2015 Djalal Harouni
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <stdio.h>
++#include <stdarg.h>
++#include <string.h>
++#include <time.h>
++#include <inttypes.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <stdbool.h>
++#include <errno.h>
++#include <assert.h>
++#include <poll.h>
++#include <grp.h>
++#include <sys/capability.h>
++#include <sys/mman.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <linux/unistd.h>
++#include <linux/memfd.h>
++
++#ifndef __NR_memfd_create
++  #ifdef __x86_64__
++    #define __NR_memfd_create 319
++  #elif defined __arm__
++    #define __NR_memfd_create 385
++  #else
++    #define __NR_memfd_create 356
++  #endif
++#endif
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++#ifndef F_ADD_SEALS
++#define F_LINUX_SPECIFIC_BASE	1024
++#define F_ADD_SEALS     (F_LINUX_SPECIFIC_BASE + 9)
++#define F_GET_SEALS     (F_LINUX_SPECIFIC_BASE + 10)
++
++#define F_SEAL_SEAL     0x0001  /* prevent further seals from being set */
++#define F_SEAL_SHRINK   0x0002  /* prevent file from shrinking */
++#define F_SEAL_GROW     0x0004  /* prevent file from growing */
++#define F_SEAL_WRITE    0x0008  /* prevent writes */
++#endif
++
++int kdbus_util_verbose = true;
++
++int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask)
++{
++	int ret;
++	FILE *file;
++	unsigned long long value;
++
++	file = fopen(path, "r");
++	if (!file) {
++		ret = -errno;
++		kdbus_printf("--- error fopen(): %d (%m)\n", ret);
++		return ret;
++	}
++
++	ret = fscanf(file, "%llu", &value);
++	if (ret != 1) {
++		if (ferror(file))
++			ret = -errno;
++		else
++			ret = -EIO;
++
++		kdbus_printf("--- error fscanf(): %d\n", ret);
++		fclose(file);
++		return ret;
++	}
++
++	*mask = (uint64_t)value;
++
++	fclose(file);
++
++	return 0;
++}
++
++int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask)
++{
++	int ret;
++	FILE *file;
++
++	file = fopen(path, "w");
++	if (!file) {
++		ret = -errno;
++		kdbus_printf("--- error open(): %d (%m)\n", ret);
++		return ret;
++	}
++
++	ret = fprintf(file, "%llu", (unsigned long long)mask);
++	if (ret <= 0) {
++		ret = -EIO;
++		kdbus_printf("--- error fprintf(): %d\n", ret);
++	}
++
++	fclose(file);
++
++	return ret > 0 ? 0 : ret;
++}
++
++int kdbus_create_bus(int control_fd, const char *name,
++		     uint64_t owner_meta, char **path)
++{
++	struct {
++		struct kdbus_cmd cmd;
++
++		/* bloom size item */
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_bloom_parameter bloom;
++		} bp;
++
++		/* owner metadata items */
++		struct {
++			uint64_t size;
++			uint64_t type;
++			uint64_t flags;
++		} attach;
++
++		/* name item */
++		struct {
++			uint64_t size;
++			uint64_t type;
++			char str[64];
++		} name;
++	} bus_make;
++	int ret;
++
++	memset(&bus_make, 0, sizeof(bus_make));
++	bus_make.bp.size = sizeof(bus_make.bp);
++	bus_make.bp.type = KDBUS_ITEM_BLOOM_PARAMETER;
++	bus_make.bp.bloom.size = 64;
++	bus_make.bp.bloom.n_hash = 1;
++
++	snprintf(bus_make.name.str, sizeof(bus_make.name.str),
++		 "%u-%s", getuid(), name);
++
++	bus_make.attach.type = KDBUS_ITEM_ATTACH_FLAGS_SEND;
++	bus_make.attach.size = sizeof(bus_make.attach);
++	bus_make.attach.flags = owner_meta;
++
++	bus_make.name.type = KDBUS_ITEM_MAKE_NAME;
++	bus_make.name.size = KDBUS_ITEM_HEADER_SIZE +
++			     strlen(bus_make.name.str) + 1;
++
++	bus_make.cmd.flags = KDBUS_MAKE_ACCESS_WORLD;
++	bus_make.cmd.size = sizeof(bus_make.cmd) +
++			     bus_make.bp.size +
++			     bus_make.attach.size +
++			     bus_make.name.size;
++
++	kdbus_printf("Creating bus with name >%s< on control fd %d ...\n",
++		     name, control_fd);
++
++	ret = kdbus_cmd_bus_make(control_fd, &bus_make.cmd);
++	if (ret < 0) {
++		kdbus_printf("--- error when making bus: %d (%m)\n", ret);
++		return ret;
++	}
++
++	if (ret == 0 && path)
++		*path = strdup(bus_make.name.str);
++
++	return ret;
++}
++
++struct kdbus_conn *
++kdbus_hello(const char *path, uint64_t flags,
++	    const struct kdbus_item *item, size_t item_size)
++{
++	struct kdbus_cmd_free cmd_free = {};
++	int fd, ret;
++	struct {
++		struct kdbus_cmd_hello hello;
++
++		struct {
++			uint64_t size;
++			uint64_t type;
++			char str[16];
++		} conn_name;
++
++		uint8_t extra_items[item_size];
++	} h;
++	struct kdbus_conn *conn;
++
++	memset(&h, 0, sizeof(h));
++
++	if (item_size > 0)
++		memcpy(h.extra_items, item, item_size);
++
++	kdbus_printf("-- opening bus connection %s\n", path);
++	fd = open(path, O_RDWR|O_CLOEXEC);
++	if (fd < 0) {
++		kdbus_printf("--- error %d (%m)\n", fd);
++		return NULL;
++	}
++
++	h.hello.flags = flags | KDBUS_HELLO_ACCEPT_FD;
++	h.hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	h.hello.attach_flags_recv = _KDBUS_ATTACH_ALL;
++	h.conn_name.type = KDBUS_ITEM_CONN_DESCRIPTION;
++	strcpy(h.conn_name.str, "this-is-my-name");
++	h.conn_name.size = KDBUS_ITEM_HEADER_SIZE + strlen(h.conn_name.str) + 1;
++
++	h.hello.size = sizeof(h);
++	h.hello.pool_size = POOL_SIZE;
++
++	ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) &h.hello);
++	if (ret < 0) {
++		kdbus_printf("--- error when saying hello: %d (%m)\n", ret);
++		return NULL;
++	}
++	kdbus_printf("-- Our peer ID for %s: %llu -- bus uuid: '%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n",
++		     path, (unsigned long long)h.hello.id,
++		     h.hello.id128[0],  h.hello.id128[1],  h.hello.id128[2],
++		     h.hello.id128[3],  h.hello.id128[4],  h.hello.id128[5],
++		     h.hello.id128[6],  h.hello.id128[7],  h.hello.id128[8],
++		     h.hello.id128[9],  h.hello.id128[10], h.hello.id128[11],
++		     h.hello.id128[12], h.hello.id128[13], h.hello.id128[14],
++		     h.hello.id128[15]);
++
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.offset = h.hello.offset;
++	kdbus_cmd_free(fd, &cmd_free);
++
++	conn = malloc(sizeof(*conn));
++	if (!conn) {
++		kdbus_printf("unable to malloc()!?\n");
++		return NULL;
++	}
++
++	conn->buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0);
++	if (conn->buf == MAP_FAILED) {
++		free(conn);
++		close(fd);
++		kdbus_printf("--- error mmap (%m)\n");
++		return NULL;
++	}
++
++	conn->fd = fd;
++	conn->id = h.hello.id;
++	return conn;
++}
++
++struct kdbus_conn *
++kdbus_hello_registrar(const char *path, const char *name,
++		      const struct kdbus_policy_access *access,
++		      size_t num_access, uint64_t flags)
++{
++	struct kdbus_item *item, *items;
++	size_t i, size;
++
++	size = KDBUS_ITEM_SIZE(strlen(name) + 1) +
++		num_access * KDBUS_ITEM_SIZE(sizeof(*access));
++
++	items = alloca(size);
++
++	item = items;
++	item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
++	item->type = KDBUS_ITEM_NAME;
++	strcpy(item->str, name);
++	item = KDBUS_ITEM_NEXT(item);
++
++	for (i = 0; i < num_access; i++) {
++		item->size = KDBUS_ITEM_HEADER_SIZE +
++			     sizeof(struct kdbus_policy_access);
++		item->type = KDBUS_ITEM_POLICY_ACCESS;
++
++		item->policy_access.type = access[i].type;
++		item->policy_access.access = access[i].access;
++		item->policy_access.id = access[i].id;
++
++		item = KDBUS_ITEM_NEXT(item);
++	}
++
++	return kdbus_hello(path, flags, items, size);
++}
++
++struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name,
++				   const struct kdbus_policy_access *access,
++				   size_t num_access)
++{
++	return kdbus_hello_registrar(path, name, access, num_access,
++				     KDBUS_HELLO_ACTIVATOR);
++}
++
++bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type)
++{
++	const struct kdbus_item *item;
++
++	KDBUS_ITEM_FOREACH(item, msg, items)
++		if (item->type == type)
++			return true;
++
++	return false;
++}
++
++int kdbus_bus_creator_info(struct kdbus_conn *conn,
++			   uint64_t flags,
++			   uint64_t *offset)
++{
++	struct kdbus_cmd_info *cmd;
++	size_t size = sizeof(*cmd);
++	int ret;
++
++	cmd = alloca(size);
++	memset(cmd, 0, size);
++	cmd->size = size;
++	cmd->attach_flags = flags;
++
++	ret = kdbus_cmd_bus_creator_info(conn->fd, cmd);
++	if (ret < 0) {
++		kdbus_printf("--- error when requesting info: %d (%m)\n", ret);
++		return ret;
++	}
++
++	if (offset)
++		*offset = cmd->offset;
++	else
++		kdbus_free(conn, cmd->offset);
++
++	return 0;
++}
++
++int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id,
++		    const char *name, uint64_t flags,
++		    uint64_t *offset)
++{
++	struct kdbus_cmd_info *cmd;
++	size_t size = sizeof(*cmd);
++	struct kdbus_info *info;
++	int ret;
++
++	if (name)
++		size += KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
++
++	cmd = alloca(size);
++	memset(cmd, 0, size);
++	cmd->size = size;
++	cmd->attach_flags = flags;
++
++	if (name) {
++		cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
++		cmd->items[0].type = KDBUS_ITEM_NAME;
++		strcpy(cmd->items[0].str, name);
++	} else {
++		cmd->id = id;
++	}
++
++	ret = kdbus_cmd_conn_info(conn->fd, cmd);
++	if (ret < 0) {
++		kdbus_printf("--- error when requesting info: %d (%m)\n", ret);
++		return ret;
++	}
++
++	info = (struct kdbus_info *) (conn->buf + cmd->offset);
++	if (info->size != cmd->info_size) {
++		kdbus_printf("%s(): size mismatch: %d != %d\n", __func__,
++				(int) info->size, (int) cmd->info_size);
++		return -EIO;
++	}
++
++	if (offset)
++		*offset = cmd->offset;
++	else
++		kdbus_free(conn, cmd->offset);
++
++	return 0;
++}
++
++void kdbus_conn_free(struct kdbus_conn *conn)
++{
++	if (!conn)
++		return;
++
++	if (conn->buf)
++		munmap(conn->buf, POOL_SIZE);
++
++	if (conn->fd >= 0)
++		close(conn->fd);
++
++	free(conn);
++}
++
++int sys_memfd_create(const char *name, __u64 size)
++{
++	int ret, fd;
++
++	fd = syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING);
++	if (fd < 0)
++		return fd;
++
++	ret = ftruncate(fd, size);
++	if (ret < 0) {
++		close(fd);
++		return ret;
++	}
++
++	return fd;
++}
++
++int sys_memfd_seal_set(int fd)
++{
++	return fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK |
++			 F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
++}
++
++off_t sys_memfd_get_size(int fd, off_t *size)
++{
++	struct stat stat;
++	int ret;
++
++	ret = fstat(fd, &stat);
++	if (ret < 0) {
++		kdbus_printf("stat() failed: %m\n");
++		return ret;
++	}
++
++	*size = stat.st_size;
++	return 0;
++}
++
++static 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,
++			    uint64_t cmd_flags,
++			    int cancel_fd)
++{
++	struct kdbus_cmd_send *cmd = NULL;
++	struct kdbus_msg *msg = NULL;
++	const char ref1[1024 * 128 + 3] = "0123456789_0";
++	const char ref2[] = "0123456789_1";
++	struct kdbus_item *item;
++	struct timespec now;
++	uint64_t size;
++	int memfd = -1;
++	int ret;
++
++	size = sizeof(*msg) + 3 * 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");
++			goto out;
++		}
++
++		ret = sys_memfd_seal_set(memfd);
++		if (ret < 0) {
++			ret = -errno;
++			kdbus_printf("memfd sealing failed: %m\n");
++			goto out;
++		}
++
++		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");
++		goto out;
++	}
++
++	if (dst_id == KDBUS_DST_ID_BROADCAST)
++		flags |= KDBUS_MSG_SIGNAL;
++
++	memset(msg, 0, size);
++	msg->flags = flags;
++	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;
++
++	if (timeout) {
++		ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
++		if (ret < 0)
++			goto out;
++
++		msg->timeout_ns = now.tv_sec * 1000000000ULL +
++				  now.tv_nsec + timeout;
++	}
++
++	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);
++
++	size = sizeof(*cmd);
++	if (cancel_fd != -1)
++		size += KDBUS_ITEM_SIZE(sizeof(cancel_fd));
++
++	cmd = malloc(size);
++	if (!cmd) {
++		ret = -errno;
++		kdbus_printf("unable to malloc()!?\n");
++		goto out;
++	}
++
++	cmd->size = size;
++	cmd->flags = cmd_flags;
++	cmd->msg_address = (uintptr_t)msg;
++
++	item = cmd->items;
++
++	if (cancel_fd != -1) {
++		item->type = KDBUS_ITEM_CANCEL_FD;
++		item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(cancel_fd);
++		item->fds[0] = cancel_fd;
++		item = KDBUS_ITEM_NEXT(item);
++	}
++
++	ret = kdbus_cmd_send(conn->fd, cmd);
++	if (ret < 0) {
++		kdbus_printf("error sending message: %d (%m)\n", ret);
++		goto out;
++	}
++
++	if (cmd_flags & KDBUS_SEND_SYNC_REPLY) {
++		struct kdbus_msg *reply;
++
++		kdbus_printf("SYNC REPLY @offset %llu:\n", cmd->reply.offset);
++		reply = (struct kdbus_msg *)(conn->buf + cmd->reply.offset);
++		kdbus_msg_dump(conn, reply);
++
++		kdbus_msg_free(reply);
++
++		ret = kdbus_free(conn, cmd->reply.offset);
++		if (ret < 0)
++			goto out;
++	}
++
++out:
++	free(msg);
++	free(cmd);
++
++	if (memfd >= 0)
++		close(memfd);
++
++	return ret < 0 ? ret : 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)
++{
++	return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority,
++				dst_id, 0, -1);
++}
++
++int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name,
++			uint64_t cookie, uint64_t flags, uint64_t timeout,
++			int64_t priority, uint64_t dst_id, int cancel_fd)
++{
++	return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority,
++				dst_id, KDBUS_SEND_SYNC_REPLY, cancel_fd);
++}
++
++int kdbus_msg_send_reply(const struct kdbus_conn *conn,
++			 uint64_t reply_cookie,
++			 uint64_t dst_id)
++{
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_msg *msg;
++	const char ref1[1024 * 128 + 3] = "0123456789_0";
++	struct kdbus_item *item;
++	uint64_t size;
++	int ret;
++
++	size = sizeof(struct kdbus_msg);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
++
++	msg = malloc(size);
++	if (!msg) {
++		kdbus_printf("unable to malloc()!?\n");
++		return -ENOMEM;
++	}
++
++	memset(msg, 0, size);
++	msg->size = size;
++	msg->src_id = conn->id;
++	msg->dst_id = dst_id;
++	msg->cookie_reply = reply_cookie;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++
++	item = msg->items;
++
++	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);
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	ret = kdbus_cmd_send(conn->fd, &cmd);
++	if (ret < 0)
++		kdbus_printf("error sending message: %d (%m)\n", ret);
++
++	free(msg);
++
++	return ret;
++}
++
++static char *msg_id(uint64_t id, char *buf)
++{
++	if (id == 0)
++		return "KERNEL";
++	if (id == ~0ULL)
++		return "BROADCAST";
++	sprintf(buf, "%llu", (unsigned long long)id);
++	return buf;
++}
++
++int kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg)
++{
++	const struct kdbus_item *item = msg->items;
++	char buf_src[32];
++	char buf_dst[32];
++	uint64_t timeout = 0;
++	uint64_t cookie_reply = 0;
++	int ret = 0;
++
++	if (msg->flags & KDBUS_MSG_EXPECT_REPLY)
++		timeout = msg->timeout_ns;
++	else
++		cookie_reply = msg->cookie_reply;
++
++	kdbus_printf("MESSAGE: %s (%llu bytes) flags=0x%08llx, %s → %s, "
++		     "cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n",
++		enum_PAYLOAD(msg->payload_type), (unsigned long long)msg->size,
++		(unsigned long long)msg->flags,
++		msg_id(msg->src_id, buf_src), msg_id(msg->dst_id, buf_dst),
++		(unsigned long long)msg->cookie, (unsigned long long)timeout,
++		(unsigned long long)cookie_reply, (long long)msg->priority);
++
++	KDBUS_ITEM_FOREACH(item, msg, items) {
++		if (item->size < KDBUS_ITEM_HEADER_SIZE) {
++			kdbus_printf("  +%s (%llu bytes) invalid data record\n",
++				     enum_MSG(item->type), item->size);
++			ret = -EINVAL;
++			break;
++		}
++
++		switch (item->type) {
++		case KDBUS_ITEM_PAYLOAD_OFF: {
++			char *s;
++
++			if (item->vec.offset == ~0ULL)
++				s = "[\\0-bytes]";
++			else
++				s = (char *)msg + item->vec.offset;
++
++			kdbus_printf("  +%s (%llu bytes) off=%llu size=%llu '%s'\n",
++			       enum_MSG(item->type), item->size,
++			       (unsigned long long)item->vec.offset,
++			       (unsigned long long)item->vec.size, s);
++			break;
++		}
++
++		case KDBUS_ITEM_FDS: {
++			int i, n = (item->size - KDBUS_ITEM_HEADER_SIZE) /
++					sizeof(int);
++
++			kdbus_printf("  +%s (%llu bytes, %d fds)\n",
++			       enum_MSG(item->type), item->size, n);
++
++			for (i = 0; i < n; i++)
++				kdbus_printf("    fd[%d] = %d\n",
++					     i, item->fds[i]);
++
++			break;
++		}
++
++		case KDBUS_ITEM_PAYLOAD_MEMFD: {
++			char *buf;
++			off_t size;
++
++			buf = mmap(NULL, item->memfd.size, PROT_READ,
++				   MAP_PRIVATE, item->memfd.fd, 0);
++			if (buf == MAP_FAILED) {
++				kdbus_printf("mmap() fd=%i size=%llu failed: %m\n",
++					     item->memfd.fd, item->memfd.size);
++				break;
++			}
++
++			if (sys_memfd_get_size(item->memfd.fd, &size) < 0) {
++				kdbus_printf("KDBUS_CMD_MEMFD_SIZE_GET failed: %m\n");
++				break;
++			}
++
++			kdbus_printf("  +%s (%llu bytes) fd=%i size=%llu filesize=%llu '%s'\n",
++			       enum_MSG(item->type), item->size, item->memfd.fd,
++			       (unsigned long long)item->memfd.size,
++			       (unsigned long long)size, buf);
++			munmap(buf, item->memfd.size);
++			break;
++		}
++
++		case KDBUS_ITEM_CREDS:
++			kdbus_printf("  +%s (%llu bytes) uid=%lld, euid=%lld, suid=%lld, fsuid=%lld, "
++							"gid=%lld, egid=%lld, sgid=%lld, fsgid=%lld\n",
++				enum_MSG(item->type), item->size,
++				item->creds.uid, item->creds.euid,
++				item->creds.suid, item->creds.fsuid,
++				item->creds.gid, item->creds.egid,
++				item->creds.sgid, item->creds.fsgid);
++			break;
++
++		case KDBUS_ITEM_PIDS:
++			kdbus_printf("  +%s (%llu bytes) pid=%lld, tid=%lld, ppid=%lld\n",
++				enum_MSG(item->type), item->size,
++				item->pids.pid, item->pids.tid,
++				item->pids.ppid);
++			break;
++
++		case KDBUS_ITEM_AUXGROUPS: {
++			int i, n;
++
++			kdbus_printf("  +%s (%llu bytes)\n",
++				     enum_MSG(item->type), item->size);
++			n = (item->size - KDBUS_ITEM_HEADER_SIZE) /
++				sizeof(uint64_t);
++
++			for (i = 0; i < n; i++)
++				kdbus_printf("    gid[%d] = %lld\n",
++					     i, item->data64[i]);
++			break;
++		}
++
++		case KDBUS_ITEM_NAME:
++		case KDBUS_ITEM_PID_COMM:
++		case KDBUS_ITEM_TID_COMM:
++		case KDBUS_ITEM_EXE:
++		case KDBUS_ITEM_CGROUP:
++		case KDBUS_ITEM_SECLABEL:
++		case KDBUS_ITEM_DST_NAME:
++		case KDBUS_ITEM_CONN_DESCRIPTION:
++			kdbus_printf("  +%s (%llu bytes) '%s' (%zu)\n",
++				     enum_MSG(item->type), item->size,
++				     item->str, strlen(item->str));
++			break;
++
++		case KDBUS_ITEM_OWNED_NAME: {
++			kdbus_printf("  +%s (%llu bytes) '%s' (%zu) flags=0x%08llx\n",
++				     enum_MSG(item->type), item->size,
++				     item->name.name, strlen(item->name.name),
++				     item->name.flags);
++			break;
++		}
++
++		case KDBUS_ITEM_CMDLINE: {
++			size_t size = item->size - KDBUS_ITEM_HEADER_SIZE;
++			const char *str = item->str;
++			int count = 0;
++
++			kdbus_printf("  +%s (%llu bytes) ",
++				     enum_MSG(item->type), item->size);
++			while (size) {
++				kdbus_printf("'%s' ", str);
++				size -= strlen(str) + 1;
++				str += strlen(str) + 1;
++				count++;
++			}
++
++			kdbus_printf("(%d string%s)\n",
++				     count, (count == 1) ? "" : "s");
++			break;
++		}
++
++		case KDBUS_ITEM_AUDIT:
++			kdbus_printf("  +%s (%llu bytes) loginuid=%u sessionid=%u\n",
++			       enum_MSG(item->type), item->size,
++			       item->audit.loginuid, item->audit.sessionid);
++			break;
++
++		case KDBUS_ITEM_CAPS: {
++			const uint32_t *cap;
++			int n, i;
++
++			kdbus_printf("  +%s (%llu bytes) len=%llu bytes, last_cap %d\n",
++				     enum_MSG(item->type), item->size,
++				     (unsigned long long)item->size -
++					KDBUS_ITEM_HEADER_SIZE,
++				     (int) item->caps.last_cap);
++
++			cap = item->caps.caps;
++			n = (item->size - offsetof(struct kdbus_item, caps.caps))
++				/ 4 / sizeof(uint32_t);
++
++			kdbus_printf("    CapInh=");
++			for (i = 0; i < n; i++)
++				kdbus_printf("%08x", cap[(0 * n) + (n - i - 1)]);
++
++			kdbus_printf(" CapPrm=");
++			for (i = 0; i < n; i++)
++				kdbus_printf("%08x", cap[(1 * n) + (n - i - 1)]);
++
++			kdbus_printf(" CapEff=");
++			for (i = 0; i < n; i++)
++				kdbus_printf("%08x", cap[(2 * n) + (n - i - 1)]);
++
++			kdbus_printf(" CapBnd=");
++			for (i = 0; i < n; i++)
++				kdbus_printf("%08x", cap[(3 * n) + (n - i - 1)]);
++			kdbus_printf("\n");
++			break;
++		}
++
++		case KDBUS_ITEM_TIMESTAMP:
++			kdbus_printf("  +%s (%llu bytes) seq=%llu realtime=%lluns monotonic=%lluns\n",
++			       enum_MSG(item->type), item->size,
++			       (unsigned long long)item->timestamp.seqnum,
++			       (unsigned long long)item->timestamp.realtime_ns,
++			       (unsigned long long)item->timestamp.monotonic_ns);
++			break;
++
++		case KDBUS_ITEM_REPLY_TIMEOUT:
++			kdbus_printf("  +%s (%llu bytes) cookie=%llu\n",
++			       enum_MSG(item->type), item->size,
++			       msg->cookie_reply);
++			break;
++
++		case KDBUS_ITEM_NAME_ADD:
++		case KDBUS_ITEM_NAME_REMOVE:
++		case KDBUS_ITEM_NAME_CHANGE:
++			kdbus_printf("  +%s (%llu bytes) '%s', old id=%lld, now id=%lld, old_flags=0x%llx new_flags=0x%llx\n",
++				enum_MSG(item->type),
++				(unsigned long long) item->size,
++				item->name_change.name,
++				item->name_change.old_id.id,
++				item->name_change.new_id.id,
++				item->name_change.old_id.flags,
++				item->name_change.new_id.flags);
++			break;
++
++		case KDBUS_ITEM_ID_ADD:
++		case KDBUS_ITEM_ID_REMOVE:
++			kdbus_printf("  +%s (%llu bytes) id=%llu flags=%llu\n",
++			       enum_MSG(item->type),
++			       (unsigned long long) item->size,
++			       (unsigned long long) item->id_change.id,
++			       (unsigned long long) item->id_change.flags);
++			break;
++
++		default:
++			kdbus_printf("  +%s (%llu bytes)\n",
++				     enum_MSG(item->type), item->size);
++			break;
++		}
++	}
++
++	if ((char *)item - ((char *)msg + msg->size) >= 8) {
++		kdbus_printf("invalid padding at end of message\n");
++		ret = -EINVAL;
++	}
++
++	kdbus_printf("\n");
++
++	return ret;
++}
++
++void kdbus_msg_free(struct kdbus_msg *msg)
++{
++	const struct kdbus_item *item;
++	int nfds, i;
++
++	if (!msg)
++		return;
++
++	KDBUS_ITEM_FOREACH(item, msg, items) {
++		switch (item->type) {
++		/* close all memfds */
++		case KDBUS_ITEM_PAYLOAD_MEMFD:
++			close(item->memfd.fd);
++			break;
++		case KDBUS_ITEM_FDS:
++			nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) /
++				sizeof(int);
++
++			for (i = 0; i < nfds; i++)
++				close(item->fds[i]);
++
++			break;
++		}
++	}
++}
++
++int kdbus_msg_recv(struct kdbus_conn *conn,
++		   struct kdbus_msg **msg_out,
++		   uint64_t *offset)
++{
++	struct kdbus_cmd_recv recv = { .size = sizeof(recv) };
++	struct kdbus_msg *msg;
++	int ret;
++
++	ret = kdbus_cmd_recv(conn->fd, &recv);
++	if (ret < 0)
++		return ret;
++
++	msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset);
++	ret = kdbus_msg_dump(conn, msg);
++	if (ret < 0) {
++		kdbus_msg_free(msg);
++		return ret;
++	}
++
++	if (msg_out) {
++		*msg_out = msg;
++
++		if (offset)
++			*offset = recv.msg.offset;
++	} else {
++		kdbus_msg_free(msg);
++
++		ret = kdbus_free(conn, recv.msg.offset);
++		if (ret < 0)
++			return ret;
++	}
++
++	return 0;
++}
++
++/*
++ * Returns: 0 on success, negative errno on failure.
++ *
++ * We must return -ETIMEDOUT, -ECONNREST, -EAGAIN and other errors.
++ * We must return the result of kdbus_msg_recv()
++ */
++int kdbus_msg_recv_poll(struct kdbus_conn *conn,
++			int timeout_ms,
++			struct kdbus_msg **msg_out,
++			uint64_t *offset)
++{
++	int ret;
++
++	do {
++		struct timeval before, after, diff;
++		struct pollfd fd;
++
++		fd.fd = conn->fd;
++		fd.events = POLLIN | POLLPRI | POLLHUP;
++		fd.revents = 0;
++
++		gettimeofday(&before, NULL);
++		ret = poll(&fd, 1, timeout_ms);
++		gettimeofday(&after, NULL);
++
++		if (ret == 0) {
++			ret = -ETIMEDOUT;
++			break;
++		}
++
++		if (ret > 0) {
++			if (fd.revents & POLLIN)
++				ret = kdbus_msg_recv(conn, msg_out, offset);
++
++			if (fd.revents & (POLLHUP | POLLERR))
++				ret = -ECONNRESET;
++		}
++
++		if (ret == 0 || ret != -EAGAIN)
++			break;
++
++		timersub(&after, &before, &diff);
++		timeout_ms -= diff.tv_sec * 1000UL +
++			      diff.tv_usec / 1000UL;
++	} while (timeout_ms > 0);
++
++	return ret;
++}
++
++int kdbus_free(const struct kdbus_conn *conn, uint64_t offset)
++{
++	struct kdbus_cmd_free cmd_free = {};
++	int ret;
++
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.offset = offset;
++	cmd_free.flags = 0;
++
++	ret = kdbus_cmd_free(conn->fd, &cmd_free);
++	if (ret < 0) {
++		kdbus_printf("KDBUS_CMD_FREE failed: %d (%m)\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++int kdbus_name_acquire(struct kdbus_conn *conn,
++		       const char *name, uint64_t *flags)
++{
++	struct kdbus_cmd *cmd_name;
++	size_t name_len = strlen(name) + 1;
++	uint64_t size = sizeof(*cmd_name) + KDBUS_ITEM_SIZE(name_len);
++	struct kdbus_item *item;
++	int ret;
++
++	cmd_name = alloca(size);
++
++	memset(cmd_name, 0, size);
++
++	item = cmd_name->items;
++	item->size = KDBUS_ITEM_HEADER_SIZE + name_len;
++	item->type = KDBUS_ITEM_NAME;
++	strcpy(item->str, name);
++
++	cmd_name->size = size;
++	if (flags)
++		cmd_name->flags = *flags;
++
++	ret = kdbus_cmd_name_acquire(conn->fd, cmd_name);
++	if (ret < 0) {
++		kdbus_printf("error aquiring name: %s\n", strerror(-ret));
++		return ret;
++	}
++
++	kdbus_printf("%s(): flags after call: 0x%llx\n", __func__,
++		     cmd_name->return_flags);
++
++	if (flags)
++		*flags = cmd_name->return_flags;
++
++	return 0;
++}
++
++int kdbus_name_release(struct kdbus_conn *conn, const char *name)
++{
++	struct kdbus_cmd *cmd_name;
++	size_t name_len = strlen(name) + 1;
++	uint64_t size = sizeof(*cmd_name) + KDBUS_ITEM_SIZE(name_len);
++	struct kdbus_item *item;
++	int ret;
++
++	cmd_name = alloca(size);
++
++	memset(cmd_name, 0, size);
++
++	item = cmd_name->items;
++	item->size = KDBUS_ITEM_HEADER_SIZE + name_len;
++	item->type = KDBUS_ITEM_NAME;
++	strcpy(item->str, name);
++
++	cmd_name->size = size;
++
++	kdbus_printf("conn %lld giving up name '%s'\n",
++		     (unsigned long long) conn->id, name);
++
++	ret = kdbus_cmd_name_release(conn->fd, cmd_name);
++	if (ret < 0) {
++		kdbus_printf("error releasing name: %s\n", strerror(-ret));
++		return ret;
++	}
++
++	return 0;
++}
++
++int kdbus_list(struct kdbus_conn *conn, uint64_t flags)
++{
++	struct kdbus_cmd_list cmd_list = {};
++	struct kdbus_info *list, *name;
++	int ret;
++
++	cmd_list.size = sizeof(cmd_list);
++	cmd_list.flags = flags;
++
++	ret = kdbus_cmd_list(conn->fd, &cmd_list);
++	if (ret < 0) {
++		kdbus_printf("error listing names: %d (%m)\n", ret);
++		return ret;
++	}
++
++	kdbus_printf("REGISTRY:\n");
++	list = (struct kdbus_info *)(conn->buf + cmd_list.offset);
++
++	KDBUS_FOREACH(name, list, cmd_list.list_size) {
++		uint64_t flags = 0;
++		struct kdbus_item *item;
++		const char *n = "MISSING-NAME";
++
++		if (name->size == sizeof(struct kdbus_cmd))
++			continue;
++
++		KDBUS_ITEM_FOREACH(item, name, items)
++			if (item->type == KDBUS_ITEM_OWNED_NAME) {
++				n = item->name.name;
++				flags = item->name.flags;
++
++				kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n",
++					     name->id,
++					     (unsigned long long) flags,
++					     name->flags, n);
++			}
++	}
++	kdbus_printf("\n");
++
++	ret = kdbus_free(conn, cmd_list.offset);
++
++	return ret;
++}
++
++int kdbus_conn_update_attach_flags(struct kdbus_conn *conn,
++				   uint64_t attach_flags_send,
++				   uint64_t attach_flags_recv)
++{
++	int ret;
++	size_t size;
++	struct kdbus_cmd *update;
++	struct kdbus_item *item;
++
++	size = sizeof(struct kdbus_cmd);
++	size += KDBUS_ITEM_SIZE(sizeof(uint64_t)) * 2;
++
++	update = malloc(size);
++	if (!update) {
++		kdbus_printf("error malloc: %m\n");
++		return -ENOMEM;
++	}
++
++	memset(update, 0, size);
++	update->size = size;
++
++	item = update->items;
++
++	item->type = KDBUS_ITEM_ATTACH_FLAGS_SEND;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t);
++	item->data64[0] = attach_flags_send;
++	item = KDBUS_ITEM_NEXT(item);
++
++	item->type = KDBUS_ITEM_ATTACH_FLAGS_RECV;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t);
++	item->data64[0] = attach_flags_recv;
++	item = KDBUS_ITEM_NEXT(item);
++
++	ret = kdbus_cmd_update(conn->fd, update);
++	if (ret < 0)
++		kdbus_printf("error conn update: %d (%m)\n", ret);
++
++	free(update);
++
++	return ret;
++}
++
++int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name,
++			     const struct kdbus_policy_access *access,
++			     size_t num_access)
++{
++	struct kdbus_cmd *update;
++	struct kdbus_item *item;
++	size_t i, size;
++	int ret;
++
++	size = sizeof(struct kdbus_cmd);
++	size += KDBUS_ITEM_SIZE(strlen(name) + 1);
++	size += num_access * KDBUS_ITEM_SIZE(sizeof(struct kdbus_policy_access));
++
++	update = malloc(size);
++	if (!update) {
++		kdbus_printf("error malloc: %m\n");
++		return -ENOMEM;
++	}
++
++	memset(update, 0, size);
++	update->size = size;
++
++	item = update->items;
++
++	item->type = KDBUS_ITEM_NAME;
++	item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
++	strcpy(item->str, name);
++	item = KDBUS_ITEM_NEXT(item);
++
++	for (i = 0; i < num_access; i++) {
++		item->size = KDBUS_ITEM_HEADER_SIZE +
++			     sizeof(struct kdbus_policy_access);
++		item->type = KDBUS_ITEM_POLICY_ACCESS;
++
++		item->policy_access.type = access[i].type;
++		item->policy_access.access = access[i].access;
++		item->policy_access.id = access[i].id;
++
++		item = KDBUS_ITEM_NEXT(item);
++	}
++
++	ret = kdbus_cmd_update(conn->fd, update);
++	if (ret < 0)
++		kdbus_printf("error conn update: %d (%m)\n", ret);
++
++	free(update);
++
++	return ret;
++}
++
++int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie,
++		       uint64_t type, uint64_t id)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_id_change chg;
++		} item;
++	} buf;
++	int ret;
++
++	memset(&buf, 0, sizeof(buf));
++
++	buf.cmd.size = sizeof(buf);
++	buf.cmd.cookie = cookie;
++	buf.item.size = sizeof(buf.item);
++	buf.item.type = type;
++	buf.item.chg.id = id;
++
++	ret = kdbus_cmd_match_add(conn->fd, &buf.cmd);
++	if (ret < 0)
++		kdbus_printf("--- error adding conn match: %d (%m)\n", ret);
++
++	return ret;
++}
++
++int kdbus_add_match_empty(struct kdbus_conn *conn)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct kdbus_item item;
++	} buf;
++	int ret;
++
++	memset(&buf, 0, sizeof(buf));
++
++	buf.item.size = sizeof(uint64_t) * 3;
++	buf.item.type = KDBUS_ITEM_ID;
++	buf.item.id = KDBUS_MATCH_ID_ANY;
++
++	buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
++
++	ret = kdbus_cmd_match_add(conn->fd, &buf.cmd);
++	if (ret < 0)
++		kdbus_printf("--- error adding conn match: %d (%m)\n", ret);
++
++	return ret;
++}
++
++static int all_ids_are_mapped(const char *path)
++{
++	int ret;
++	FILE *file;
++	uint32_t inside_id, length;
++
++	file = fopen(path, "r");
++	if (!file) {
++		ret = -errno;
++		kdbus_printf("error fopen() %s: %d (%m)\n",
++			     path, ret);
++		return ret;
++	}
++
++	ret = fscanf(file, "%u\t%*u\t%u", &inside_id, &length);
++	if (ret != 2) {
++		if (ferror(file))
++			ret = -errno;
++		else
++			ret = -EIO;
++
++		kdbus_printf("--- error fscanf(): %d\n", ret);
++		fclose(file);
++		return ret;
++	}
++
++	fclose(file);
++
++	/*
++	 * If length is 4294967295 which means the invalid uid
++	 * (uid_t) -1 then we are able to map all uid/gids
++	 */
++	if (inside_id == 0 && length == (uid_t) -1)
++		return 1;
++
++	return 0;
++}
++
++int all_uids_gids_are_mapped(void)
++{
++	int ret;
++
++	ret = all_ids_are_mapped("/proc/self/uid_map");
++	if (ret <= 0) {
++		kdbus_printf("--- error not all uids are mapped\n");
++		return 0;
++	}
++
++	ret = all_ids_are_mapped("/proc/self/gid_map");
++	if (ret <= 0) {
++		kdbus_printf("--- error not all gids are mapped\n");
++		return 0;
++	}
++
++	return 1;
++}
++
++int drop_privileges(uid_t uid, gid_t gid)
++{
++	int ret;
++
++	ret = setgroups(0, NULL);
++	if (ret < 0) {
++		ret = -errno;
++		kdbus_printf("error setgroups: %d (%m)\n", ret);
++		return ret;
++	}
++
++	ret = setresgid(gid, gid, gid);
++	if (ret < 0) {
++		ret = -errno;
++		kdbus_printf("error setresgid: %d (%m)\n", ret);
++		return ret;
++	}
++
++	ret = setresuid(uid, uid, uid);
++	if (ret < 0) {
++		ret = -errno;
++		kdbus_printf("error setresuid: %d (%m)\n", ret);
++		return ret;
++	}
++
++	return ret;
++}
++
++uint64_t now(clockid_t clock)
++{
++	struct timespec spec;
++
++	clock_gettime(clock, &spec);
++	return spec.tv_sec * 1000ULL * 1000ULL * 1000ULL + spec.tv_nsec;
++}
++
++char *unique_name(const char *prefix)
++{
++	unsigned int i;
++	uint64_t u_now;
++	char n[17];
++	char *str;
++	int r;
++
++	/*
++	 * This returns a random string which is guaranteed to be
++	 * globally unique across all calls to unique_name(). We
++	 * compose the string as:
++	 *   <prefix>-<random>-<time>
++	 * With:
++	 *   <prefix>: string provided by the caller
++	 *   <random>: a random alpha string of 16 characters
++	 *   <time>: the current time in micro-seconds since last boot
++	 *
++	 * The <random> part makes the string always look vastly different,
++	 * the <time> part makes sure no two calls return the same string.
++	 */
++
++	u_now = now(CLOCK_MONOTONIC);
++
++	for (i = 0; i < sizeof(n) - 1; ++i)
++		n[i] = 'a' + (rand() % ('z' - 'a'));
++	n[sizeof(n) - 1] = 0;
++
++	r = asprintf(&str, "%s-%s-%" PRIu64, prefix, n, u_now);
++	if (r < 0)
++		return NULL;
++
++	return str;
++}
++
++static int do_userns_map_id(pid_t pid,
++			    const char *map_file,
++			    const char *map_id)
++{
++	int ret;
++	int fd;
++	char *map;
++	unsigned int i;
++
++	map = strndupa(map_id, strlen(map_id));
++	if (!map) {
++		ret = -errno;
++		kdbus_printf("error strndupa %s: %d (%m)\n",
++			map_file, ret);
++		return ret;
++	}
++
++	for (i = 0; i < strlen(map); i++)
++		if (map[i] == ',')
++			map[i] = '\n';
++
++	fd = open(map_file, O_RDWR);
++	if (fd < 0) {
++		ret = -errno;
++		kdbus_printf("error open %s: %d (%m)\n",
++			map_file, ret);
++		return ret;
++	}
++
++	ret = write(fd, map, strlen(map));
++	if (ret < 0) {
++		ret = -errno;
++		kdbus_printf("error write to %s: %d (%m)\n",
++			     map_file, ret);
++		goto out;
++	}
++
++	ret = 0;
++
++out:
++	close(fd);
++	return ret;
++}
++
++int userns_map_uid_gid(pid_t pid,
++		       const char *map_uid,
++		       const char *map_gid)
++{
++	int fd, ret;
++	char file_id[128] = {'\0'};
++
++	snprintf(file_id, sizeof(file_id), "/proc/%ld/uid_map",
++		 (long) pid);
++
++	ret = do_userns_map_id(pid, file_id, map_uid);
++	if (ret < 0)
++		return ret;
++
++	snprintf(file_id, sizeof(file_id), "/proc/%ld/setgroups",
++		 (long) pid);
++
++	fd = open(file_id, O_WRONLY);
++	if (fd >= 0) {
++		write(fd, "deny\n", 5);
++		close(fd);
++	}
++
++	snprintf(file_id, sizeof(file_id), "/proc/%ld/gid_map",
++		 (long) pid);
++
++	return do_userns_map_id(pid, file_id, map_gid);
++}
++
++static int do_cap_get_flag(cap_t caps, cap_value_t cap)
++{
++	int ret;
++	cap_flag_value_t flag_set;
++
++	ret = cap_get_flag(caps, cap, CAP_EFFECTIVE, &flag_set);
++	if (ret < 0) {
++		ret = -errno;
++		kdbus_printf("error cap_get_flag(): %d (%m)\n", ret);
++		return ret;
++	}
++
++	return (flag_set == CAP_SET);
++}
++
++/*
++ * Returns:
++ *  1 in case all the requested effective capabilities are set.
++ *  0 in case we do not have the requested capabilities. This value
++ *    will be used to abort tests with TEST_SKIP
++ *  Negative errno on failure.
++ *
++ *  Terminate args with a negative value.
++ */
++int test_is_capable(int cap, ...)
++{
++	int ret;
++	va_list ap;
++	cap_t caps;
++
++	caps = cap_get_proc();
++	if (!caps) {
++		ret = -errno;
++		kdbus_printf("error cap_get_proc(): %d (%m)\n", ret);
++		return ret;
++	}
++
++	ret = do_cap_get_flag(caps, (cap_value_t)cap);
++	if (ret <= 0)
++		goto out;
++
++	va_start(ap, cap);
++	while ((cap = va_arg(ap, int)) > 0) {
++		ret = do_cap_get_flag(caps, (cap_value_t)cap);
++		if (ret <= 0)
++			break;
++	}
++	va_end(ap);
++
++out:
++	cap_free(caps);
++	return ret;
++}
++
++int config_user_ns_is_enabled(void)
++{
++	return (access("/proc/self/uid_map", F_OK) == 0);
++}
++
++int config_auditsyscall_is_enabled(void)
++{
++	return (access("/proc/self/loginuid", F_OK) == 0);
++}
++
++int config_cgroups_is_enabled(void)
++{
++	return (access("/proc/self/cgroup", F_OK) == 0);
++}
++
++int config_security_is_enabled(void)
++{
++	int fd;
++	int ret;
++	char buf[128];
++
++	/* CONFIG_SECURITY is disabled */
++	if (access("/proc/self/attr/current", F_OK) != 0)
++		return 0;
++
++	/*
++	 * Now only if read() fails with -EINVAL then we assume
++	 * that SECLABEL and LSM are disabled
++	 */
++	fd = open("/proc/self/attr/current", O_RDONLY|O_CLOEXEC);
++	if (fd < 0)
++		return 1;
++
++	ret = read(fd, buf, sizeof(buf));
++	if (ret == -1 && errno == EINVAL)
++		ret = 0;
++	else
++		ret = 1;
++
++	close(fd);
++
++	return ret;
++}
+diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h
+new file mode 100644
+index 0000000..e1e18b9
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/kdbus-util.h
+@@ -0,0 +1,218 @@
++/*
++ * Copyright (C) 2013-2015 Kay Sievers
++ * Copyright (C) 2013-2015 Daniel Mack
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#pragma once
++
++#define BIT(X) (1 << (X))
++
++#include <time.h>
++#include <stdbool.h>
++#include <linux/kdbus.h>
++
++#define _STRINGIFY(x) #x
++#define STRINGIFY(x) _STRINGIFY(x)
++#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
++
++#define KDBUS_PTR(addr) ((void *)(uintptr_t)(addr))
++
++#define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
++#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
++#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
++
++#define KDBUS_ITEM_NEXT(item) \
++	(typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size))
++#define KDBUS_ITEM_FOREACH(item, head, first)				\
++	for ((item) = (head)->first;					\
++	     ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) &&	\
++	       ((uint8_t *)(item) >= (uint8_t *)(head));		\
++	     (item) = KDBUS_ITEM_NEXT(item))
++#define KDBUS_FOREACH(iter, first, _size)				\
++	for ((iter) = (first);						\
++	     ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) &&	\
++	       ((uint8_t *)(iter) >= (uint8_t *)(first));		\
++	     (iter) = (void *)((uint8_t *)(iter) + KDBUS_ALIGN8((iter)->size)))
++
++#define _KDBUS_ATTACH_BITS_SET_NR (__builtin_popcountll(_KDBUS_ATTACH_ALL))
++
++/* Sum of KDBUS_ITEM_* that reflects _KDBUS_ATTACH_ALL */
++#define KDBUS_ATTACH_ITEMS_TYPE_SUM					\
++	((((_KDBUS_ATTACH_BITS_SET_NR - 1) *				\
++	((_KDBUS_ATTACH_BITS_SET_NR - 1) + 1)) / 2) +			\
++	(_KDBUS_ITEM_ATTACH_BASE * _KDBUS_ATTACH_BITS_SET_NR))
++
++#define POOL_SIZE (16 * 1024LU * 1024LU)
++
++#define UNPRIV_UID 65534
++#define UNPRIV_GID 65534
++
++/* Dump as user of process, useful for user namespace testing */
++#define SUID_DUMP_USER	1
++
++extern int kdbus_util_verbose;
++
++#define kdbus_printf(X...) \
++	if (kdbus_util_verbose) \
++		printf(X)
++
++#define RUN_UNPRIVILEGED(child_uid, child_gid, _child_, _parent_) ({	\
++		pid_t pid, rpid;					\
++		int ret;						\
++									\
++		pid = fork();						\
++		if (pid == 0) {						\
++			ret = drop_privileges(child_uid, child_gid);	\
++			ASSERT_EXIT_VAL(ret == 0, ret);			\
++									\
++			_child_;					\
++			_exit(0);					\
++		} else if (pid > 0) {					\
++			_parent_;					\
++			rpid = waitpid(pid, &ret, 0);			\
++			ASSERT_RETURN(rpid == pid);			\
++			ASSERT_RETURN(WIFEXITED(ret));			\
++			ASSERT_RETURN(WEXITSTATUS(ret) == 0);		\
++			ret = TEST_OK;					\
++		} else {						\
++			ret = pid;					\
++		}							\
++									\
++		ret;							\
++	})
++
++#define RUN_UNPRIVILEGED_CONN(_var_, _bus_, _code_)			\
++	RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({			\
++		struct kdbus_conn *_var_;				\
++		_var_ = kdbus_hello(_bus_, 0, NULL, 0);			\
++		ASSERT_EXIT(_var_);					\
++		_code_;							\
++		kdbus_conn_free(_var_);					\
++	}), ({ 0; }))
++
++#define RUN_CLONE_CHILD(clone_ret, flags, _setup_, _child_body_,	\
++			_parent_setup_, _parent_body_) ({		\
++	pid_t pid, rpid;						\
++	int ret;							\
++	int efd = -1;							\
++									\
++	_setup_;							\
++	efd = eventfd(0, EFD_CLOEXEC);					\
++	ASSERT_RETURN(efd >= 0);					\
++	*(clone_ret) = 0;						\
++	pid = syscall(__NR_clone, flags, NULL);				\
++	if (pid == 0) {							\
++		eventfd_t event_status = 0;				\
++		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);			\
++		ASSERT_EXIT(ret == 0);					\
++		ret = eventfd_read(efd, &event_status);			\
++		if (ret < 0 || event_status != 1) {			\
++			kdbus_printf("error eventfd_read()\n");		\
++			_exit(EXIT_FAILURE);				\
++		}							\
++		_child_body_;						\
++		_exit(0);						\
++	} else if (pid > 0) {						\
++		_parent_setup_;						\
++		ret = eventfd_write(efd, 1);				\
++		ASSERT_RETURN(ret >= 0);				\
++		_parent_body_;						\
++		rpid = waitpid(pid, &ret, 0);				\
++		ASSERT_RETURN(rpid == pid);				\
++		ASSERT_RETURN(WIFEXITED(ret));				\
++		ASSERT_RETURN(WEXITSTATUS(ret) == 0);			\
++		ret = TEST_OK;						\
++	} else {							\
++		ret = -errno;						\
++		*(clone_ret) = -errno;					\
++	}								\
++	close(efd);							\
++	ret;								\
++})
++
++/* Enums for parent if it should drop privs or not */
++enum kdbus_drop_parent {
++	DO_NOT_DROP,
++	DROP_SAME_UNPRIV,
++	DROP_OTHER_UNPRIV,
++};
++
++struct kdbus_conn {
++	int fd;
++	uint64_t id;
++	unsigned char *buf;
++};
++
++int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask);
++int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask);
++
++int sys_memfd_create(const char *name, __u64 size);
++int sys_memfd_seal_set(int fd);
++off_t sys_memfd_get_size(int fd, off_t *size);
++
++int kdbus_list(struct kdbus_conn *conn, uint64_t flags);
++int kdbus_name_release(struct kdbus_conn *conn, const char *name);
++int kdbus_name_acquire(struct kdbus_conn *conn, const char *name,
++		       uint64_t *flags);
++void kdbus_msg_free(struct kdbus_msg *msg);
++int kdbus_msg_recv(struct kdbus_conn *conn,
++		   struct kdbus_msg **msg, uint64_t *offset);
++int kdbus_msg_recv_poll(struct kdbus_conn *conn, int timeout_ms,
++			struct kdbus_msg **msg_out, uint64_t *offset);
++int kdbus_free(const struct kdbus_conn *conn, uint64_t offset);
++int kdbus_msg_dump(const struct kdbus_conn *conn,
++		   const struct kdbus_msg *msg);
++int kdbus_create_bus(int control_fd, const char *name,
++		     uint64_t owner_meta, char **path);
++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);
++int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name,
++			uint64_t cookie, uint64_t flags, uint64_t timeout,
++			int64_t priority, uint64_t dst_id, int cancel_fd);
++int kdbus_msg_send_reply(const struct kdbus_conn *conn,
++			 uint64_t reply_cookie,
++			 uint64_t dst_id);
++struct kdbus_conn *kdbus_hello(const char *path, uint64_t hello_flags,
++			       const struct kdbus_item *item,
++			       size_t item_size);
++struct kdbus_conn *kdbus_hello_registrar(const char *path, const char *name,
++					 const struct kdbus_policy_access *access,
++					 size_t num_access, uint64_t flags);
++struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name,
++					 const struct kdbus_policy_access *access,
++					 size_t num_access);
++bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type);
++int kdbus_bus_creator_info(struct kdbus_conn *conn,
++			   uint64_t flags,
++			   uint64_t *offset);
++int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id,
++		    const char *name, uint64_t flags, uint64_t *offset);
++void kdbus_conn_free(struct kdbus_conn *conn);
++int kdbus_conn_update_attach_flags(struct kdbus_conn *conn,
++				   uint64_t attach_flags_send,
++				   uint64_t attach_flags_recv);
++int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name,
++			     const struct kdbus_policy_access *access,
++			     size_t num_access);
++
++int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie,
++		       uint64_t type, uint64_t id);
++int kdbus_add_match_empty(struct kdbus_conn *conn);
++
++int all_uids_gids_are_mapped(void);
++int drop_privileges(uid_t uid, gid_t gid);
++uint64_t now(clockid_t clock);
++char *unique_name(const char *prefix);
++
++int userns_map_uid_gid(pid_t pid, const char *map_uid, const char *map_gid);
++int test_is_capable(int cap, ...);
++int config_user_ns_is_enabled(void);
++int config_auditsyscall_is_enabled(void);
++int config_cgroups_is_enabled(void);
++int config_security_is_enabled(void);
+diff --git a/tools/testing/selftests/kdbus/test-activator.c b/tools/testing/selftests/kdbus/test-activator.c
+new file mode 100644
+index 0000000..3d1b763
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-activator.c
+@@ -0,0 +1,318 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <poll.h>
++#include <sys/capability.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++static int kdbus_starter_poll(struct kdbus_conn *conn)
++{
++	int ret;
++	struct pollfd fd;
++
++	fd.fd = conn->fd;
++	fd.events = POLLIN | POLLPRI | POLLHUP;
++	fd.revents = 0;
++
++	ret = poll(&fd, 1, 100);
++	if (ret == 0)
++		return -ETIMEDOUT;
++	else if (ret > 0) {
++		if (fd.revents & POLLIN)
++			return 0;
++
++		if (fd.revents & (POLLHUP | POLLERR))
++			ret = -ECONNRESET;
++	}
++
++	return ret;
++}
++
++/* Ensure that kdbus activator logic is safe */
++static int kdbus_priv_activator(struct kdbus_test_env *env)
++{
++	int ret;
++	struct kdbus_msg *msg = NULL;
++	uint64_t cookie = 0xdeadbeef;
++	uint64_t flags = KDBUS_NAME_REPLACE_EXISTING;
++	struct kdbus_conn *activator;
++	struct kdbus_conn *service;
++	struct kdbus_conn *client;
++	struct kdbus_conn *holder;
++	struct kdbus_policy_access *access;
++
++	access = (struct kdbus_policy_access[]){
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = getuid(),
++			.access = KDBUS_POLICY_OWN,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = getuid(),
++			.access = KDBUS_POLICY_TALK,
++		},
++	};
++
++	activator = kdbus_hello_activator(env->buspath, "foo.priv.activator",
++					  access, 2);
++	ASSERT_RETURN(activator);
++
++	service = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(service);
++
++	client = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(client);
++
++	/*
++	 * Make sure that other users can't TALK to the activator
++	 */
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		/* Try to talk using the ID */
++		ret = kdbus_msg_send(unpriv, NULL, 0xdeadbeef, 0, 0,
++				     0, activator->id);
++		ASSERT_EXIT(ret == -ENXIO);
++
++		/* Try to talk to the name */
++		ret = kdbus_msg_send(unpriv, "foo.priv.activator",
++				     0xdeadbeef, 0, 0, 0,
++				     KDBUS_DST_ID_NAME);
++		ASSERT_EXIT(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure that we did not receive anything, so the
++	 * service will not be started automatically
++	 */
++
++	ret = kdbus_starter_poll(activator);
++	ASSERT_RETURN(ret == -ETIMEDOUT);
++
++	/*
++	 * Now try to emulate the starter/service logic and
++	 * acquire the name.
++	 */
++
++	cookie++;
++	ret = kdbus_msg_send(service, "foo.priv.activator", cookie,
++			     0, 0, 0, KDBUS_DST_ID_NAME);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_starter_poll(activator);
++	ASSERT_RETURN(ret == 0);
++
++	/* Policies are still checked, access denied */
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "foo.priv.activator",
++					 &flags);
++		ASSERT_RETURN(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_name_acquire(service, "foo.priv.activator",
++				 &flags);
++	ASSERT_RETURN(ret == 0);
++
++	/* We read our previous starter message */
++
++	ret = kdbus_msg_recv_poll(service, 100, NULL, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* Try to talk, we still fail */
++
++	cookie++;
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		/* Try to talk to the name */
++		ret = kdbus_msg_send(unpriv, "foo.priv.activator",
++				     cookie, 0, 0, 0,
++				     KDBUS_DST_ID_NAME);
++		ASSERT_EXIT(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/* Still nothing to read */
++
++	ret = kdbus_msg_recv_poll(service, 100, NULL, NULL);
++	ASSERT_RETURN(ret == -ETIMEDOUT);
++
++	/* We receive every thing now */
++
++	cookie++;
++	ret = kdbus_msg_send(client, "foo.priv.activator", cookie,
++			     0, 0, 0, KDBUS_DST_ID_NAME);
++	ASSERT_RETURN(ret == 0);
++	ret = kdbus_msg_recv_poll(service, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++
++	/* Policies default to deny TALK now */
++	kdbus_conn_free(activator);
++
++	cookie++;
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		/* Try to talk to the name */
++		ret = kdbus_msg_send(unpriv, "foo.priv.activator",
++				     cookie, 0, 0, 0,
++				     KDBUS_DST_ID_NAME);
++		ASSERT_EXIT(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(service, 100, NULL, NULL);
++	ASSERT_RETURN(ret == -ETIMEDOUT);
++
++	/* Same user is able to TALK */
++	cookie++;
++	ret = kdbus_msg_send(client, "foo.priv.activator", cookie,
++			     0, 0, 0, KDBUS_DST_ID_NAME);
++	ASSERT_RETURN(ret == 0);
++	ret = kdbus_msg_recv_poll(service, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++
++	access = (struct kdbus_policy_access []){
++		{
++			.type = KDBUS_POLICY_ACCESS_WORLD,
++			.id = getuid(),
++			.access = KDBUS_POLICY_TALK,
++		},
++	};
++
++	holder = kdbus_hello_registrar(env->buspath, "foo.priv.activator",
++				       access, 1, KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(holder);
++
++	/* Now we are able to TALK to the name */
++
++	cookie++;
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		/* Try to talk to the name */
++		ret = kdbus_msg_send(unpriv, "foo.priv.activator",
++				     cookie, 0, 0, 0,
++				     KDBUS_DST_ID_NAME);
++		ASSERT_EXIT(ret == 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(service, 100, NULL, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "foo.priv.activator",
++					 &flags);
++		ASSERT_RETURN(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	kdbus_conn_free(service);
++	kdbus_conn_free(client);
++	kdbus_conn_free(holder);
++
++	return 0;
++}
++
++int kdbus_test_activator(struct kdbus_test_env *env)
++{
++	int ret;
++	struct kdbus_conn *activator;
++	struct pollfd fds[2];
++	bool activator_done = false;
++	struct kdbus_policy_access access[2];
++
++	access[0].type = KDBUS_POLICY_ACCESS_USER;
++	access[0].id = getuid();
++	access[0].access = KDBUS_POLICY_OWN;
++
++	access[1].type = KDBUS_POLICY_ACCESS_WORLD;
++	access[1].access = KDBUS_POLICY_TALK;
++
++	activator = kdbus_hello_activator(env->buspath, "foo.test.activator",
++					  access, 2);
++	ASSERT_RETURN(activator);
++
++	ret = kdbus_add_match_empty(env->conn);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_list(env->conn, KDBUS_LIST_NAMES |
++				    KDBUS_LIST_UNIQUE |
++				    KDBUS_LIST_ACTIVATORS |
++				    KDBUS_LIST_QUEUED);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_send(env->conn, "foo.test.activator", 0xdeafbeef,
++			     0, 0, 0, KDBUS_DST_ID_NAME);
++	ASSERT_RETURN(ret == 0);
++
++	fds[0].fd = activator->fd;
++	fds[1].fd = env->conn->fd;
++
++	kdbus_printf("-- entering poll loop ...\n");
++
++	for (;;) {
++		int i, nfds = sizeof(fds) / sizeof(fds[0]);
++
++		for (i = 0; i < nfds; i++) {
++			fds[i].events = POLLIN | POLLPRI;
++			fds[i].revents = 0;
++		}
++
++		ret = poll(fds, nfds, 3000);
++		ASSERT_RETURN(ret >= 0);
++
++		ret = kdbus_list(env->conn, KDBUS_LIST_NAMES);
++		ASSERT_RETURN(ret == 0);
++
++		if ((fds[0].revents & POLLIN) && !activator_done) {
++			uint64_t flags = KDBUS_NAME_REPLACE_EXISTING;
++
++			kdbus_printf("Starter was called back!\n");
++
++			ret = kdbus_name_acquire(env->conn,
++						 "foo.test.activator", &flags);
++			ASSERT_RETURN(ret == 0);
++
++			activator_done = true;
++		}
++
++		if (fds[1].revents & POLLIN) {
++			kdbus_msg_recv(env->conn, NULL, NULL);
++			break;
++		}
++	}
++
++	/* Check if all uids/gids are mapped */
++	if (!all_uids_gids_are_mapped())
++		return TEST_SKIP;
++
++	/* Check now capabilities, so we run the previous tests */
++	ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
++	ASSERT_RETURN(ret >= 0);
++
++	if (!ret)
++		return TEST_SKIP;
++
++	ret = kdbus_priv_activator(env);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_conn_free(activator);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-benchmark.c b/tools/testing/selftests/kdbus/test-benchmark.c
+new file mode 100644
+index 0000000..8a9744b
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-benchmark.c
+@@ -0,0 +1,451 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <locale.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <stdbool.h>
++#include <errno.h>
++#include <assert.h>
++#include <poll.h>
++#include <sys/time.h>
++#include <sys/mman.h>
++#include <sys/socket.h>
++#include <math.h>
++
++#include "kdbus-api.h"
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++#define SERVICE_NAME "foo.bar.echo"
++
++/*
++ * To have a banchmark comparison with unix socket, set:
++ * user_memfd	= false;
++ * compare_uds	= true;
++ * attach_none	= true;		do not attached metadata
++ */
++
++static bool use_memfd = true;		/* transmit memfd? */
++static bool compare_uds = false;		/* unix-socket comparison? */
++static bool attach_none = false;		/* clear attach-flags? */
++static char stress_payload[8192];
++
++struct stats {
++	uint64_t count;
++	uint64_t latency_acc;
++	uint64_t latency_low;
++	uint64_t latency_high;
++	uint64_t latency_avg;
++	uint64_t latency_ssquares;
++};
++
++static struct stats stats;
++
++static void reset_stats(void)
++{
++	stats.count = 0;
++	stats.latency_acc = 0;
++	stats.latency_low = UINT64_MAX;
++	stats.latency_high = 0;
++	stats.latency_avg = 0;
++	stats.latency_ssquares = 0;
++}
++
++static void dump_stats(bool is_uds)
++{
++	if (stats.count > 0) {
++		kdbus_printf("stats %s: %'llu packets processed, latency (nsecs) min/max/avg/dev %'7llu // %'7llu // %'7llu // %'7.f\n",
++			     is_uds ? " (UNIX)" : "(KDBUS)",
++			     (unsigned long long) stats.count,
++			     (unsigned long long) stats.latency_low,
++			     (unsigned long long) stats.latency_high,
++			     (unsigned long long) stats.latency_avg,
++			     sqrt(stats.latency_ssquares / stats.count));
++	} else {
++		kdbus_printf("*** no packets received. bus stuck?\n");
++	}
++}
++
++static void add_stats(uint64_t prev)
++{
++	uint64_t diff, latency_avg_prev;
++
++	diff = now(CLOCK_THREAD_CPUTIME_ID) - prev;
++
++	stats.count++;
++	stats.latency_acc += diff;
++
++	/* see Welford62 */
++	latency_avg_prev = stats.latency_avg;
++	stats.latency_avg = stats.latency_acc / stats.count;
++	stats.latency_ssquares += (diff - latency_avg_prev) * (diff - stats.latency_avg);
++
++	if (stats.latency_low > diff)
++		stats.latency_low = diff;
++
++	if (stats.latency_high < diff)
++		stats.latency_high = diff;
++}
++
++static int setup_simple_kdbus_msg(struct kdbus_conn *conn,
++				  uint64_t dst_id,
++				  struct kdbus_msg **msg_out)
++{
++	struct kdbus_msg *msg;
++	struct kdbus_item *item;
++	uint64_t size;
++
++	size = sizeof(struct kdbus_msg);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
++
++	msg = malloc(size);
++	ASSERT_RETURN_VAL(msg, -ENOMEM);
++
++	memset(msg, 0, size);
++	msg->size = size;
++	msg->src_id = conn->id;
++	msg->dst_id = dst_id;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++
++	item = msg->items;
++
++	item->type = KDBUS_ITEM_PAYLOAD_VEC;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
++	item->vec.address = (uintptr_t) stress_payload;
++	item->vec.size = sizeof(stress_payload);
++	item = KDBUS_ITEM_NEXT(item);
++
++	*msg_out = msg;
++
++	return 0;
++}
++
++static int setup_memfd_kdbus_msg(struct kdbus_conn *conn,
++				 uint64_t dst_id,
++				 off_t *memfd_item_offset,
++				 struct kdbus_msg **msg_out)
++{
++	struct kdbus_msg *msg;
++	struct kdbus_item *item;
++	uint64_t size;
++
++	size = sizeof(struct kdbus_msg);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
++
++	msg = malloc(size);
++	ASSERT_RETURN_VAL(msg, -ENOMEM);
++
++	memset(msg, 0, size);
++	msg->size = size;
++	msg->src_id = conn->id;
++	msg->dst_id = dst_id;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++
++	item = msg->items;
++
++	item->type = KDBUS_ITEM_PAYLOAD_VEC;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
++	item->vec.address = (uintptr_t) stress_payload;
++	item->vec.size = sizeof(stress_payload);
++	item = KDBUS_ITEM_NEXT(item);
++
++	item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd);
++	item->memfd.size = sizeof(uint64_t);
++
++	*memfd_item_offset = (unsigned char *)item - (unsigned char *)msg;
++	*msg_out = msg;
++
++	return 0;
++}
++
++static int
++send_echo_request(struct kdbus_conn *conn, uint64_t dst_id,
++		  void *kdbus_msg, off_t memfd_item_offset)
++{
++	struct kdbus_cmd_send cmd = {};
++	int memfd = -1;
++	int ret;
++
++	if (use_memfd) {
++		uint64_t now_ns = now(CLOCK_THREAD_CPUTIME_ID);
++		struct kdbus_item *item = memfd_item_offset + kdbus_msg;
++		memfd = sys_memfd_create("memfd-name", 0);
++		ASSERT_RETURN_VAL(memfd >= 0, memfd);
++
++		ret = write(memfd, &now_ns, sizeof(now_ns));
++		ASSERT_RETURN_VAL(ret == sizeof(now_ns), -EAGAIN);
++
++		ret = sys_memfd_seal_set(memfd);
++		ASSERT_RETURN_VAL(ret == 0, -errno);
++
++		item->memfd.fd = memfd;
++	}
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)kdbus_msg;
++
++	ret = kdbus_cmd_send(conn->fd, &cmd);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	close(memfd);
++
++	return 0;
++}
++
++static int
++handle_echo_reply(struct kdbus_conn *conn, uint64_t send_ns)
++{
++	int ret;
++	struct kdbus_cmd_recv recv = { .size = sizeof(recv) };
++	struct kdbus_msg *msg;
++	const struct kdbus_item *item;
++	bool has_memfd = false;
++
++	ret = kdbus_cmd_recv(conn->fd, &recv);
++	if (ret == -EAGAIN)
++		return ret;
++
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	if (!use_memfd)
++		goto out;
++
++	msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset);
++
++	KDBUS_ITEM_FOREACH(item, msg, items) {
++		switch (item->type) {
++		case KDBUS_ITEM_PAYLOAD_MEMFD: {
++			char *buf;
++
++			buf = mmap(NULL, item->memfd.size, PROT_READ,
++				   MAP_PRIVATE, item->memfd.fd, 0);
++			ASSERT_RETURN_VAL(buf != MAP_FAILED, -EINVAL);
++			ASSERT_RETURN_VAL(item->memfd.size == sizeof(uint64_t),
++					  -EINVAL);
++
++			add_stats(*(uint64_t*)buf);
++			munmap(buf, item->memfd.size);
++			close(item->memfd.fd);
++			has_memfd = true;
++			break;
++		}
++
++		case KDBUS_ITEM_PAYLOAD_OFF:
++			/* ignore */
++			break;
++		}
++	}
++
++out:
++	if (!has_memfd)
++		add_stats(send_ns);
++
++	ret = kdbus_free(conn, recv.msg.offset);
++	ASSERT_RETURN_VAL(ret == 0, -errno);
++
++	return 0;
++}
++
++static int benchmark(struct kdbus_test_env *env)
++{
++	static char buf[sizeof(stress_payload)];
++	struct kdbus_msg *kdbus_msg = NULL;
++	off_t memfd_cached_offset = 0;
++	int ret;
++	struct kdbus_conn *conn_a, *conn_b;
++	struct pollfd fds[2];
++	uint64_t start, send_ns, now_ns, diff;
++	unsigned int i;
++	int uds[2];
++
++	setlocale(LC_ALL, "");
++
++	for (i = 0; i < sizeof(stress_payload); i++)
++		stress_payload[i] = i;
++
++	/* setup kdbus pair */
++
++	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_a && conn_b);
++
++	ret = kdbus_add_match_empty(conn_a);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_add_match_empty(conn_b);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_acquire(conn_a, SERVICE_NAME, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	if (attach_none) {
++		ret = kdbus_conn_update_attach_flags(conn_a,
++						     _KDBUS_ATTACH_ALL,
++						     0);
++		ASSERT_RETURN(ret == 0);
++	}
++
++	/* setup UDS pair */
++
++	ret = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0, uds);
++	ASSERT_RETURN(ret == 0);
++
++	/* setup a kdbus msg now */
++	if (use_memfd) {
++		ret = setup_memfd_kdbus_msg(conn_b, conn_a->id,
++					    &memfd_cached_offset,
++					    &kdbus_msg);
++		ASSERT_RETURN(ret == 0);
++	} else {
++		ret = setup_simple_kdbus_msg(conn_b, conn_a->id, &kdbus_msg);
++		ASSERT_RETURN(ret == 0);
++	}
++
++	/* start benchmark */
++
++	kdbus_printf("-- entering poll loop ...\n");
++
++	do {
++		/* run kdbus benchmark */
++		fds[0].fd = conn_a->fd;
++		fds[1].fd = conn_b->fd;
++
++		/* cancel any pending message */
++		handle_echo_reply(conn_a, 0);
++
++		start = now(CLOCK_THREAD_CPUTIME_ID);
++		reset_stats();
++
++		send_ns = now(CLOCK_THREAD_CPUTIME_ID);
++		ret = send_echo_request(conn_b, conn_a->id,
++					kdbus_msg, memfd_cached_offset);
++		ASSERT_RETURN(ret == 0);
++
++		while (1) {
++			unsigned int nfds = sizeof(fds) / sizeof(fds[0]);
++			unsigned int i;
++
++			for (i = 0; i < nfds; i++) {
++				fds[i].events = POLLIN | POLLPRI | POLLHUP;
++				fds[i].revents = 0;
++			}
++
++			ret = poll(fds, nfds, 10);
++			if (ret < 0)
++				break;
++
++			if (fds[0].revents & POLLIN) {
++				ret = handle_echo_reply(conn_a, send_ns);
++				ASSERT_RETURN(ret == 0);
++
++				send_ns = now(CLOCK_THREAD_CPUTIME_ID);
++				ret = send_echo_request(conn_b, conn_a->id,
++							kdbus_msg,
++							memfd_cached_offset);
++				ASSERT_RETURN(ret == 0);
++			}
++
++			now_ns = now(CLOCK_THREAD_CPUTIME_ID);
++			diff = now_ns - start;
++			if (diff > 1000000000ULL) {
++				start = now_ns;
++
++				dump_stats(false);
++				break;
++			}
++		}
++
++		if (!compare_uds)
++			continue;
++
++		/* run unix-socket benchmark as comparison */
++
++		fds[0].fd = uds[0];
++		fds[1].fd = uds[1];
++
++		/* cancel any pendign message */
++		read(uds[1], buf, sizeof(buf));
++
++		start = now(CLOCK_THREAD_CPUTIME_ID);
++		reset_stats();
++
++		send_ns = now(CLOCK_THREAD_CPUTIME_ID);
++		ret = write(uds[0], stress_payload, sizeof(stress_payload));
++		ASSERT_RETURN(ret == sizeof(stress_payload));
++
++		while (1) {
++			unsigned int nfds = sizeof(fds) / sizeof(fds[0]);
++			unsigned int i;
++
++			for (i = 0; i < nfds; i++) {
++				fds[i].events = POLLIN | POLLPRI | POLLHUP;
++				fds[i].revents = 0;
++			}
++
++			ret = poll(fds, nfds, 10);
++			if (ret < 0)
++				break;
++
++			if (fds[1].revents & POLLIN) {
++				ret = read(uds[1], buf, sizeof(buf));
++				ASSERT_RETURN(ret == sizeof(buf));
++
++				add_stats(send_ns);
++
++				send_ns = now(CLOCK_THREAD_CPUTIME_ID);
++				ret = write(uds[0], buf, sizeof(buf));
++				ASSERT_RETURN(ret == sizeof(buf));
++			}
++
++			now_ns = now(CLOCK_THREAD_CPUTIME_ID);
++			diff = now_ns - start;
++			if (diff > 1000000000ULL) {
++				start = now_ns;
++
++				dump_stats(true);
++				break;
++			}
++		}
++
++	} while (kdbus_util_verbose);
++
++	kdbus_printf("-- closing bus connections\n");
++
++	free(kdbus_msg);
++
++	kdbus_conn_free(conn_a);
++	kdbus_conn_free(conn_b);
++
++	return (stats.count > 1) ? TEST_OK : TEST_ERR;
++}
++
++int kdbus_test_benchmark(struct kdbus_test_env *env)
++{
++	use_memfd = true;
++	attach_none = false;
++	compare_uds = false;
++	return benchmark(env);
++}
++
++int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env)
++{
++	use_memfd = false;
++	attach_none = false;
++	compare_uds = false;
++	return benchmark(env);
++}
++
++int kdbus_test_benchmark_uds(struct kdbus_test_env *env)
++{
++	use_memfd = false;
++	attach_none = true;
++	compare_uds = true;
++	return benchmark(env);
++}
+diff --git a/tools/testing/selftests/kdbus/test-bus.c b/tools/testing/selftests/kdbus/test-bus.c
+new file mode 100644
+index 0000000..762fb30
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-bus.c
+@@ -0,0 +1,175 @@
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <limits.h>
++#include <sys/mman.h>
++#include <stdbool.h>
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++static struct kdbus_item *kdbus_get_item(struct kdbus_info *info,
++					 uint64_t type)
++{
++	struct kdbus_item *item;
++
++	KDBUS_ITEM_FOREACH(item, info, items)
++		if (item->type == type)
++			return item;
++
++	return NULL;
++}
++
++static int test_bus_creator_info(const char *bus_path)
++{
++	int ret;
++	uint64_t offset;
++	struct kdbus_conn *conn;
++	struct kdbus_info *info;
++	struct kdbus_item *item;
++	char *tmp, *busname;
++
++	/* extract the bus-name from @bus_path */
++	tmp = strdup(bus_path);
++	ASSERT_RETURN(tmp);
++	busname = strrchr(tmp, '/');
++	ASSERT_RETURN(busname);
++	*busname = 0;
++	busname = strrchr(tmp, '/');
++	ASSERT_RETURN(busname);
++	++busname;
++
++	conn = kdbus_hello(bus_path, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	ret = kdbus_bus_creator_info(conn, _KDBUS_ATTACH_ALL, &offset);
++	ASSERT_RETURN(ret == 0);
++
++	info = (struct kdbus_info *)(conn->buf + offset);
++
++	item = kdbus_get_item(info, KDBUS_ITEM_MAKE_NAME);
++	ASSERT_RETURN(item);
++	ASSERT_RETURN(!strcmp(item->str, busname));
++
++	ret = kdbus_free(conn, offset);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	free(tmp);
++	kdbus_conn_free(conn);
++	return 0;
++}
++
++int kdbus_test_bus_make(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd cmd;
++
++		/* bloom size item */
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_bloom_parameter bloom;
++		} bs;
++
++		/* name item */
++		uint64_t n_size;
++		uint64_t n_type;
++		char name[64];
++	} bus_make;
++	char s[PATH_MAX], *name;
++	int ret, control_fd2;
++	uid_t uid;
++
++	name = unique_name("");
++	ASSERT_RETURN(name);
++
++	snprintf(s, sizeof(s), "%s/control", env->root);
++	env->control_fd = open(s, O_RDWR|O_CLOEXEC);
++	ASSERT_RETURN(env->control_fd >= 0);
++
++	control_fd2 = open(s, O_RDWR|O_CLOEXEC);
++	ASSERT_RETURN(control_fd2 >= 0);
++
++	memset(&bus_make, 0, sizeof(bus_make));
++
++	bus_make.bs.size = sizeof(bus_make.bs);
++	bus_make.bs.type = KDBUS_ITEM_BLOOM_PARAMETER;
++	bus_make.bs.bloom.size = 64;
++	bus_make.bs.bloom.n_hash = 1;
++
++	bus_make.n_type = KDBUS_ITEM_MAKE_NAME;
++
++	uid = getuid();
++
++	/* missing uid prefix */
++	snprintf(bus_make.name, sizeof(bus_make.name), "foo");
++	bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
++	bus_make.cmd.size = sizeof(struct kdbus_cmd) +
++			    sizeof(bus_make.bs) + bus_make.n_size;
++	ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* non alphanumeric character */
++	snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah@123", uid);
++	bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
++	bus_make.cmd.size = sizeof(struct kdbus_cmd) +
++			    sizeof(bus_make.bs) + bus_make.n_size;
++	ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* '-' at the end */
++	snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah-", uid);
++	bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
++	bus_make.cmd.size = sizeof(struct kdbus_cmd) +
++			    sizeof(bus_make.bs) + bus_make.n_size;
++	ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* create a new bus */
++	snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-1", uid, name);
++	bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
++	bus_make.cmd.size = sizeof(struct kdbus_cmd) +
++			    sizeof(bus_make.bs) + bus_make.n_size;
++	ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_cmd_bus_make(control_fd2, &bus_make.cmd);
++	ASSERT_RETURN(ret == -EEXIST);
++
++	snprintf(s, sizeof(s), "%s/%u-%s-1/bus", env->root, uid, name);
++	ASSERT_RETURN(access(s, F_OK) == 0);
++
++	ret = test_bus_creator_info(s);
++	ASSERT_RETURN(ret == 0);
++
++	/* can't use the same fd for bus make twice, even though a different
++	 * bus name is used
++	 */
++	snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-2", uid, name);
++	bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
++	bus_make.cmd.size = sizeof(struct kdbus_cmd) +
++			    sizeof(bus_make.bs) + bus_make.n_size;
++	ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd);
++	ASSERT_RETURN(ret == -EBADFD);
++
++	/* create a new bus, with different fd and different bus name */
++	snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-2", uid, name);
++	bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
++	bus_make.cmd.size = sizeof(struct kdbus_cmd) +
++			    sizeof(bus_make.bs) + bus_make.n_size;
++	ret = kdbus_cmd_bus_make(control_fd2, &bus_make.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	close(control_fd2);
++	free(name);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-chat.c b/tools/testing/selftests/kdbus/test-chat.c
+new file mode 100644
+index 0000000..41e5b53
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-chat.c
+@@ -0,0 +1,124 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <poll.h>
++#include <stdbool.h>
++
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++int kdbus_test_chat(struct kdbus_test_env *env)
++{
++	int ret, cookie;
++	struct kdbus_conn *conn_a, *conn_b;
++	struct pollfd fds[2];
++	uint64_t flags;
++	int count;
++
++	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_a && conn_b);
++
++	flags = KDBUS_NAME_ALLOW_REPLACEMENT;
++	ret = kdbus_name_acquire(conn_a, "foo.bar.test", &flags);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_acquire(conn_a, "foo.bar.baz", NULL);
++	ASSERT_RETURN(ret == 0);
++
++	flags = KDBUS_NAME_QUEUE;
++	ret = kdbus_name_acquire(conn_b, "foo.bar.baz", &flags);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL);
++	ASSERT_RETURN(ret == 0);
++
++	flags = 0;
++	ret = kdbus_name_acquire(conn_a, "foo.bar.double", &flags);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(!(flags & KDBUS_NAME_ACQUIRED));
++
++	ret = kdbus_name_release(conn_a, "foo.bar.double");
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_release(conn_a, "foo.bar.double");
++	ASSERT_RETURN(ret == -ESRCH);
++
++	ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE |
++				 KDBUS_LIST_NAMES  |
++				 KDBUS_LIST_QUEUED |
++				 KDBUS_LIST_ACTIVATORS);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_add_match_empty(conn_a);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_add_match_empty(conn_b);
++	ASSERT_RETURN(ret == 0);
++
++	cookie = 0;
++	ret = kdbus_msg_send(conn_b, NULL, 0xc0000000 | cookie, 0, 0, 0,
++			     KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++	fds[0].fd = conn_a->fd;
++	fds[1].fd = conn_b->fd;
++
++	kdbus_printf("-- entering poll loop ...\n");
++
++	for (count = 0;; count++) {
++		int i, nfds = sizeof(fds) / sizeof(fds[0]);
++
++		for (i = 0; i < nfds; i++) {
++			fds[i].events = POLLIN | POLLPRI | POLLHUP;
++			fds[i].revents = 0;
++		}
++
++		ret = poll(fds, nfds, 3000);
++		ASSERT_RETURN(ret >= 0);
++
++		if (fds[0].revents & POLLIN) {
++			if (count > 2)
++				kdbus_name_release(conn_a, "foo.bar.baz");
++
++			ret = kdbus_msg_recv(conn_a, NULL, NULL);
++			ASSERT_RETURN(ret == 0);
++			ret = kdbus_msg_send(conn_a, NULL,
++					     0xc0000000 | cookie++,
++					     0, 0, 0, conn_b->id);
++			ASSERT_RETURN(ret == 0);
++		}
++
++		if (fds[1].revents & POLLIN) {
++			ret = kdbus_msg_recv(conn_b, NULL, NULL);
++			ASSERT_RETURN(ret == 0);
++			ret = kdbus_msg_send(conn_b, NULL,
++					     0xc0000000 | cookie++,
++					     0, 0, 0, conn_a->id);
++			ASSERT_RETURN(ret == 0);
++		}
++
++		ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE |
++					 KDBUS_LIST_NAMES  |
++					 KDBUS_LIST_QUEUED |
++					 KDBUS_LIST_ACTIVATORS);
++		ASSERT_RETURN(ret == 0);
++
++		if (count > 10)
++			break;
++	}
++
++	kdbus_printf("-- closing bus connections\n");
++	kdbus_conn_free(conn_a);
++	kdbus_conn_free(conn_b);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-connection.c b/tools/testing/selftests/kdbus/test-connection.c
+new file mode 100644
+index 0000000..4688ce8
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-connection.c
+@@ -0,0 +1,597 @@
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <limits.h>
++#include <sys/types.h>
++#include <sys/capability.h>
++#include <sys/mman.h>
++#include <sys/syscall.h>
++#include <sys/wait.h>
++#include <stdbool.h>
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++int kdbus_test_hello(struct kdbus_test_env *env)
++{
++	struct kdbus_cmd_free cmd_free = {};
++	struct kdbus_cmd_hello hello;
++	int fd, ret;
++
++	memset(&hello, 0, sizeof(hello));
++
++	fd = open(env->buspath, O_RDWR|O_CLOEXEC);
++	ASSERT_RETURN(fd >= 0);
++
++	hello.flags = KDBUS_HELLO_ACCEPT_FD;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	hello.attach_flags_recv = _KDBUS_ATTACH_ALL;
++	hello.size = sizeof(struct kdbus_cmd_hello);
++	hello.pool_size = POOL_SIZE;
++
++	/* an unaligned hello must result in -EFAULT */
++	ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) ((char *) &hello + 1));
++	ASSERT_RETURN(ret == -EFAULT);
++
++	/* a size of 0 must return EMSGSIZE */
++	hello.size = 1;
++	hello.flags = KDBUS_HELLO_ACCEPT_FD;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	ret = kdbus_cmd_hello(fd, &hello);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	hello.size = sizeof(struct kdbus_cmd_hello);
++
++	/* check faulty flags */
++	hello.flags = 1ULL << 32;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	ret = kdbus_cmd_hello(fd, &hello);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* check for faulty pool sizes */
++	hello.pool_size = 0;
++	hello.flags = KDBUS_HELLO_ACCEPT_FD;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	ret = kdbus_cmd_hello(fd, &hello);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	hello.pool_size = 4097;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	ret = kdbus_cmd_hello(fd, &hello);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	hello.pool_size = POOL_SIZE;
++
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	hello.offset = (__u64)-1;
++
++	/* success test */
++	ret = kdbus_cmd_hello(fd, &hello);
++	ASSERT_RETURN(ret == 0);
++
++	/* The kernel should have returned some items */
++	ASSERT_RETURN(hello.offset != (__u64)-1);
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.offset = hello.offset;
++	ret = kdbus_cmd_free(fd, &cmd_free);
++	ASSERT_RETURN(ret >= 0);
++
++	close(fd);
++
++	fd = open(env->buspath, O_RDWR|O_CLOEXEC);
++	ASSERT_RETURN(fd >= 0);
++
++	/* no ACTIVATOR flag without a name */
++	hello.flags = KDBUS_HELLO_ACTIVATOR;
++	ret = kdbus_cmd_hello(fd, &hello);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	close(fd);
++
++	return TEST_OK;
++}
++
++int kdbus_test_byebye(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn;
++	struct kdbus_cmd_recv cmd_recv = { .size = sizeof(cmd_recv) };
++	struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) };
++	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 = kdbus_cmd_byebye(conn->fd, &cmd_byebye);
++	ASSERT_RETURN(ret == -EBUSY);
++
++	/* receive the message */
++	ret = kdbus_cmd_recv(conn->fd, &cmd_recv);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_free(conn, cmd_recv.msg.offset);
++	ASSERT_RETURN(ret == 0);
++
++	/* and try again */
++	ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye);
++	ASSERT_RETURN(ret == 0);
++
++	/* a 2nd try should result in -ECONNRESET */
++	ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye);
++	ASSERT_RETURN(ret == -ECONNRESET);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++/* Get only the first item */
++static struct kdbus_item *kdbus_get_item(struct kdbus_info *info,
++					 uint64_t type)
++{
++	struct kdbus_item *item;
++
++	KDBUS_ITEM_FOREACH(item, info, items)
++		if (item->type == type)
++			return item;
++
++	return NULL;
++}
++
++static unsigned int kdbus_count_item(struct kdbus_info *info,
++				     uint64_t type)
++{
++	unsigned int i = 0;
++	const struct kdbus_item *item;
++
++	KDBUS_ITEM_FOREACH(item, info, items)
++		if (item->type == type)
++			i++;
++
++	return i;
++}
++
++static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable)
++{
++	int ret;
++	unsigned int cnt = 0;
++	uint64_t offset = 0;
++	struct kdbus_info *info;
++	struct kdbus_conn *conn;
++	struct kdbus_conn *privileged;
++	const struct kdbus_item *item;
++	uint64_t valid_flags = KDBUS_ATTACH_NAMES |
++			       KDBUS_ATTACH_CREDS |
++			       KDBUS_ATTACH_PIDS |
++			       KDBUS_ATTACH_CONN_DESCRIPTION;
++
++	uint64_t invalid_flags = KDBUS_ATTACH_NAMES	|
++				 KDBUS_ATTACH_CREDS	|
++				 KDBUS_ATTACH_PIDS	|
++				 KDBUS_ATTACH_CAPS	|
++				 KDBUS_ATTACH_CGROUP	|
++				 KDBUS_ATTACH_CONN_DESCRIPTION;
++
++	struct kdbus_creds cached_creds;
++	uid_t ruid, euid, suid;
++	gid_t rgid, egid, sgid;
++
++	getresuid(&ruid, &euid, &suid);
++	getresgid(&rgid, &egid, &sgid);
++
++	cached_creds.uid = ruid;
++	cached_creds.euid = euid;
++	cached_creds.suid = suid;
++	cached_creds.fsuid = ruid;
++
++	cached_creds.gid = rgid;
++	cached_creds.egid = egid;
++	cached_creds.sgid = sgid;
++	cached_creds.fsgid = rgid;
++
++	struct kdbus_pids cached_pids = {
++		.pid	= getpid(),
++		.tid	= syscall(SYS_gettid),
++		.ppid	= getppid(),
++	};
++
++	ret = kdbus_conn_info(env->conn, env->conn->id, NULL,
++			      valid_flags, &offset);
++	ASSERT_RETURN(ret == 0);
++
++	info = (struct kdbus_info *)(env->conn->buf + offset);
++	ASSERT_RETURN(info->id == env->conn->id);
++
++	/* We do not have any well-known name */
++	item = kdbus_get_item(info, KDBUS_ITEM_NAME);
++	ASSERT_RETURN(item == NULL);
++
++	item = kdbus_get_item(info, KDBUS_ITEM_CONN_DESCRIPTION);
++	if (valid_flags & KDBUS_ATTACH_CONN_DESCRIPTION) {
++		ASSERT_RETURN(item);
++	} else {
++		ASSERT_RETURN(item == NULL);
++	}
++
++	kdbus_free(env->conn, offset);
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	privileged = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(privileged);
++
++	ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset);
++	ASSERT_RETURN(ret == 0);
++
++	info = (struct kdbus_info *)(conn->buf + offset);
++	ASSERT_RETURN(info->id == conn->id);
++
++	/* We do not have any well-known name */
++	item = kdbus_get_item(info, KDBUS_ITEM_NAME);
++	ASSERT_RETURN(item == NULL);
++
++	cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS);
++	if (valid_flags & KDBUS_ATTACH_CREDS) {
++		ASSERT_RETURN(cnt == 1);
++
++		item = kdbus_get_item(info, KDBUS_ITEM_CREDS);
++		ASSERT_RETURN(item);
++
++		/* Compare received items with cached creds */
++		ASSERT_RETURN(memcmp(&item->creds, &cached_creds,
++				      sizeof(struct kdbus_creds)) == 0);
++	} else {
++		ASSERT_RETURN(cnt == 0);
++	}
++
++	item = kdbus_get_item(info, KDBUS_ITEM_PIDS);
++	if (valid_flags & KDBUS_ATTACH_PIDS) {
++		ASSERT_RETURN(item);
++
++		/* Compare item->pids with cached PIDs */
++		ASSERT_RETURN(item->pids.pid == cached_pids.pid &&
++			      item->pids.tid == cached_pids.tid &&
++			      item->pids.ppid == cached_pids.ppid);
++	} else {
++		ASSERT_RETURN(item == NULL);
++	}
++
++	/* We did not request KDBUS_ITEM_CAPS */
++	item = kdbus_get_item(info, KDBUS_ITEM_CAPS);
++	ASSERT_RETURN(item == NULL);
++
++	kdbus_free(conn, offset);
++
++	ret = kdbus_name_acquire(conn, "com.example.a", NULL);
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset);
++	ASSERT_RETURN(ret == 0);
++
++	info = (struct kdbus_info *)(conn->buf + offset);
++	ASSERT_RETURN(info->id == conn->id);
++
++	item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME);
++	if (valid_flags & KDBUS_ATTACH_NAMES) {
++		ASSERT_RETURN(item && !strcmp(item->name.name, "com.example.a"));
++	} else {
++		ASSERT_RETURN(item == NULL);
++	}
++
++	kdbus_free(conn, offset);
++
++	ret = kdbus_conn_info(conn, 0, "com.example.a", valid_flags, &offset);
++	ASSERT_RETURN(ret == 0);
++
++	info = (struct kdbus_info *)(conn->buf + offset);
++	ASSERT_RETURN(info->id == conn->id);
++
++	kdbus_free(conn, offset);
++
++	/* does not have the necessary caps to drop to unprivileged */
++	if (!capable)
++		goto continue_test;
++
++	ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({
++		ret = kdbus_conn_info(conn, conn->id, NULL,
++				      valid_flags, &offset);
++		ASSERT_EXIT(ret == 0);
++
++		info = (struct kdbus_info *)(conn->buf + offset);
++		ASSERT_EXIT(info->id == conn->id);
++
++		if (valid_flags & KDBUS_ATTACH_NAMES) {
++			item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME);
++			ASSERT_EXIT(item &&
++				    strcmp(item->name.name,
++				           "com.example.a") == 0);
++		}
++
++		if (valid_flags & KDBUS_ATTACH_CREDS) {
++			item = kdbus_get_item(info, KDBUS_ITEM_CREDS);
++			ASSERT_EXIT(item);
++
++			/* Compare received items with cached creds */
++			ASSERT_EXIT(memcmp(&item->creds, &cached_creds,
++				    sizeof(struct kdbus_creds)) == 0);
++		}
++
++		if (valid_flags & KDBUS_ATTACH_PIDS) {
++			item = kdbus_get_item(info, KDBUS_ITEM_PIDS);
++			ASSERT_EXIT(item);
++
++			/*
++			 * Compare item->pids with cached pids of
++			 * privileged one.
++			 *
++			 * cmd_info will always return cached pids.
++			 */
++			ASSERT_EXIT(item->pids.pid == cached_pids.pid &&
++				    item->pids.tid == cached_pids.tid);
++		}
++
++		kdbus_free(conn, offset);
++
++		/*
++		 * Use invalid_flags and make sure that userspace
++		 * do not play with us.
++		 */
++		ret = kdbus_conn_info(conn, conn->id, NULL,
++				      invalid_flags, &offset);
++		ASSERT_EXIT(ret == 0);
++
++		/*
++		 * Make sure that we return only one creds item and
++		 * it points to the cached creds.
++		 */
++		cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS);
++		if (invalid_flags & KDBUS_ATTACH_CREDS) {
++			ASSERT_EXIT(cnt == 1);
++
++			item = kdbus_get_item(info, KDBUS_ITEM_CREDS);
++			ASSERT_EXIT(item);
++
++			/* Compare received items with cached creds */
++			ASSERT_EXIT(memcmp(&item->creds, &cached_creds,
++				    sizeof(struct kdbus_creds)) == 0);
++		} else {
++			ASSERT_EXIT(cnt == 0);
++		}
++
++		if (invalid_flags & KDBUS_ATTACH_PIDS) {
++			cnt = kdbus_count_item(info, KDBUS_ITEM_PIDS);
++			ASSERT_EXIT(cnt == 1);
++
++			item = kdbus_get_item(info, KDBUS_ITEM_PIDS);
++			ASSERT_EXIT(item);
++
++			/* Compare item->pids with cached pids */
++			ASSERT_EXIT(item->pids.pid == cached_pids.pid &&
++				    item->pids.tid == cached_pids.tid);
++		}
++
++		cnt = kdbus_count_item(info, KDBUS_ITEM_CGROUP);
++		if (invalid_flags & KDBUS_ATTACH_CGROUP) {
++			ASSERT_EXIT(cnt == 1);
++		} else {
++			ASSERT_EXIT(cnt == 0);
++		}
++
++		cnt = kdbus_count_item(info, KDBUS_ITEM_CAPS);
++		if (invalid_flags & KDBUS_ATTACH_CAPS) {
++			ASSERT_EXIT(cnt == 1);
++		} else {
++			ASSERT_EXIT(cnt == 0);
++		}
++
++		kdbus_free(conn, offset);
++	}),
++	({ 0; }));
++	ASSERT_RETURN(ret == 0);
++
++continue_test:
++
++	/* A second name */
++	ret = kdbus_name_acquire(conn, "com.example.b", NULL);
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset);
++	ASSERT_RETURN(ret == 0);
++
++	info = (struct kdbus_info *)(conn->buf + offset);
++	ASSERT_RETURN(info->id == conn->id);
++
++	cnt = kdbus_count_item(info, KDBUS_ITEM_OWNED_NAME);
++	if (valid_flags & KDBUS_ATTACH_NAMES) {
++		ASSERT_RETURN(cnt == 2);
++	} else {
++		ASSERT_RETURN(cnt == 0);
++	}
++
++	kdbus_free(conn, offset);
++
++	ASSERT_RETURN(ret == 0);
++
++	return 0;
++}
++
++int kdbus_test_conn_info(struct kdbus_test_env *env)
++{
++	int ret;
++	int have_caps;
++	struct {
++		struct kdbus_cmd_info cmd_info;
++
++		struct {
++			uint64_t size;
++			uint64_t type;
++			char str[64];
++		} name;
++	} buf;
++
++	buf.cmd_info.size = sizeof(struct kdbus_cmd_info);
++	buf.cmd_info.flags = 0;
++	buf.cmd_info.attach_flags = 0;
++	buf.cmd_info.id = env->conn->id;
++
++	ret = kdbus_conn_info(env->conn, env->conn->id, NULL, 0, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* try to pass a name that is longer than the buffer's size */
++	buf.name.size = KDBUS_ITEM_HEADER_SIZE + 1;
++	buf.name.type = KDBUS_ITEM_NAME;
++	strcpy(buf.name.str, "foo.bar.bla");
++
++	buf.cmd_info.id = 0;
++	buf.cmd_info.size = sizeof(buf.cmd_info) + buf.name.size;
++	ret = kdbus_cmd_conn_info(env->conn->fd, (struct kdbus_cmd_info *) &buf);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* Pass a non existent name */
++	ret = kdbus_conn_info(env->conn, 0, "non.existent.name", 0, NULL);
++	ASSERT_RETURN(ret == -ESRCH);
++
++	if (!all_uids_gids_are_mapped())
++		return TEST_SKIP;
++
++	/* Test for caps here, so we run the previous test */
++	have_caps = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
++	ASSERT_RETURN(have_caps >= 0);
++
++	ret = kdbus_fuzz_conn_info(env, have_caps);
++	ASSERT_RETURN(ret == 0);
++
++	/* Now if we have skipped some tests then let the user know */
++	if (!have_caps)
++		return TEST_SKIP;
++
++	return TEST_OK;
++}
++
++int kdbus_test_conn_update(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn;
++	struct kdbus_msg *msg;
++	int found = 0;
++	int ret;
++
++	/*
++	 * kdbus_hello() sets all attach flags. Receive a message by this
++	 * connection, and make sure a timestamp item (just to pick one) is
++	 * present.
++	 */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP);
++	ASSERT_RETURN(found == 1);
++
++	kdbus_msg_free(msg);
++
++	/*
++	 * Now, modify the attach flags and repeat the action. The item must
++	 * now be missing.
++	 */
++	found = 0;
++
++	ret = kdbus_conn_update_attach_flags(conn,
++					     _KDBUS_ATTACH_ALL,
++					     _KDBUS_ATTACH_ALL &
++					     ~KDBUS_ATTACH_TIMESTAMP);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP);
++	ASSERT_RETURN(found == 0);
++
++	/* Provide a bogus attach_flags value */
++	ret = kdbus_conn_update_attach_flags(conn,
++					     _KDBUS_ATTACH_ALL + 1,
++					     _KDBUS_ATTACH_ALL);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	kdbus_msg_free(msg);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++int kdbus_test_writable_pool(struct kdbus_test_env *env)
++{
++	struct kdbus_cmd_free cmd_free = {};
++	struct kdbus_cmd_hello hello;
++	int fd, ret;
++	void *map;
++
++	fd = open(env->buspath, O_RDWR | O_CLOEXEC);
++	ASSERT_RETURN(fd >= 0);
++
++	memset(&hello, 0, sizeof(hello));
++	hello.flags = KDBUS_HELLO_ACCEPT_FD;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++	hello.attach_flags_recv = _KDBUS_ATTACH_ALL;
++	hello.size = sizeof(struct kdbus_cmd_hello);
++	hello.pool_size = POOL_SIZE;
++	hello.offset = (__u64)-1;
++
++	/* success test */
++	ret = kdbus_cmd_hello(fd, &hello);
++	ASSERT_RETURN(ret == 0);
++
++	/* The kernel should have returned some items */
++	ASSERT_RETURN(hello.offset != (__u64)-1);
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.offset = hello.offset;
++	ret = kdbus_cmd_free(fd, &cmd_free);
++	ASSERT_RETURN(ret >= 0);
++
++	/* pools cannot be mapped writable */
++	map = mmap(NULL, POOL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
++	ASSERT_RETURN(map == MAP_FAILED);
++
++	/* pools can always be mapped readable */
++	map = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0);
++	ASSERT_RETURN(map != MAP_FAILED);
++
++	/* make sure we cannot change protection masks to writable */
++	ret = mprotect(map, POOL_SIZE, PROT_READ | PROT_WRITE);
++	ASSERT_RETURN(ret < 0);
++
++	munmap(map, POOL_SIZE);
++	close(fd);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-daemon.c b/tools/testing/selftests/kdbus/test-daemon.c
+new file mode 100644
+index 0000000..8bc2386
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-daemon.c
+@@ -0,0 +1,65 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <poll.h>
++#include <stdbool.h>
++
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++int kdbus_test_daemon(struct kdbus_test_env *env)
++{
++	struct pollfd fds[2];
++	int count;
++	int ret;
++
++	/* This test doesn't make any sense in non-interactive mode */
++	if (!kdbus_util_verbose)
++		return TEST_OK;
++
++	printf("Created connection %llu on bus '%s'\n",
++		(unsigned long long) env->conn->id, env->buspath);
++
++	ret = kdbus_name_acquire(env->conn, "com.example.kdbus-test", NULL);
++	ASSERT_RETURN(ret == 0);
++	printf("  Aquired name: com.example.kdbus-test\n");
++
++	fds[0].fd = env->conn->fd;
++	fds[1].fd = STDIN_FILENO;
++
++	printf("Monitoring connections:\n");
++
++	for (count = 0;; count++) {
++		int i, nfds = sizeof(fds) / sizeof(fds[0]);
++
++		for (i = 0; i < nfds; i++) {
++			fds[i].events = POLLIN | POLLPRI | POLLHUP;
++			fds[i].revents = 0;
++		}
++
++		ret = poll(fds, nfds, -1);
++		if (ret <= 0)
++			break;
++
++		if (fds[0].revents & POLLIN) {
++			ret = kdbus_msg_recv(env->conn, NULL, NULL);
++			ASSERT_RETURN(ret == 0);
++		}
++
++		/* stdin */
++		if (fds[1].revents & POLLIN)
++			break;
++	}
++
++	printf("Closing bus connection\n");
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-endpoint.c b/tools/testing/selftests/kdbus/test-endpoint.c
+new file mode 100644
+index 0000000..34a7be4
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-endpoint.c
+@@ -0,0 +1,352 @@
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <libgen.h>
++#include <sys/capability.h>
++#include <sys/wait.h>
++#include <stdbool.h>
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++#define KDBUS_SYSNAME_MAX_LEN			63
++
++static int install_name_add_match(struct kdbus_conn *conn, const char *name)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_name_change chg;
++		} item;
++		char name[64];
++	} buf;
++	int ret;
++
++	/* install the match rule */
++	memset(&buf, 0, sizeof(buf));
++	buf.item.type = KDBUS_ITEM_NAME_ADD;
++	buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
++	buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
++	strncpy(buf.name, name, sizeof(buf.name) - 1);
++	buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
++	buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
++
++	ret = kdbus_cmd_match_add(conn->fd, &buf.cmd);
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
++static int create_endpoint(const char *buspath, uid_t uid, const char *name,
++			   uint64_t flags)
++{
++	struct {
++		struct kdbus_cmd cmd;
++
++		/* name item */
++		struct {
++			uint64_t size;
++			uint64_t type;
++			/* max should be KDBUS_SYSNAME_MAX_LEN */
++			char str[128];
++		} name;
++	} ep_make;
++	int fd, ret;
++
++	fd = open(buspath, O_RDWR);
++	if (fd < 0)
++		return fd;
++
++	memset(&ep_make, 0, sizeof(ep_make));
++
++	snprintf(ep_make.name.str,
++		 /* Use the KDBUS_SYSNAME_MAX_LEN or sizeof(str) */
++		 KDBUS_SYSNAME_MAX_LEN > strlen(name) ?
++		 KDBUS_SYSNAME_MAX_LEN : sizeof(ep_make.name.str),
++		 "%u-%s", uid, name);
++
++	ep_make.name.type = KDBUS_ITEM_MAKE_NAME;
++	ep_make.name.size = KDBUS_ITEM_HEADER_SIZE +
++			    strlen(ep_make.name.str) + 1;
++
++	ep_make.cmd.flags = flags;
++	ep_make.cmd.size = sizeof(ep_make.cmd) + ep_make.name.size;
++
++	ret = kdbus_cmd_endpoint_make(fd, &ep_make.cmd);
++	if (ret < 0) {
++		kdbus_printf("error creating endpoint: %d (%m)\n", ret);
++		return ret;
++	}
++
++	return fd;
++}
++
++static int unpriv_test_custom_ep(const char *buspath)
++{
++	int ret, ep_fd1, ep_fd2;
++	char *ep1, *ep2, *tmp1, *tmp2;
++
++	tmp1 = strdup(buspath);
++	tmp2 = strdup(buspath);
++	ASSERT_RETURN(tmp1 && tmp2);
++
++	ret = asprintf(&ep1, "%s/%u-%s", dirname(tmp1), getuid(), "apps1");
++	ASSERT_RETURN(ret >= 0);
++
++	ret = asprintf(&ep2, "%s/%u-%s", dirname(tmp2), getuid(), "apps2");
++	ASSERT_RETURN(ret >= 0);
++
++	free(tmp1);
++	free(tmp2);
++
++	/* endpoint only accessible to current uid */
++	ep_fd1 = create_endpoint(buspath, getuid(), "apps1", 0);
++	ASSERT_RETURN(ep_fd1 >= 0);
++
++	/* endpoint world accessible */
++	ep_fd2 = create_endpoint(buspath, getuid(), "apps2",
++				  KDBUS_MAKE_ACCESS_WORLD);
++	ASSERT_RETURN(ep_fd2 >= 0);
++
++	ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({
++		int ep_fd;
++		struct kdbus_conn *ep_conn;
++
++		/*
++		 * Make sure that we are not able to create custom
++		 * endpoints
++		 */
++		ep_fd = create_endpoint(buspath, getuid(),
++					"unpriv_costum_ep", 0);
++		ASSERT_EXIT(ep_fd == -EPERM);
++
++		/*
++		 * Endpoint "apps1" only accessible to same users,
++		 * that own the endpoint. Access denied by VFS
++		 */
++		ep_conn = kdbus_hello(ep1, 0, NULL, 0);
++		ASSERT_EXIT(!ep_conn && errno == EACCES);
++
++		/* Endpoint "apps2" world accessible */
++		ep_conn = kdbus_hello(ep2, 0, NULL, 0);
++		ASSERT_EXIT(ep_conn);
++
++		kdbus_conn_free(ep_conn);
++
++		_exit(EXIT_SUCCESS);
++	}),
++	({ 0; }));
++	ASSERT_RETURN(ret == 0);
++
++	close(ep_fd1);
++	close(ep_fd2);
++	free(ep1);
++	free(ep2);
++
++	return 0;
++}
++
++static int update_endpoint(int fd, const char *name)
++{
++	int len = strlen(name) + 1;
++	struct {
++		struct kdbus_cmd cmd;
++
++		/* name item */
++		struct {
++			uint64_t size;
++			uint64_t type;
++			char str[KDBUS_ALIGN8(len)];
++		} name;
++
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_policy_access access;
++		} access;
++	} ep_update;
++	int ret;
++
++	memset(&ep_update, 0, sizeof(ep_update));
++
++	ep_update.name.size = KDBUS_ITEM_HEADER_SIZE + len;
++	ep_update.name.type = KDBUS_ITEM_NAME;
++	strncpy(ep_update.name.str, name, sizeof(ep_update.name.str) - 1);
++
++	ep_update.access.size = sizeof(ep_update.access);
++	ep_update.access.type = KDBUS_ITEM_POLICY_ACCESS;
++	ep_update.access.access.type = KDBUS_POLICY_ACCESS_WORLD;
++	ep_update.access.access.access = KDBUS_POLICY_SEE;
++
++	ep_update.cmd.size = sizeof(ep_update);
++
++	ret = kdbus_cmd_endpoint_update(fd, &ep_update.cmd);
++	if (ret < 0) {
++		kdbus_printf("error updating endpoint: %d (%m)\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++int kdbus_test_custom_endpoint(struct kdbus_test_env *env)
++{
++	char *ep, *tmp;
++	int ret, ep_fd;
++	struct kdbus_msg *msg;
++	struct kdbus_conn *ep_conn;
++	struct kdbus_conn *reader;
++	const char *name = "foo.bar.baz";
++	const char *epname = "foo";
++	char fake_ep[KDBUS_SYSNAME_MAX_LEN + 1] = {'\0'};
++
++	memset(fake_ep, 'X', sizeof(fake_ep) - 1);
++
++	/* Try to create a custom endpoint with a long name */
++	ret = create_endpoint(env->buspath, getuid(), fake_ep, 0);
++	ASSERT_RETURN(ret == -ENAMETOOLONG);
++
++	/* Try to create a custom endpoint with a different uid */
++	ret = create_endpoint(env->buspath, getuid() + 1, "foobar", 0);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* create a custom endpoint, and open a connection on it */
++	ep_fd = create_endpoint(env->buspath, getuid(), "foo", 0);
++	ASSERT_RETURN(ep_fd >= 0);
++
++	tmp = strdup(env->buspath);
++	ASSERT_RETURN(tmp);
++
++	ret = asprintf(&ep, "%s/%u-%s", dirname(tmp), getuid(), epname);
++	free(tmp);
++	ASSERT_RETURN(ret >= 0);
++
++	/* Register a connection that listen to broadcasts */
++	reader = kdbus_hello(ep, 0, NULL, 0);
++	ASSERT_RETURN(reader);
++
++	/* Register to kernel 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);
++
++	ret = install_name_add_match(reader, name);
++	ASSERT_RETURN(ret == 0);
++
++	/* Monitor connections are not supported on custom endpoints */
++	ep_conn = kdbus_hello(ep, KDBUS_HELLO_MONITOR, NULL, 0);
++	ASSERT_RETURN(!ep_conn && errno == EOPNOTSUPP);
++
++	ep_conn = kdbus_hello(ep, 0, NULL, 0);
++	ASSERT_RETURN(ep_conn);
++
++	/* Check that the reader got the IdAdd notification */
++	ret = kdbus_msg_recv(reader, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_ADD);
++	ASSERT_RETURN(msg->items[0].id_change.id == ep_conn->id);
++	kdbus_msg_free(msg);
++
++	/*
++	 * Add a name add match on the endpoint connection, acquire name from
++	 * the unfiltered connection, and make sure the filtered connection
++	 * did not get the notification on the name owner change. Also, the
++	 * endpoint connection may not be able to call conn_info, neither on
++	 * the name nor on the ID.
++	 */
++	ret = install_name_add_match(ep_conn, name);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_acquire(env->conn, name, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(ep_conn, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	ret = kdbus_conn_info(ep_conn, 0, name, 0, NULL);
++	ASSERT_RETURN(ret == -ESRCH);
++
++	ret = kdbus_conn_info(ep_conn, 0, "random.crappy.name", 0, NULL);
++	ASSERT_RETURN(ret == -ESRCH);
++
++	ret = kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL);
++	ASSERT_RETURN(ret == -ENXIO);
++
++	ret = kdbus_conn_info(ep_conn, 0x0fffffffffffffffULL, NULL, 0, NULL);
++	ASSERT_RETURN(ret == -ENXIO);
++
++	/* Check that the reader did not receive the name notification */
++	ret = kdbus_msg_recv(reader, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	/*
++	 * Release the name again, update the custom endpoint policy,
++	 * and try again. This time, the connection on the custom endpoint
++	 * should have gotten it.
++	 */
++	ret = kdbus_name_release(env->conn, name);
++	ASSERT_RETURN(ret == 0);
++
++	/* Check that the reader did not receive the name notification */
++	ret = kdbus_msg_recv(reader, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	ret = update_endpoint(ep_fd, name);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_acquire(env->conn, name, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(ep_conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_ADD);
++	ASSERT_RETURN(msg->items[0].name_change.old_id.id == 0);
++	ASSERT_RETURN(msg->items[0].name_change.new_id.id == env->conn->id);
++	ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
++	kdbus_msg_free(msg);
++
++	ret = kdbus_msg_recv(reader, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
++
++	kdbus_msg_free(msg);
++
++	ret = kdbus_conn_info(ep_conn, 0, name, 0, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* If we have privileges test custom endpoints */
++	ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * All uids/gids are mapped and we have the necessary caps
++	 */
++	if (ret && all_uids_gids_are_mapped()) {
++		ret = unpriv_test_custom_ep(env->buspath);
++		ASSERT_RETURN(ret == 0);
++	}
++
++	kdbus_conn_free(reader);
++	kdbus_conn_free(ep_conn);
++	close(ep_fd);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-fd.c b/tools/testing/selftests/kdbus/test-fd.c
+new file mode 100644
+index 0000000..2ae0f5a
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-fd.c
+@@ -0,0 +1,789 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <sys/types.h>
++#include <sys/mman.h>
++#include <sys/socket.h>
++#include <sys/wait.h>
++
++#include "kdbus-api.h"
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++#define KDBUS_MSG_MAX_ITEMS     128
++#define KDBUS_USER_MAX_CONN	256
++
++/* maximum number of inflight fds in a target queue per user */
++#define KDBUS_CONN_MAX_FDS_PER_USER	16
++
++/* maximum number of memfd items per message */
++#define KDBUS_MSG_MAX_MEMFD_ITEMS       16
++
++static int make_msg_payload_dbus(uint64_t src_id, uint64_t dst_id,
++				 uint64_t msg_size,
++				 struct kdbus_msg **msg_dbus)
++{
++	struct kdbus_msg *msg;
++
++	msg = malloc(msg_size);
++	ASSERT_RETURN_VAL(msg, -ENOMEM);
++
++	memset(msg, 0, msg_size);
++	msg->size = msg_size;
++	msg->src_id = src_id;
++	msg->dst_id = dst_id;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++
++	*msg_dbus = msg;
++
++	return 0;
++}
++
++static void make_item_memfds(struct kdbus_item *item,
++			     int *memfds, size_t memfd_size)
++{
++	size_t i;
++
++	for (i = 0; i < memfd_size; i++) {
++		item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
++		item->size = KDBUS_ITEM_HEADER_SIZE +
++			     sizeof(struct kdbus_memfd);
++		item->memfd.fd = memfds[i];
++		item->memfd.size = sizeof(uint64_t); /* const size */
++		item = KDBUS_ITEM_NEXT(item);
++	}
++}
++
++static void make_item_fds(struct kdbus_item *item,
++			  int *fd_array, size_t fd_size)
++{
++	size_t i;
++	item->type = KDBUS_ITEM_FDS;
++	item->size = KDBUS_ITEM_HEADER_SIZE + (sizeof(int) * fd_size);
++
++	for (i = 0; i < fd_size; i++)
++		item->fds[i] = fd_array[i];
++}
++
++static int memfd_write(const char *name, void *buf, size_t bufsize)
++{
++	ssize_t ret;
++	int memfd;
++
++	memfd = sys_memfd_create(name, 0);
++	ASSERT_RETURN_VAL(memfd >= 0, memfd);
++
++	ret = write(memfd, buf, bufsize);
++	ASSERT_RETURN_VAL(ret == (ssize_t)bufsize, -EAGAIN);
++
++	ret = sys_memfd_seal_set(memfd);
++	ASSERT_RETURN_VAL(ret == 0, -errno);
++
++	return memfd;
++}
++
++static int send_memfds(struct kdbus_conn *conn, uint64_t dst_id,
++		       int *memfds_array, size_t memfd_count)
++{
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_item *item;
++	struct kdbus_msg *msg;
++	uint64_t size;
++	int ret;
++
++	size = sizeof(struct kdbus_msg);
++	size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
++
++	if (dst_id == KDBUS_DST_ID_BROADCAST)
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64;
++
++	ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	item = msg->items;
++
++	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 = KDBUS_ITEM_NEXT(item);
++
++		msg->flags |= KDBUS_MSG_SIGNAL;
++	}
++
++	make_item_memfds(item, memfds_array, memfd_count);
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	ret = kdbus_cmd_send(conn->fd, &cmd);
++	if (ret < 0) {
++		kdbus_printf("error sending message: %d (%m)\n", ret);
++		return ret;
++	}
++
++	free(msg);
++	return 0;
++}
++
++static int send_fds(struct kdbus_conn *conn, uint64_t dst_id,
++		    int *fd_array, size_t fd_count)
++{
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_item *item;
++	struct kdbus_msg *msg;
++	uint64_t size;
++	int ret;
++
++	size = sizeof(struct kdbus_msg);
++	size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count);
++
++	if (dst_id == KDBUS_DST_ID_BROADCAST)
++		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64;
++
++	ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	item = msg->items;
++
++	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 = KDBUS_ITEM_NEXT(item);
++
++		msg->flags |= KDBUS_MSG_SIGNAL;
++	}
++
++	make_item_fds(item, fd_array, fd_count);
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	ret = kdbus_cmd_send(conn->fd, &cmd);
++	if (ret < 0) {
++		kdbus_printf("error sending message: %d (%m)\n", ret);
++		return ret;
++	}
++
++	free(msg);
++	return ret;
++}
++
++static int send_fds_memfds(struct kdbus_conn *conn, uint64_t dst_id,
++			   int *fds_array, size_t fd_count,
++			   int *memfds_array, size_t memfd_count)
++{
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_item *item;
++	struct kdbus_msg *msg;
++	uint64_t size;
++	int ret;
++
++	size = sizeof(struct kdbus_msg);
++	size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
++	size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count);
++
++	ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	item = msg->items;
++
++	make_item_fds(item, fds_array, fd_count);
++	item = KDBUS_ITEM_NEXT(item);
++	make_item_memfds(item, memfds_array, memfd_count);
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	ret = kdbus_cmd_send(conn->fd, &cmd);
++	if (ret < 0) {
++		kdbus_printf("error sending message: %d (%m)\n", ret);
++		return ret;
++	}
++
++	free(msg);
++	return ret;
++}
++
++/* Return the number of received fds */
++static unsigned int kdbus_item_get_nfds(struct kdbus_msg *msg)
++{
++	unsigned int fds = 0;
++	const struct kdbus_item *item;
++
++	KDBUS_ITEM_FOREACH(item, msg, items) {
++		switch (item->type) {
++		case KDBUS_ITEM_FDS: {
++			fds += (item->size - KDBUS_ITEM_HEADER_SIZE) /
++				sizeof(int);
++			break;
++		}
++
++		case KDBUS_ITEM_PAYLOAD_MEMFD:
++			fds++;
++			break;
++
++		default:
++			break;
++		}
++	}
++
++	return fds;
++}
++
++static struct kdbus_msg *
++get_kdbus_msg_with_fd(struct kdbus_conn *conn_src,
++		      uint64_t dst_id, uint64_t cookie, int fd)
++{
++	int ret;
++	uint64_t size;
++	struct kdbus_item *item;
++	struct kdbus_msg *msg;
++
++	size = sizeof(struct kdbus_msg);
++	if (fd >= 0)
++		size += KDBUS_ITEM_SIZE(sizeof(int));
++
++	ret = make_msg_payload_dbus(conn_src->id, dst_id, size, &msg);
++	ASSERT_RETURN_VAL(ret == 0, NULL);
++
++	msg->cookie = cookie;
++
++	if (fd >= 0) {
++		item = msg->items;
++
++		make_item_fds(item, (int *)&fd, 1);
++	}
++
++	return msg;
++}
++
++static int kdbus_test_no_fds(struct kdbus_test_env *env,
++			     int *fds, int *memfd)
++{
++	pid_t pid;
++	int ret, status;
++	uint64_t cookie;
++	int connfd1, connfd2;
++	struct kdbus_msg *msg, *msg_sync_reply;
++	struct kdbus_cmd_hello hello;
++	struct kdbus_conn *conn_src, *conn_dst, *conn_dummy;
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_cmd_free cmd_free = {};
++
++	conn_src = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_src);
++
++	connfd1 = open(env->buspath, O_RDWR|O_CLOEXEC);
++	ASSERT_RETURN(connfd1 >= 0);
++
++	connfd2 = open(env->buspath, O_RDWR|O_CLOEXEC);
++	ASSERT_RETURN(connfd2 >= 0);
++
++	/*
++	 * Create connections without KDBUS_HELLO_ACCEPT_FD
++	 * to test if send fd operations are blocked
++	 */
++	conn_dst = malloc(sizeof(*conn_dst));
++	ASSERT_RETURN(conn_dst);
++
++	conn_dummy = malloc(sizeof(*conn_dummy));
++	ASSERT_RETURN(conn_dummy);
++
++	memset(&hello, 0, sizeof(hello));
++	hello.size = sizeof(struct kdbus_cmd_hello);
++	hello.pool_size = POOL_SIZE;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++
++	ret = kdbus_cmd_hello(connfd1, &hello);
++	ASSERT_RETURN(ret == 0);
++
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.offset = hello.offset;
++	ret = kdbus_cmd_free(connfd1, &cmd_free);
++	ASSERT_RETURN(ret >= 0);
++
++	conn_dst->fd = connfd1;
++	conn_dst->id = hello.id;
++
++	memset(&hello, 0, sizeof(hello));
++	hello.size = sizeof(struct kdbus_cmd_hello);
++	hello.pool_size = POOL_SIZE;
++	hello.attach_flags_send = _KDBUS_ATTACH_ALL;
++
++	ret = kdbus_cmd_hello(connfd2, &hello);
++	ASSERT_RETURN(ret == 0);
++
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.offset = hello.offset;
++	ret = kdbus_cmd_free(connfd2, &cmd_free);
++	ASSERT_RETURN(ret >= 0);
++
++	conn_dummy->fd = connfd2;
++	conn_dummy->id = hello.id;
++
++	conn_dst->buf = mmap(NULL, POOL_SIZE, PROT_READ,
++			     MAP_SHARED, connfd1, 0);
++	ASSERT_RETURN(conn_dst->buf != MAP_FAILED);
++
++	conn_dummy->buf = mmap(NULL, POOL_SIZE, PROT_READ,
++			       MAP_SHARED, connfd2, 0);
++	ASSERT_RETURN(conn_dummy->buf != MAP_FAILED);
++
++	/*
++	 * Send fds to connection that do not accept fd passing
++	 */
++	ret = send_fds(conn_src, conn_dst->id, fds, 1);
++	ASSERT_RETURN(ret == -ECOMM);
++
++	/*
++	 * memfd are kdbus payload
++	 */
++	ret = send_memfds(conn_src, conn_dst->id, memfd, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv_poll(conn_dst, 100, NULL, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	cookie = time(NULL);
++
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, pid);
++
++	if (pid == 0) {
++		struct timespec now;
++
++		/*
++		 * A sync send/reply to a connection that do not
++		 * accept fds should fail if it contains an fd
++		 */
++		msg_sync_reply = get_kdbus_msg_with_fd(conn_dst,
++						       conn_dummy->id,
++						       cookie, fds[0]);
++		ASSERT_EXIT(msg_sync_reply);
++
++		ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
++		ASSERT_EXIT(ret == 0);
++
++		msg_sync_reply->timeout_ns = now.tv_sec * 1000000000ULL +
++					     now.tv_nsec + 100000000ULL;
++		msg_sync_reply->flags = KDBUS_MSG_EXPECT_REPLY;
++
++		memset(&cmd, 0, sizeof(cmd));
++		cmd.size = sizeof(cmd);
++		cmd.msg_address = (uintptr_t)msg_sync_reply;
++		cmd.flags = KDBUS_SEND_SYNC_REPLY;
++
++		ret = kdbus_cmd_send(conn_dst->fd, &cmd);
++		ASSERT_EXIT(ret == -ECOMM);
++
++		/*
++		 * Now send a normal message, but the sync reply
++		 * will fail since it contains an fd that the
++		 * original sender do not want.
++		 *
++		 * The original sender will fail with -ETIMEDOUT
++		 */
++		cookie++;
++		ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
++					  KDBUS_MSG_EXPECT_REPLY,
++					  5000000000ULL, 0, conn_src->id, -1);
++		ASSERT_EXIT(ret == -EREMOTEIO);
++
++		cookie++;
++		ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL);
++		ASSERT_EXIT(ret == 0);
++		ASSERT_EXIT(msg->cookie == cookie);
++
++		free(msg_sync_reply);
++		kdbus_msg_free(msg);
++
++		_exit(EXIT_SUCCESS);
++	}
++
++	ret = kdbus_msg_recv_poll(conn_dummy, 100, NULL, NULL);
++	ASSERT_RETURN(ret == -ETIMEDOUT);
++
++	cookie++;
++	ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++
++	/*
++	 * Try to reply with a kdbus connection handle, this should
++	 * fail with -EOPNOTSUPP
++	 */
++	msg_sync_reply = get_kdbus_msg_with_fd(conn_src,
++					       conn_dst->id,
++					       cookie, conn_dst->fd);
++	ASSERT_RETURN(msg_sync_reply);
++
++	msg_sync_reply->cookie_reply = cookie;
++
++	memset(&cmd, 0, sizeof(cmd));
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg_sync_reply;
++
++	ret = kdbus_cmd_send(conn_src->fd, &cmd);
++	ASSERT_RETURN(ret == -EOPNOTSUPP);
++
++	free(msg_sync_reply);
++
++	/*
++	 * Try to reply with a normal fd, this should fail even
++	 * if the response is a sync reply
++	 *
++	 * From the sender view we fail with -ECOMM
++	 */
++	msg_sync_reply = get_kdbus_msg_with_fd(conn_src,
++					       conn_dst->id,
++					       cookie, fds[0]);
++	ASSERT_RETURN(msg_sync_reply);
++
++	msg_sync_reply->cookie_reply = cookie;
++
++	memset(&cmd, 0, sizeof(cmd));
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg_sync_reply;
++
++	ret = kdbus_cmd_send(conn_src->fd, &cmd);
++	ASSERT_RETURN(ret == -ECOMM);
++
++	free(msg_sync_reply);
++
++	/*
++	 * Resend another normal message and check if the queue
++	 * is clear
++	 */
++	cookie++;
++	ret = kdbus_msg_send(conn_src, NULL, cookie, 0, 0, 0,
++			     conn_dst->id);
++	ASSERT_RETURN(ret == 0);
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	kdbus_conn_free(conn_dummy);
++	kdbus_conn_free(conn_dst);
++	kdbus_conn_free(conn_src);
++
++	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
++}
++
++static int kdbus_send_multiple_fds(struct kdbus_conn *conn_src,
++				   struct kdbus_conn *conn_dst)
++{
++	int ret, i;
++	unsigned int nfds;
++	int fds[KDBUS_CONN_MAX_FDS_PER_USER + 1];
++	int memfds[KDBUS_MSG_MAX_ITEMS + 1];
++	struct kdbus_msg *msg;
++	uint64_t dummy_value;
++
++	dummy_value = time(NULL);
++
++	for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) {
++		fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC);
++		ASSERT_RETURN_VAL(fds[i] >= 0, -errno);
++	}
++
++	/* Send KDBUS_CONN_MAX_FDS_PER_USER with one more fd */
++	ret = send_fds(conn_src, conn_dst->id, fds,
++		       KDBUS_CONN_MAX_FDS_PER_USER + 1);
++	ASSERT_RETURN(ret == -EMFILE);
++
++	/* Retry with the correct KDBUS_CONN_MAX_FDS_PER_USER */
++	ret = send_fds(conn_src, conn_dst->id, fds,
++		       KDBUS_CONN_MAX_FDS_PER_USER);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(conn_dst, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* Check we got the right number of fds */
++	nfds = kdbus_item_get_nfds(msg);
++	ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER);
++
++	kdbus_msg_free(msg);
++
++	for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++, dummy_value++) {
++		memfds[i] = memfd_write("memfd-name",
++					&dummy_value,
++					sizeof(dummy_value));
++		ASSERT_RETURN_VAL(memfds[i] >= 0, memfds[i]);
++	}
++
++	/* Send KDBUS_MSG_MAX_ITEMS with one more memfd */
++	ret = send_memfds(conn_src, conn_dst->id,
++			  memfds, KDBUS_MSG_MAX_ITEMS + 1);
++	ASSERT_RETURN(ret == -E2BIG);
++
++	ret = send_memfds(conn_src, conn_dst->id,
++			  memfds, KDBUS_MSG_MAX_MEMFD_ITEMS + 1);
++	ASSERT_RETURN(ret == -E2BIG);
++
++	/* Retry with the correct KDBUS_MSG_MAX_ITEMS */
++	ret = send_memfds(conn_src, conn_dst->id,
++			  memfds, KDBUS_MSG_MAX_MEMFD_ITEMS);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(conn_dst, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* Check we got the right number of fds */
++	nfds = kdbus_item_get_nfds(msg);
++	ASSERT_RETURN(nfds == KDBUS_MSG_MAX_MEMFD_ITEMS);
++
++	kdbus_msg_free(msg);
++
++
++	/*
++	 * Combine multiple KDBUS_CONN_MAX_FDS_PER_USER+1 fds and
++	 * 10 memfds
++	 */
++	ret = send_fds_memfds(conn_src, conn_dst->id,
++			      fds, KDBUS_CONN_MAX_FDS_PER_USER + 1,
++			      memfds, 10);
++	ASSERT_RETURN(ret == -EMFILE);
++
++	ret = kdbus_msg_recv(conn_dst, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	/*
++	 * Combine multiple KDBUS_CONN_MAX_FDS_PER_USER fds and
++	 * (128 - 1) + 1 memfds, all fds take one item, while each
++	 * memfd takes one item
++	 */
++	ret = send_fds_memfds(conn_src, conn_dst->id,
++			      fds, KDBUS_CONN_MAX_FDS_PER_USER,
++			      memfds, (KDBUS_MSG_MAX_ITEMS - 1) + 1);
++	ASSERT_RETURN(ret == -E2BIG);
++
++	ret = send_fds_memfds(conn_src, conn_dst->id,
++			      fds, KDBUS_CONN_MAX_FDS_PER_USER,
++			      memfds, KDBUS_MSG_MAX_MEMFD_ITEMS + 1);
++	ASSERT_RETURN(ret == -E2BIG);
++
++	ret = kdbus_msg_recv(conn_dst, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	/*
++	 * Send KDBUS_CONN_MAX_FDS_PER_USER fds +
++	 * KDBUS_MSG_MAX_MEMFD_ITEMS memfds
++	 */
++	ret = send_fds_memfds(conn_src, conn_dst->id,
++			      fds, KDBUS_CONN_MAX_FDS_PER_USER,
++			      memfds, KDBUS_MSG_MAX_MEMFD_ITEMS);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(conn_dst, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* Check we got the right number of fds */
++	nfds = kdbus_item_get_nfds(msg);
++	ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER +
++			      KDBUS_MSG_MAX_MEMFD_ITEMS);
++
++	kdbus_msg_free(msg);
++
++
++	/*
++	 * Re-send fds + memfds, close them, but do not receive them
++	 * and try to queue more
++	 */
++	ret = send_fds_memfds(conn_src, conn_dst->id,
++			      fds, KDBUS_CONN_MAX_FDS_PER_USER,
++			      memfds, KDBUS_MSG_MAX_MEMFD_ITEMS);
++	ASSERT_RETURN(ret == 0);
++
++	/* close old references and get a new ones */
++	for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) {
++		close(fds[i]);
++		fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC);
++		ASSERT_RETURN_VAL(fds[i] >= 0, -errno);
++	}
++
++	/* should fail since we have already fds in the queue */
++	ret = send_fds(conn_src, conn_dst->id, fds,
++		       KDBUS_CONN_MAX_FDS_PER_USER);
++	ASSERT_RETURN(ret == -EMFILE);
++
++	/* This should succeed */
++	ret = send_memfds(conn_src, conn_dst->id,
++			  memfds, KDBUS_MSG_MAX_MEMFD_ITEMS);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(conn_dst, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	nfds = kdbus_item_get_nfds(msg);
++	ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER +
++			      KDBUS_MSG_MAX_MEMFD_ITEMS);
++
++	kdbus_msg_free(msg);
++
++	ret = kdbus_msg_recv(conn_dst, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	nfds = kdbus_item_get_nfds(msg);
++	ASSERT_RETURN(nfds == KDBUS_MSG_MAX_MEMFD_ITEMS);
++
++	kdbus_msg_free(msg);
++
++	ret = kdbus_msg_recv(conn_dst, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++)
++		close(fds[i]);
++
++	for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++)
++		close(memfds[i]);
++
++	return 0;
++}
++
++int kdbus_test_fd_passing(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn_src, *conn_dst;
++	const char *str = "stackenblocken";
++	const struct kdbus_item *item;
++	struct kdbus_msg *msg;
++	unsigned int i;
++	uint64_t now;
++	int fds_conn[2];
++	int sock_pair[2];
++	int fds[2];
++	int memfd;
++	int ret;
++
++	now = (uint64_t) time(NULL);
++
++	/* create two connections */
++	conn_src = kdbus_hello(env->buspath, 0, NULL, 0);
++	conn_dst = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_src && conn_dst);
++
++	fds_conn[0] = conn_src->fd;
++	fds_conn[1] = conn_dst->fd;
++
++	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair);
++	ASSERT_RETURN(ret == 0);
++
++	/* Setup memfd */
++	memfd = memfd_write("memfd-name", &now, sizeof(now));
++	ASSERT_RETURN(memfd >= 0);
++
++	/* Setup pipes */
++	ret = pipe(fds);
++	ASSERT_RETURN(ret == 0);
++
++	i = write(fds[1], str, strlen(str));
++	ASSERT_RETURN(i == strlen(str));
++
++	/*
++	 * Try to ass the handle of a connection as message payload.
++	 * This must fail.
++	 */
++	ret = send_fds(conn_src, conn_dst->id, fds_conn, 2);
++	ASSERT_RETURN(ret == -ENOTSUP);
++
++	ret = send_fds(conn_dst, conn_src->id, fds_conn, 2);
++	ASSERT_RETURN(ret == -ENOTSUP);
++
++	ret = send_fds(conn_src, conn_dst->id, sock_pair, 2);
++	ASSERT_RETURN(ret == -ENOTSUP);
++
++	/*
++	 * Send fds and memfds to connection that do not accept fds
++	 */
++	ret = kdbus_test_no_fds(env, fds, (int *)&memfd);
++	ASSERT_RETURN(ret == 0);
++
++	/* Try to broadcast file descriptors. This must fail. */
++	ret = send_fds(conn_src, KDBUS_DST_ID_BROADCAST, fds, 1);
++	ASSERT_RETURN(ret == -ENOTUNIQ);
++
++	/* Try to broadcast memfd. This must succeed. */
++	ret = send_memfds(conn_src, KDBUS_DST_ID_BROADCAST, (int *)&memfd, 1);
++	ASSERT_RETURN(ret == 0);
++
++	/* Open code this loop */
++loop_send_fds:
++
++	/*
++	 * Send the read end of the pipe and close it.
++	 */
++	ret = send_fds(conn_src, conn_dst->id, fds, 1);
++	ASSERT_RETURN(ret == 0);
++	close(fds[0]);
++
++	ret = kdbus_msg_recv(conn_dst, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	KDBUS_ITEM_FOREACH(item, msg, items) {
++		if (item->type == KDBUS_ITEM_FDS) {
++			char tmp[14];
++			int nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) /
++					sizeof(int);
++			ASSERT_RETURN(nfds == 1);
++
++			i = read(item->fds[0], tmp, sizeof(tmp));
++			if (i != 0) {
++				ASSERT_RETURN(i == sizeof(tmp));
++				ASSERT_RETURN(memcmp(tmp, str, sizeof(tmp)) == 0);
++
++				/* Write EOF */
++				close(fds[1]);
++
++				/*
++				 * Resend the read end of the pipe,
++				 * the receiver still holds a reference
++				 * to it...
++				 */
++				goto loop_send_fds;
++			}
++
++			/* Got EOF */
++
++			/*
++			 * Close the last reference to the read end
++			 * of the pipe, other references are
++			 * automatically closed just after send.
++			 */
++			close(item->fds[0]);
++		}
++	}
++
++	/*
++	 * Try to resend the read end of the pipe. Must fail with
++	 * -EBADF since both the sender and receiver closed their
++	 * references to it. We assume the above since sender and
++	 * receiver are on the same process.
++	 */
++	ret = send_fds(conn_src, conn_dst->id, fds, 1);
++	ASSERT_RETURN(ret == -EBADF);
++
++	/* Then we clear out received any data... */
++	kdbus_msg_free(msg);
++
++	ret = kdbus_send_multiple_fds(conn_src, conn_dst);
++	ASSERT_RETURN(ret == 0);
++
++	close(sock_pair[0]);
++	close(sock_pair[1]);
++	close(memfd);
++
++	kdbus_conn_free(conn_src);
++	kdbus_conn_free(conn_dst);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-free.c b/tools/testing/selftests/kdbus/test-free.c
+new file mode 100644
+index 0000000..f666da3
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-free.c
+@@ -0,0 +1,64 @@
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <stdbool.h>
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++static int sample_ioctl_call(struct kdbus_test_env *env)
++{
++	int ret;
++	struct kdbus_cmd_list cmd_list = {
++		.flags = KDBUS_LIST_QUEUED,
++		.size = sizeof(cmd_list),
++	};
++
++	ret = kdbus_cmd_list(env->conn->fd, &cmd_list);
++	ASSERT_RETURN(ret == 0);
++
++	/* DON'T FREE THIS SLICE OF MEMORY! */
++
++	return TEST_OK;
++}
++
++int kdbus_test_free(struct kdbus_test_env *env)
++{
++	int ret;
++	struct kdbus_cmd_free cmd_free = {};
++
++	/* free an unallocated buffer */
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.flags = 0;
++	cmd_free.offset = 0;
++	ret = kdbus_cmd_free(env->conn->fd, &cmd_free);
++	ASSERT_RETURN(ret == -ENXIO);
++
++	/* free a buffer out of the pool's bounds */
++	cmd_free.size = sizeof(cmd_free);
++	cmd_free.offset = POOL_SIZE + 1;
++	ret = kdbus_cmd_free(env->conn->fd, &cmd_free);
++	ASSERT_RETURN(ret == -ENXIO);
++
++	/*
++	 * The user application is responsible for freeing the allocated
++	 * memory with the KDBUS_CMD_FREE ioctl, so let's test what happens
++	 * if we forget about it.
++	 */
++
++	ret = sample_ioctl_call(env);
++	ASSERT_RETURN(ret == 0);
++
++	ret = sample_ioctl_call(env);
++	ASSERT_RETURN(ret == 0);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-match.c b/tools/testing/selftests/kdbus/test-match.c
+new file mode 100644
+index 0000000..2360dc1
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-match.c
+@@ -0,0 +1,441 @@
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <stdbool.h>
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++int kdbus_test_match_id_add(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_id_change chg;
++		} item;
++	} buf;
++	struct kdbus_conn *conn;
++	struct kdbus_msg *msg;
++	int ret;
++
++	memset(&buf, 0, sizeof(buf));
++
++	buf.cmd.size = sizeof(buf);
++	buf.cmd.cookie = 0xdeafbeefdeaddead;
++	buf.item.size = sizeof(buf.item);
++	buf.item.type = KDBUS_ITEM_ID_ADD;
++	buf.item.chg.id = KDBUS_MATCH_ID_ANY;
++
++	/* match on id add */
++	ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	/* create 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++
++	/* 1st connection should have received a notification */
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_ADD);
++	ASSERT_RETURN(msg->items[0].id_change.id == conn->id);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++int kdbus_test_match_id_remove(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_id_change chg;
++		} item;
++	} buf;
++	struct kdbus_conn *conn;
++	struct kdbus_msg *msg;
++	size_t id;
++	int ret;
++
++	/* create 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++	id = conn->id;
++
++	memset(&buf, 0, sizeof(buf));
++	buf.cmd.size = sizeof(buf);
++	buf.cmd.cookie = 0xdeafbeefdeaddead;
++	buf.item.size = sizeof(buf.item);
++	buf.item.type = KDBUS_ITEM_ID_REMOVE;
++	buf.item.chg.id = id;
++
++	/* register match on 2nd connection */
++	ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	/* remove 2nd connection again */
++	kdbus_conn_free(conn);
++
++	/* 1st connection should have received a notification */
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE);
++	ASSERT_RETURN(msg->items[0].id_change.id == id);
++
++	return TEST_OK;
++}
++
++int kdbus_test_match_replace(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_id_change chg;
++		} item;
++	} buf;
++	struct kdbus_conn *conn;
++	struct kdbus_msg *msg;
++	size_t id;
++	int ret;
++
++	/* add a match to id_add */
++	ASSERT_RETURN(kdbus_test_match_id_add(env) == TEST_OK);
++
++	/* do a replace of the match from id_add to id_remove */
++	memset(&buf, 0, sizeof(buf));
++
++	buf.cmd.size = sizeof(buf);
++	buf.cmd.cookie = 0xdeafbeefdeaddead;
++	buf.cmd.flags = KDBUS_MATCH_REPLACE;
++	buf.item.size = sizeof(buf.item);
++	buf.item.type = KDBUS_ITEM_ID_REMOVE;
++	buf.item.chg.id = KDBUS_MATCH_ID_ANY;
++
++	ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
++
++	/* create 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++	id = conn->id;
++
++	/* 1st connection should _not_ have received a notification */
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret != 0);
++
++	/* remove 2nd connection */
++	kdbus_conn_free(conn);
++
++	/* 1st connection should _now_ have received a notification */
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE);
++	ASSERT_RETURN(msg->items[0].id_change.id == id);
++
++	return TEST_OK;
++}
++
++int kdbus_test_match_name_add(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_name_change chg;
++		} item;
++		char name[64];
++	} buf;
++	struct kdbus_msg *msg;
++	char *name;
++	int ret;
++
++	name = "foo.bla.blaz";
++
++	/* install the match rule */
++	memset(&buf, 0, sizeof(buf));
++	buf.item.type = KDBUS_ITEM_NAME_ADD;
++	buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
++	buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
++	strncpy(buf.name, name, sizeof(buf.name) - 1);
++	buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
++	buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
++
++	ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	/* acquire the name */
++	ret = kdbus_name_acquire(env->conn, name, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* we should have received a notification */
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_ADD);
++	ASSERT_RETURN(msg->items[0].name_change.old_id.id == 0);
++	ASSERT_RETURN(msg->items[0].name_change.new_id.id == env->conn->id);
++	ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
++
++	return TEST_OK;
++}
++
++int kdbus_test_match_name_remove(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_name_change chg;
++		} item;
++		char name[64];
++	} buf;
++	struct kdbus_msg *msg;
++	char *name;
++	int ret;
++
++	name = "foo.bla.blaz";
++
++	/* acquire the name */
++	ret = kdbus_name_acquire(env->conn, name, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* install the match rule */
++	memset(&buf, 0, sizeof(buf));
++	buf.item.type = KDBUS_ITEM_NAME_REMOVE;
++	buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
++	buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
++	strncpy(buf.name, name, sizeof(buf.name) - 1);
++	buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
++	buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
++
++	ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	/* release the name again */
++	kdbus_name_release(env->conn, name);
++	ASSERT_RETURN(ret == 0);
++
++	/* we should have received a notification */
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_REMOVE);
++	ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id);
++	ASSERT_RETURN(msg->items[0].name_change.new_id.id == 0);
++	ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
++
++	return TEST_OK;
++}
++
++int kdbus_test_match_name_change(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			struct kdbus_notify_name_change chg;
++		} item;
++		char name[64];
++	} buf;
++	struct kdbus_conn *conn;
++	struct kdbus_msg *msg;
++	uint64_t flags;
++	char *name = "foo.bla.baz";
++	int ret;
++
++	/* acquire the name */
++	ret = kdbus_name_acquire(env->conn, name, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* install the match rule */
++	memset(&buf, 0, sizeof(buf));
++	buf.item.type = KDBUS_ITEM_NAME_CHANGE;
++	buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
++	buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
++	strncpy(buf.name, name, sizeof(buf.name) - 1);
++	buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
++	buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
++
++	ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	/* create a 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++
++	/* allow the new connection to own the same name */
++	/* queue the 2nd connection as waiting owner */
++	flags = KDBUS_NAME_QUEUE;
++	ret = kdbus_name_acquire(conn, name, &flags);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE);
++
++	/* release name from 1st connection */
++	ret = kdbus_name_release(env->conn, name);
++	ASSERT_RETURN(ret == 0);
++
++	/* we should have received a notification */
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_CHANGE);
++	ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id);
++	ASSERT_RETURN(msg->items[0].name_change.new_id.id == conn->id);
++	ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++static int send_bloom_filter(const struct kdbus_conn *conn,
++			     uint64_t cookie,
++			     const uint8_t *filter,
++			     size_t filter_size,
++			     uint64_t filter_generation)
++{
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_msg *msg;
++	struct kdbus_item *item;
++	uint64_t size;
++	int ret;
++
++	size = sizeof(struct kdbus_msg);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + filter_size;
++
++	msg = alloca(size);
++
++	memset(msg, 0, size);
++	msg->size = size;
++	msg->src_id = conn->id;
++	msg->dst_id = KDBUS_DST_ID_BROADCAST;
++	msg->flags = KDBUS_MSG_SIGNAL;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++	msg->cookie = cookie;
++
++	item = msg->items;
++	item->type = KDBUS_ITEM_BLOOM_FILTER;
++	item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) +
++				filter_size;
++
++	item->bloom_filter.generation = filter_generation;
++	memcpy(item->bloom_filter.data, filter, filter_size);
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	ret = kdbus_cmd_send(conn->fd, &cmd);
++	if (ret < 0) {
++		kdbus_printf("error sending message: %d (%m)\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++int kdbus_test_match_bloom(struct kdbus_test_env *env)
++{
++	struct {
++		struct kdbus_cmd_match cmd;
++		struct {
++			uint64_t size;
++			uint64_t type;
++			uint8_t data_gen0[64];
++			uint8_t data_gen1[64];
++		} item;
++	} buf;
++	struct kdbus_conn *conn;
++	struct kdbus_msg *msg;
++	uint64_t cookie = 0xf000f00f;
++	uint8_t filter[64];
++	int ret;
++
++	/* install the match rule */
++	memset(&buf, 0, sizeof(buf));
++	buf.cmd.size = sizeof(buf);
++
++	buf.item.size = sizeof(buf.item);
++	buf.item.type = KDBUS_ITEM_BLOOM_MASK;
++	buf.item.data_gen0[0] = 0x55;
++	buf.item.data_gen0[63] = 0x80;
++
++	buf.item.data_gen1[1] = 0xaa;
++	buf.item.data_gen1[9] = 0x02;
++
++	ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
++	ASSERT_RETURN(ret == 0);
++
++	/* create a 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++
++	/* a message with a 0'ed out filter must not reach the other peer */
++	memset(filter, 0, sizeof(filter));
++	ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	/* now set the filter to the connection's mask and expect success */
++	filter[0] = 0x55;
++	filter[63] = 0x80;
++	ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	/* broaden the filter and try again. this should also succeed. */
++	filter[0] = 0xff;
++	filter[8] = 0xff;
++	filter[63] = 0xff;
++	ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	/* the same filter must not match against bloom generation 1 */
++	ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	/* set a different filter and try again */
++	filter[1] = 0xaa;
++	filter[9] = 0x02;
++	ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(env->conn, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c
+new file mode 100644
+index 0000000..563dc85
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-message.c
+@@ -0,0 +1,734 @@
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <time.h>
++#include <stdbool.h>
++#include <sys/eventfd.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++/* maximum number of queued messages from the same individual user */
++#define KDBUS_CONN_MAX_MSGS			256
++
++/* maximum number of queued requests waiting for a reply */
++#define KDBUS_CONN_MAX_REQUESTS_PENDING		128
++
++/* maximum message payload size */
++#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE		(2 * 1024UL * 1024UL)
++
++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 get our own broadcasts */
++	ret = kdbus_msg_recv(sender, &msg, &offset);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++
++	/* ... 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);
++
++	/* Msgs that expect a reply must have timeout and cookie */
++	ret = kdbus_msg_send(sender, NULL, 0, KDBUS_MSG_EXPECT_REPLY,
++			     0, 0, conn->id);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* Faked replies with a valid reply cookie are rejected */
++	ret = kdbus_msg_send_reply(conn, time(NULL) ^ cookie, sender->id);
++	ASSERT_RETURN(ret == -EBADSLT);
++
++	ret = kdbus_free(conn, offset);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_conn_free(sender);
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++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 = kdbus_cmd_recv(conn->fd, &recv);
++	if (ret < 0) {
++		kdbus_printf("error receiving message: %d (%m)\n", -errno);
++		return ret;
++	}
++
++	msg = (struct kdbus_msg *)(conn->buf + recv.msg.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.msg.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) == -EAGAIN);
++	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;
++	struct kdbus_conn *conn;
++	struct kdbus_conn *reader;
++	struct kdbus_msg *msg = NULL;
++	struct kdbus_cmd_recv recv = { .size = sizeof(recv) };
++
++	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 with kernel notfications,
++	 * but as a user we still have room to push our messages.
++	 */
++	ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, 0, reader->id);
++	ASSERT_RETURN(ret == 0);
++
++	/* 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);
++
++	/*
++	 * We lost only 3 packets since only signal msgs are
++	 * accounted. The connection ID add/remove notification
++	 */
++	ret = kdbus_cmd_recv(reader->fd, &recv);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS);
++	ASSERT_RETURN(recv.dropped_msgs == 3);
++
++	msg = (struct kdbus_msg *)(reader->buf + recv.msg.offset);
++	kdbus_msg_free(msg);
++
++	/* Read our queue */
++	for (i = 0; i < KDBUS_CONN_MAX_MSGS - 1; i++) {
++		memset(&recv, 0, sizeof(recv));
++		recv.size = sizeof(recv);
++
++		ret = kdbus_cmd_recv(reader->fd, &recv);
++		ASSERT_RETURN(ret == 0);
++		ASSERT_RETURN(!(recv.return_flags &
++			        KDBUS_RECV_RETURN_DROPPED_MSGS));
++
++		msg = (struct kdbus_msg *)(reader->buf + recv.msg.offset);
++		kdbus_msg_free(msg);
++	}
++
++	ret = kdbus_msg_recv(reader, NULL, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(reader, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	kdbus_conn_free(reader);
++
++	return 0;
++}
++
++/* Return the number of message successfully sent */
++static int kdbus_fill_conn_queue(struct kdbus_conn *conn_src,
++				 uint64_t dst_id,
++				 unsigned int max_msgs)
++{
++	unsigned int i;
++	uint64_t cookie = 0;
++	size_t size;
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_msg *msg;
++	int ret;
++
++	size = sizeof(struct kdbus_msg);
++	msg = malloc(size);
++	ASSERT_RETURN_VAL(msg, -ENOMEM);
++
++	memset(msg, 0, size);
++	msg->size = size;
++	msg->src_id = conn_src->id;
++	msg->dst_id = dst_id;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	for (i = 0; i < max_msgs; i++) {
++		msg->cookie = cookie++;
++		ret = kdbus_cmd_send(conn_src->fd, &cmd);
++		if (ret < 0)
++			break;
++	}
++
++	free(msg);
++
++	return i;
++}
++
++static int kdbus_test_activator_quota(struct kdbus_test_env *env)
++{
++	int ret;
++	unsigned int i;
++	unsigned int activator_msgs_count = 0;
++	uint64_t cookie = time(NULL);
++	struct kdbus_conn *conn;
++	struct kdbus_conn *sender;
++	struct kdbus_conn *activator;
++	struct kdbus_msg *msg;
++	uint64_t flags = KDBUS_NAME_REPLACE_EXISTING;
++	struct kdbus_cmd_recv recv = { .size = sizeof(recv) };
++	struct kdbus_policy_access access = {
++		.type = KDBUS_POLICY_ACCESS_USER,
++		.id = geteuid(),
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	activator = kdbus_hello_activator(env->buspath, "foo.test.activator",
++					  &access, 1);
++	ASSERT_RETURN(activator);
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	sender = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn || sender);
++
++	ret = kdbus_list(sender, KDBUS_LIST_NAMES |
++				 KDBUS_LIST_UNIQUE |
++				 KDBUS_LIST_ACTIVATORS |
++				 KDBUS_LIST_QUEUED);
++	ASSERT_RETURN(ret == 0);
++
++	for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) {
++		ret = kdbus_msg_send(sender, "foo.test.activator",
++				     cookie++, 0, 0, 0,
++				     KDBUS_DST_ID_NAME);
++		if (ret < 0)
++			break;
++		activator_msgs_count++;
++	}
++
++	/* we must have at least sent one message */
++	ASSERT_RETURN_VAL(i > 0, -errno);
++	ASSERT_RETURN(ret == -ENOBUFS);
++
++	/* Good, activator queue is full now */
++
++	/* ENXIO on direct send (activators can never be addressed by ID) */
++	ret = kdbus_msg_send(conn, NULL, cookie++, 0, 0, 0, activator->id);
++	ASSERT_RETURN(ret == -ENXIO);
++
++	/* can't queue more */
++	ret = kdbus_msg_send(conn, "foo.test.activator", cookie++,
++			     0, 0, 0, KDBUS_DST_ID_NAME);
++	ASSERT_RETURN(ret == -ENOBUFS);
++
++	/* no match installed, so the broadcast will not inc dropped_msgs */
++	ret = kdbus_msg_send(sender, NULL, cookie++, 0, 0, 0,
++			     KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++	/* Check activator queue */
++	ret = kdbus_cmd_recv(activator->fd, &recv);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(recv.dropped_msgs == 0);
++
++	activator_msgs_count--;
++
++	msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset);
++	kdbus_msg_free(msg);
++
++
++	/* Stage 1) of test check the pool memory quota */
++
++	/* Consume the connection pool memory */
++	for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) {
++		ret = kdbus_msg_send(sender, NULL,
++				     cookie++, 0, 0, 0, conn->id);
++		if (ret < 0)
++			break;
++	}
++
++	/* consume one message, so later at least one can be moved */
++	memset(&recv, 0, sizeof(recv));
++	recv.size = sizeof(recv);
++	ret = kdbus_cmd_recv(conn->fd, &recv);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(recv.dropped_msgs == 0);
++	msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset);
++	kdbus_msg_free(msg);
++
++	/* Try to acquire the name now */
++	ret = kdbus_name_acquire(conn, "foo.test.activator", &flags);
++	ASSERT_RETURN(ret == 0);
++
++	/* try to read messages and see if we have lost some */
++	memset(&recv, 0, sizeof(recv));
++	recv.size = sizeof(recv);
++	ret = kdbus_cmd_recv(conn->fd, &recv);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(recv.dropped_msgs != 0);
++
++	/* number of dropped msgs < received ones (at least one was moved) */
++	ASSERT_RETURN(recv.dropped_msgs < activator_msgs_count);
++
++	/* Deduct the number of dropped msgs from the activator msgs */
++	activator_msgs_count -= recv.dropped_msgs;
++
++	msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset);
++	kdbus_msg_free(msg);
++
++	/*
++	 * Release the name and hand it back to activator, now
++	 * we should have 'activator_msgs_count' msgs again in
++	 * the activator queue
++	 */
++	ret = kdbus_name_release(conn, "foo.test.activator");
++	ASSERT_RETURN(ret == 0);
++
++	/* make sure that we got our previous activator msgs */
++	ret = kdbus_msg_recv(activator, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->src_id == sender->id);
++
++	activator_msgs_count--;
++
++	kdbus_msg_free(msg);
++
++
++	/* Stage 2) of test check max message quota */
++
++	/* Empty conn queue */
++	for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) {
++		ret = kdbus_msg_recv(conn, NULL, NULL);
++		if (ret == -EAGAIN)
++			break;
++	}
++
++	/* fill queue with max msgs quota */
++	ret = kdbus_fill_conn_queue(sender, conn->id, KDBUS_CONN_MAX_MSGS);
++	ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS);
++
++	/* This one is lost but it is not accounted */
++	ret = kdbus_msg_send(sender, NULL,
++			     cookie++, 0, 0, 0, conn->id);
++	ASSERT_RETURN(ret == -ENOBUFS);
++
++	/* Acquire the name again */
++	ret = kdbus_name_acquire(conn, "foo.test.activator", &flags);
++	ASSERT_RETURN(ret == 0);
++
++	memset(&recv, 0, sizeof(recv));
++	recv.size = sizeof(recv);
++
++	/*
++	 * Try to read messages and make sure that we have lost all
++	 * the activator messages due to quota checks. Our queue is
++	 * already full.
++	 */
++	ret = kdbus_cmd_recv(conn->fd, &recv);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(recv.dropped_msgs == activator_msgs_count);
++
++	msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset);
++	kdbus_msg_free(msg);
++
++	kdbus_conn_free(sender);
++	kdbus_conn_free(conn);
++	kdbus_conn_free(activator);
++
++	return 0;
++}
++
++static int kdbus_test_expected_reply_quota(struct kdbus_test_env *env)
++{
++	int ret;
++	unsigned int i, n;
++	unsigned int count;
++	uint64_t cookie = 0x1234abcd5678eeff;
++	struct kdbus_conn *conn;
++	struct kdbus_conn *connections[9];
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	for (i = 0; i < 9; i++) {
++		connections[i] = kdbus_hello(env->buspath, 0, NULL, 0);
++		ASSERT_RETURN(connections[i]);
++	}
++
++	count = 0;
++	/* Send 16 messages to 8 different connections */
++	for (i = 0; i < 8; i++) {
++		for (n = 0; n < 16; n++) {
++			ret = kdbus_msg_send(conn, NULL, cookie++,
++					     KDBUS_MSG_EXPECT_REPLY,
++					     100000000ULL, 0,
++					     connections[i]->id);
++			if (ret < 0)
++				break;
++
++			count++;
++		}
++	}
++
++	/*
++	 * We should have queued at least
++	 * KDBUS_CONN_MAX_REQUESTS_PENDING method call
++	 */
++	ASSERT_RETURN(count == KDBUS_CONN_MAX_REQUESTS_PENDING);
++
++	/*
++	 * Now try to send a message to the last connection,
++	 * if we have reached KDBUS_CONN_MAX_REQUESTS_PENDING
++	 * no further requests are allowed
++	 */
++	ret = kdbus_msg_send(conn, NULL, cookie++, KDBUS_MSG_EXPECT_REPLY,
++			     1000000000ULL, 0, connections[8]->id);
++	ASSERT_RETURN(ret == -EMLINK);
++
++	for (i = 0; i < 9; i++)
++		kdbus_conn_free(connections[i]);
++
++	kdbus_conn_free(conn);
++
++	return 0;
++}
++
++int kdbus_test_pool_quota(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *a, *b, *c;
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_item *item;
++	struct kdbus_msg *recv_msg;
++	struct kdbus_msg *msg;
++	uint64_t cookie = time(NULL);
++	uint64_t size;
++	unsigned int i;
++	char *payload;
++	int ret;
++
++	/* just a guard */
++	if (POOL_SIZE <= KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE ||
++	    POOL_SIZE % KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE != 0)
++		return 0;
++
++	payload = calloc(KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE, sizeof(char));
++	ASSERT_RETURN_VAL(payload, -ENOMEM);
++
++	a = kdbus_hello(env->buspath, 0, NULL, 0);
++	b = kdbus_hello(env->buspath, 0, NULL, 0);
++	c = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(a && b && c);
++
++	size = sizeof(struct kdbus_msg);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
++
++	msg = malloc(size);
++	ASSERT_RETURN_VAL(msg, -ENOMEM);
++
++	memset(msg, 0, size);
++	msg->size = size;
++	msg->src_id = a->id;
++	msg->dst_id = c->id;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++
++	item = msg->items;
++	item->type = KDBUS_ITEM_PAYLOAD_VEC;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
++	item->vec.address = (uintptr_t)payload;
++	item->vec.size = KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE;
++	item = KDBUS_ITEM_NEXT(item);
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	/*
++	 * Send 2097248 bytes, a user is only allowed to get 33% of half of
++	 * the free space of the pool, the already used space is
++	 * accounted as free space
++	 */
++	size += KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE;
++	for (i = size; i < (POOL_SIZE / 2 / 3); i += size) {
++		msg->cookie = cookie++;
++
++		ret = kdbus_cmd_send(a->fd, &cmd);
++		ASSERT_RETURN_VAL(ret == 0, ret);
++	}
++
++	/* Try to get more than 33% */
++	msg->cookie = cookie++;
++	ret = kdbus_cmd_send(a->fd, &cmd);
++	ASSERT_RETURN(ret == -ENOBUFS);
++
++	/* We still can pass small messages */
++	ret = kdbus_msg_send(b, NULL, cookie++, 0, 0, 0, c->id);
++	ASSERT_RETURN(ret == 0);
++
++	for (i = size; i < (POOL_SIZE / 2 / 3); i += size) {
++		ret = kdbus_msg_recv(c, &recv_msg, NULL);
++		ASSERT_RETURN(ret == 0);
++		ASSERT_RETURN(recv_msg->src_id == a->id);
++
++		kdbus_msg_free(recv_msg);
++	}
++
++	ret = kdbus_msg_recv(c, &recv_msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(recv_msg->src_id == b->id);
++
++	kdbus_msg_free(recv_msg);
++
++	ret = kdbus_msg_recv(c, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	free(msg);
++	free(payload);
++
++	kdbus_conn_free(c);
++	kdbus_conn_free(b);
++	kdbus_conn_free(a);
++
++	return 0;
++}
++
++int kdbus_test_message_quota(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *a, *b;
++	uint64_t cookie = 0;
++	int ret;
++	int i;
++
++	ret = kdbus_test_activator_quota(env);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_test_notify_kernel_quota(env);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_test_pool_quota(env);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_test_expected_reply_quota(env);
++	ASSERT_RETURN(ret == 0);
++
++	a = kdbus_hello(env->buspath, 0, NULL, 0);
++	b = kdbus_hello(env->buspath, 0, NULL, 0);
++
++	ret = kdbus_fill_conn_queue(b, a->id, KDBUS_CONN_MAX_MSGS);
++	ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS);
++
++	ret = kdbus_msg_send(b, NULL, ++cookie, 0, 0, 0, a->id);
++	ASSERT_RETURN(ret == -ENOBUFS);
++
++	for (i = 0; i < KDBUS_CONN_MAX_MSGS; ++i) {
++		ret = kdbus_msg_recv(a, NULL, NULL);
++		ASSERT_RETURN(ret == 0);
++	}
++
++	ret = kdbus_msg_recv(a, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	ret = kdbus_fill_conn_queue(b, a->id, KDBUS_CONN_MAX_MSGS + 1);
++	ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS);
++
++	ret = kdbus_msg_send(b, NULL, ++cookie, 0, 0, 0, a->id);
++	ASSERT_RETURN(ret == -ENOBUFS);
++
++	kdbus_conn_free(a);
++	kdbus_conn_free(b);
++
++	return TEST_OK;
++}
++
++int kdbus_test_memory_access(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *a, *b;
++	struct kdbus_cmd_send cmd = {};
++	struct kdbus_item *item;
++	struct kdbus_msg *msg;
++	uint64_t test_addr = 0;
++	char line[256];
++	uint64_t size;
++	FILE *f;
++	int ret;
++
++	/*
++	 * Search in /proc/kallsyms for the address of a kernel symbol that
++	 * should always be there, regardless of the config. Use that address
++	 * in a PAYLOAD_VEC item and make sure it's inaccessible.
++	 */
++
++	f = fopen("/proc/kallsyms", "r");
++	if (!f)
++		return TEST_SKIP;
++
++	while (fgets(line, sizeof(line), f)) {
++		char *s = line;
++
++		if (!strsep(&s, " "))
++			continue;
++
++		if (!strsep(&s, " "))
++			continue;
++
++		if (!strncmp(s, "mutex_lock", 10)) {
++			test_addr = strtoull(line, NULL, 16);
++			break;
++		}
++	}
++
++	fclose(f);
++
++	if (!test_addr)
++		return TEST_SKIP;
++
++	a = kdbus_hello(env->buspath, 0, NULL, 0);
++	b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(a && b);
++
++	size = sizeof(struct kdbus_msg);
++	size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
++
++	msg = alloca(size);
++	ASSERT_RETURN_VAL(msg, -ENOMEM);
++
++	memset(msg, 0, size);
++	msg->size = size;
++	msg->src_id = a->id;
++	msg->dst_id = b->id;
++	msg->payload_type = KDBUS_PAYLOAD_DBUS;
++
++	item = msg->items;
++	item->type = KDBUS_ITEM_PAYLOAD_VEC;
++	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
++	item->vec.address = test_addr;
++	item->vec.size = sizeof(void*);
++	item = KDBUS_ITEM_NEXT(item);
++
++	cmd.size = sizeof(cmd);
++	cmd.msg_address = (uintptr_t)msg;
++
++	ret = kdbus_cmd_send(a->fd, &cmd);
++	ASSERT_RETURN(ret == -EFAULT);
++
++	kdbus_conn_free(b);
++	kdbus_conn_free(a);
++
++	return 0;
++}
+diff --git a/tools/testing/selftests/kdbus/test-metadata-ns.c b/tools/testing/selftests/kdbus/test-metadata-ns.c
+new file mode 100644
+index 0000000..1f6edc0
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-metadata-ns.c
+@@ -0,0 +1,500 @@
++/*
++ * Test metadata in new namespaces. Even if our tests can run
++ * in a namespaced setup, this test is necessary so we can inspect
++ * metadata on the same kdbusfs but between multiple namespaces
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <sched.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <signal.h>
++#include <sys/wait.h>
++#include <sys/prctl.h>
++#include <sys/eventfd.h>
++#include <sys/syscall.h>
++#include <sys/capability.h>
++#include <linux/sched.h>
++
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++static const struct kdbus_creds privileged_creds = {};
++
++static const struct kdbus_creds unmapped_creds = {
++	.uid	= UNPRIV_UID,
++	.euid	= UNPRIV_UID,
++	.suid	= UNPRIV_UID,
++	.fsuid	= UNPRIV_UID,
++	.gid	= UNPRIV_GID,
++	.egid	= UNPRIV_GID,
++	.sgid	= UNPRIV_GID,
++	.fsgid	= UNPRIV_GID,
++};
++
++static const struct kdbus_pids unmapped_pids = {};
++
++/* Get only the first item */
++static struct kdbus_item *kdbus_get_item(struct kdbus_msg *msg,
++					 uint64_t type)
++{
++	struct kdbus_item *item;
++
++	KDBUS_ITEM_FOREACH(item, msg, items)
++		if (item->type == type)
++			return item;
++
++	return NULL;
++}
++
++static int kdbus_match_kdbus_creds(struct kdbus_msg *msg,
++				   const struct kdbus_creds *expected_creds)
++{
++	struct kdbus_item *item;
++
++	item = kdbus_get_item(msg, KDBUS_ITEM_CREDS);
++	ASSERT_RETURN(item);
++
++	ASSERT_RETURN(memcmp(&item->creds, expected_creds,
++			     sizeof(struct kdbus_creds)) == 0);
++
++	return 0;
++}
++
++static int kdbus_match_kdbus_pids(struct kdbus_msg *msg,
++				  const struct kdbus_pids *expected_pids)
++{
++	struct kdbus_item *item;
++
++	item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
++	ASSERT_RETURN(item);
++
++	ASSERT_RETURN(memcmp(&item->pids, expected_pids,
++			     sizeof(struct kdbus_pids)) == 0);
++
++	return 0;
++}
++
++static int __kdbus_clone_userns_test(const char *bus,
++				     struct kdbus_conn *conn,
++				     uint64_t grandpa_pid,
++				     int signal_fd)
++{
++	int clone_ret;
++	int ret;
++	struct kdbus_msg *msg = NULL;
++	const struct kdbus_item *item;
++	uint64_t cookie = time(NULL) ^ 0xdeadbeef;
++	struct kdbus_conn *unpriv_conn = NULL;
++	struct kdbus_pids parent_pids = {
++		.pid = getppid(),
++		.tid = getppid(),
++		.ppid = grandpa_pid,
++	};
++
++	ret = drop_privileges(UNPRIV_UID, UNPRIV_GID);
++	ASSERT_EXIT(ret == 0);
++
++	unpriv_conn = kdbus_hello(bus, 0, NULL, 0);
++	ASSERT_EXIT(unpriv_conn);
++
++	ret = kdbus_add_match_empty(unpriv_conn);
++	ASSERT_EXIT(ret == 0);
++
++	/*
++	 * ping privileged connection from this new unprivileged
++	 * one
++	 */
++
++	ret = kdbus_msg_send(unpriv_conn, NULL, cookie, 0, 0,
++			     0, conn->id);
++	ASSERT_EXIT(ret == 0);
++
++	/*
++	 * Since we just dropped privileges, the dumpable flag
++	 * was just cleared which makes the /proc/$clone_child/uid_map
++	 * to be owned by root, hence any userns uid mapping will fail
++	 * with -EPERM since the mapping will be done by uid 65534.
++	 *
++	 * To avoid this set the dumpable flag again which makes
++	 * procfs update the /proc/$clone_child/ inodes owner to 65534.
++	 *
++	 * Using this we will be able write to /proc/$clone_child/uid_map
++	 * as uid 65534 and map the uid 65534 to 0 inside the user namespace.
++	 */
++	ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER);
++	ASSERT_EXIT(ret == 0);
++
++	/* Make child privileged in its new userns and run tests */
++
++	ret = RUN_CLONE_CHILD(&clone_ret,
++			      SIGCHLD | CLONE_NEWUSER | CLONE_NEWPID,
++	({ 0;  /* Clone setup, nothing */ }),
++	({
++		eventfd_t event_status = 0;
++		struct kdbus_conn *userns_conn;
++
++		/* ping connection from the new user namespace */
++		userns_conn = kdbus_hello(bus, 0, NULL, 0);
++		ASSERT_EXIT(userns_conn);
++
++		ret = kdbus_add_match_empty(userns_conn);
++		ASSERT_EXIT(ret == 0);
++
++		cookie++;
++		ret = kdbus_msg_send(userns_conn, NULL, cookie,
++				     0, 0, 0, conn->id);
++		ASSERT_EXIT(ret == 0);
++
++		/* Parent did send */
++		ret = eventfd_read(signal_fd, &event_status);
++		ASSERT_RETURN(ret >= 0 && event_status == 1);
++
++		/*
++		 * Receive from privileged connection
++		 */
++		kdbus_printf("Privileged → unprivileged/privileged "
++			     "in its userns "
++			     "(different userns and pidns):\n");
++		ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL);
++		ASSERT_EXIT(ret == 0);
++		ASSERT_EXIT(msg->dst_id == userns_conn->id);
++
++		item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
++		ASSERT_EXIT(item);
++
++		/* uid/gid not mapped, so we have unpriv cached creds */
++		ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
++		ASSERT_EXIT(ret == 0);
++
++		/*
++		 * Diffent pid namepsaces. This is the child pidns
++		 * so it should not see its parent kdbus_pids
++		 */
++		ret = kdbus_match_kdbus_pids(msg, &unmapped_pids);
++		ASSERT_EXIT(ret == 0);
++
++		kdbus_msg_free(msg);
++
++
++		/*
++		 * Receive broadcast from privileged connection
++		 */
++		kdbus_printf("Privileged → unprivileged/privileged "
++			     "in its userns "
++			     "(different userns and pidns):\n");
++		ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL);
++		ASSERT_EXIT(ret == 0);
++		ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST);
++
++		item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
++		ASSERT_EXIT(item);
++
++		/* uid/gid not mapped, so we have unpriv cached creds */
++		ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
++		ASSERT_EXIT(ret == 0);
++
++		/*
++		 * Diffent pid namepsaces. This is the child pidns
++		 * so it should not see its parent kdbus_pids
++		 */
++		ret = kdbus_match_kdbus_pids(msg, &unmapped_pids);
++		ASSERT_EXIT(ret == 0);
++
++		kdbus_msg_free(msg);
++
++		kdbus_conn_free(userns_conn);
++	}),
++	({
++		/* Parent setup map child uid/gid */
++		ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1");
++		ASSERT_EXIT(ret == 0);
++	}),
++	({ 0; }));
++	/* Unprivileged was not able to create user namespace */
++	if (clone_ret == -EPERM) {
++		kdbus_printf("-- CLONE_NEWUSER TEST Failed for "
++			     "uid: %u\n -- Make sure that your kernel "
++			     "do not allow CLONE_NEWUSER for "
++			     "unprivileged users\n", UNPRIV_UID);
++		ret = 0;
++		goto out;
++	}
++
++	ASSERT_EXIT(ret == 0);
++
++
++	/*
++	 * Receive from privileged connection
++	 */
++	kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n");
++	ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL);
++
++	ASSERT_EXIT(ret == 0);
++	ASSERT_EXIT(msg->dst_id == unpriv_conn->id);
++
++	/* will get the privileged creds */
++	ret = kdbus_match_kdbus_creds(msg, &privileged_creds);
++	ASSERT_EXIT(ret == 0);
++
++	/* Same pidns so will get the kdbus_pids */
++	ret = kdbus_match_kdbus_pids(msg, &parent_pids);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_msg_free(msg);
++
++
++	/*
++	 * Receive broadcast from privileged connection
++	 */
++	kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n");
++	ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL);
++
++	ASSERT_EXIT(ret == 0);
++	ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST);
++
++	/* will get the privileged creds */
++	ret = kdbus_match_kdbus_creds(msg, &privileged_creds);
++	ASSERT_EXIT(ret == 0);
++
++	ret = kdbus_match_kdbus_pids(msg, &parent_pids);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_msg_free(msg);
++
++out:
++	kdbus_conn_free(unpriv_conn);
++
++	return ret;
++}
++
++static int kdbus_clone_userns_test(const char *bus,
++				   struct kdbus_conn *conn)
++{
++	int ret, status, efd;
++	pid_t pid, ppid;
++	uint64_t unpriv_conn_id, userns_conn_id;
++	struct kdbus_msg *msg;
++	const struct kdbus_item *item;
++	struct kdbus_pids expected_pids;
++	struct kdbus_conn *monitor;
++
++	kdbus_printf("STARTING TEST 'metadata-ns'.\n");
++
++	monitor = kdbus_hello(bus, KDBUS_HELLO_MONITOR, NULL, 0);
++	ASSERT_EXIT(monitor);
++
++	/*
++	 * parent will signal to child that is in its
++	 * userns to read its queue
++	 */
++	efd = eventfd(0, EFD_CLOEXEC);
++	ASSERT_RETURN_VAL(efd >= 0, efd);
++
++	ppid = getppid();
++
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, -errno);
++
++	if (pid == 0) {
++		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
++		ASSERT_EXIT_VAL(ret == 0, -errno);
++
++		ret = __kdbus_clone_userns_test(bus, conn, ppid, efd);
++		_exit(ret);
++	}
++
++
++	/* Phase 1) privileged receives from unprivileged */
++
++	/*
++	 * Receive from the unprivileged child
++	 */
++	kdbus_printf("\nUnprivileged → privileged (same namespaces):\n");
++	ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	unpriv_conn_id = msg->src_id;
++
++	/* Unprivileged user */
++	ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
++	ASSERT_RETURN(ret == 0);
++
++	/* Set the expected creds_pids */
++	expected_pids = (struct kdbus_pids) {
++		.pid = pid,
++		.tid = pid,
++		.ppid = getpid(),
++	};
++	ret = kdbus_match_kdbus_pids(msg, &expected_pids);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_msg_free(msg);
++
++
++	/*
++	 * Receive from the unprivileged that is in his own
++	 * userns and pidns
++	 */
++
++	kdbus_printf("\nUnprivileged/privileged in its userns → privileged "
++		     "(different userns and pidns)\n");
++	ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL);
++	if (ret == -ETIMEDOUT)
++		/* perhaps unprivileged userns is not allowed */
++		goto wait;
++
++	ASSERT_RETURN(ret == 0);
++
++	userns_conn_id = msg->src_id;
++
++	item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
++	ASSERT_RETURN(item);
++
++	/*
++	 * Compare received items, creds must be translated into
++	 * the receiver user namespace, so the user is unprivileged
++	 */
++	ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * We should have the kdbus_pids since we are the parent
++	 * pidns
++	 */
++	item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
++	ASSERT_RETURN(item);
++
++	ASSERT_RETURN(memcmp(&item->pids, &unmapped_pids,
++			     sizeof(struct kdbus_pids)) != 0);
++
++	/*
++	 * Parent pid of the unprivileged/privileged in its userns
++	 * is the unprivileged child pid that was forked here.
++	 */
++	ASSERT_RETURN((uint64_t)pid == item->pids.ppid);
++
++	kdbus_msg_free(msg);
++
++
++	/* Phase 2) Privileged connection sends now 3 packets */
++
++	/*
++	 * Sending to unprivileged connections a unicast
++	 */
++	ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
++			     0, unpriv_conn_id);
++	ASSERT_RETURN(ret == 0);
++
++	/* signal to child that is in its userns */
++	ret = eventfd_write(efd, 1);
++	ASSERT_EXIT(ret == 0);
++
++	/*
++	 * Sending to unprivileged/privilged in its userns
++	 * connections a unicast
++	 */
++	ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
++			     0, userns_conn_id);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Sending to unprivileged connections a broadcast
++	 */
++	ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
++			     0, KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++
++wait:
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN(ret >= 0);
++
++	ASSERT_RETURN(WIFEXITED(status))
++	ASSERT_RETURN(!WEXITSTATUS(status));
++
++	/* Dump monitor queue */
++	kdbus_printf("\n\nMonitor queue:\n");
++	for (;;) {
++		ret = kdbus_msg_recv_poll(monitor, 100, &msg, NULL);
++		if (ret < 0)
++			break;
++
++		if (msg->payload_type == KDBUS_PAYLOAD_DBUS) {
++			/*
++			 * Parent pidns should see all the
++			 * pids
++			 */
++			item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
++			ASSERT_RETURN(item);
++
++			ASSERT_RETURN(item->pids.pid != 0 &&
++				      item->pids.tid != 0 &&
++				      item->pids.ppid != 0);
++		}
++
++		kdbus_msg_free(msg);
++	}
++
++	kdbus_conn_free(monitor);
++	close(efd);
++
++	return 0;
++}
++
++int kdbus_test_metadata_ns(struct kdbus_test_env *env)
++{
++	int ret;
++	struct kdbus_conn *holder, *conn;
++	struct kdbus_policy_access policy_access = {
++		/* Allow world so we can inspect metadata in namespace */
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = geteuid(),
++		.access = KDBUS_POLICY_TALK,
++	};
++
++	/*
++	 * We require user-namespaces and all uids/gids
++	 * should be mapped (we can just require the necessary ones)
++	 */
++	if (!config_user_ns_is_enabled() ||
++	    !all_uids_gids_are_mapped())
++		return TEST_SKIP;
++
++	ret = test_is_capable(CAP_SETUID, CAP_SETGID, CAP_SYS_ADMIN, -1);
++	ASSERT_RETURN(ret >= 0);
++
++	/* no enough privileges, SKIP test */
++	if (!ret)
++		return TEST_SKIP;
++
++	holder = kdbus_hello_registrar(env->buspath, "com.example.metadata",
++				       &policy_access, 1,
++				       KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(holder);
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	ret = kdbus_add_match_empty(conn);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_acquire(conn, "com.example.metadata", NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	ret = kdbus_clone_userns_test(env->buspath, conn);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_conn_free(holder);
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-monitor.c b/tools/testing/selftests/kdbus/test-monitor.c
+new file mode 100644
+index 0000000..e00d738
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-monitor.c
+@@ -0,0 +1,176 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <stdbool.h>
++#include <errno.h>
++#include <assert.h>
++#include <signal.h>
++#include <sys/time.h>
++#include <sys/mman.h>
++#include <sys/capability.h>
++#include <sys/wait.h>
++
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++int kdbus_test_monitor(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *monitor, *conn;
++	unsigned int cookie = 0xdeadbeef;
++	struct kdbus_msg *msg;
++	uint64_t offset = 0;
++	int ret;
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	/* add matches to make sure the monitor do not trigger an item add or
++	 * remove on connect and disconnect, respectively.
++	 */
++	ret = kdbus_add_match_id(conn, 0x1, KDBUS_ITEM_ID_ADD,
++				 KDBUS_MATCH_ID_ANY);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_add_match_id(conn, 0x2, KDBUS_ITEM_ID_REMOVE,
++				 KDBUS_MATCH_ID_ANY);
++	ASSERT_RETURN(ret == 0);
++
++	/* register a monitor */
++	monitor = kdbus_hello(env->buspath, KDBUS_HELLO_MONITOR, NULL, 0);
++	ASSERT_RETURN(monitor);
++
++	/* make sure we did not receive a monitor connect notification */
++	ret = kdbus_msg_recv(conn, &msg, &offset);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	/* check that a monitor cannot acquire a name */
++	ret = kdbus_name_acquire(monitor, "foo.bar.baz", NULL);
++	ASSERT_RETURN(ret == -EOPNOTSUPP);
++
++	ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0,  0, conn->id);
++	ASSERT_RETURN(ret == 0);
++
++	/* the recipient should have gotten the message */
++	ret = kdbus_msg_recv(conn, &msg, &offset);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++	kdbus_msg_free(msg);
++	kdbus_free(conn, offset);
++
++	/* and so should the monitor */
++	ret = kdbus_msg_recv(monitor, &msg, &offset);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++	kdbus_free(monitor, offset);
++
++	/* Installing matches for monitors must fais must fail */
++	ret = kdbus_add_match_empty(monitor);
++	ASSERT_RETURN(ret == -EOPNOTSUPP);
++
++	cookie++;
++	ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0,
++			     KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++	/* The monitor should get the message. */
++	ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++	kdbus_free(monitor, offset);
++
++	/*
++	 * Since we are the only monitor, update the attach flags
++	 * and tell we are not interessted in attach flags recv
++	 */
++
++	ret = kdbus_conn_update_attach_flags(monitor,
++					     _KDBUS_ATTACH_ALL,
++					     0);
++	ASSERT_RETURN(ret == 0);
++
++	cookie++;
++	ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0,
++			     KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	ret = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_msg_free(msg);
++	kdbus_free(monitor, offset);
++
++	/*
++	 * Now we are interested in KDBUS_ITEM_TIMESTAMP and
++	 * KDBUS_ITEM_CREDS
++	 */
++	ret = kdbus_conn_update_attach_flags(monitor,
++					     _KDBUS_ATTACH_ALL,
++					     KDBUS_ATTACH_TIMESTAMP |
++					     KDBUS_ATTACH_CREDS);
++	ASSERT_RETURN(ret == 0);
++
++	cookie++;
++	ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0,
++			     KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == cookie);
++
++	ret = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP);
++	ASSERT_RETURN(ret == 1);
++
++	ret = kdbus_item_in_message(msg, KDBUS_ITEM_CREDS);
++	ASSERT_RETURN(ret == 1);
++
++	/* the KDBUS_ITEM_PID_COMM was not requested */
++	ret = kdbus_item_in_message(msg, KDBUS_ITEM_PID_COMM);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_msg_free(msg);
++	kdbus_free(monitor, offset);
++
++	kdbus_conn_free(monitor);
++	/* make sure we did not receive a monitor disconnect notification */
++	ret = kdbus_msg_recv(conn, &msg, &offset);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	kdbus_conn_free(conn);
++
++	/* Make sure that monitor as unprivileged is not allowed */
++	ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
++	ASSERT_RETURN(ret >= 0);
++
++	if (ret && all_uids_gids_are_mapped()) {
++		ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({
++			monitor = kdbus_hello(env->buspath,
++					      KDBUS_HELLO_MONITOR,
++					      NULL, 0);
++			ASSERT_EXIT(!monitor && errno == EPERM);
++
++			_exit(EXIT_SUCCESS);
++		}),
++		({ 0; }));
++		ASSERT_RETURN(ret == 0);
++	}
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-names.c b/tools/testing/selftests/kdbus/test-names.c
+new file mode 100644
+index 0000000..e400dc8
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-names.c
+@@ -0,0 +1,272 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <limits.h>
++#include <getopt.h>
++#include <stdbool.h>
++
++#include "kdbus-api.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++#include "kdbus-test.h"
++
++struct test_name {
++	const char *name;
++	__u64 owner_id;
++	__u64 flags;
++};
++
++static bool conn_test_names(const struct kdbus_conn *conn,
++			    const struct test_name *tests,
++			    unsigned int n_tests)
++{
++	struct kdbus_cmd_list cmd_list = {};
++	struct kdbus_info *name, *list;
++	unsigned int i;
++	int ret;
++
++	cmd_list.size = sizeof(cmd_list);
++	cmd_list.flags = KDBUS_LIST_NAMES |
++			 KDBUS_LIST_ACTIVATORS |
++			 KDBUS_LIST_QUEUED;
++
++	ret = kdbus_cmd_list(conn->fd, &cmd_list);
++	ASSERT_RETURN(ret == 0);
++
++	list = (struct kdbus_info *)(conn->buf + cmd_list.offset);
++
++	for (i = 0; i < n_tests; i++) {
++		const struct test_name *t = tests + i;
++		bool found = false;
++
++		KDBUS_FOREACH(name, list, cmd_list.list_size) {
++			struct kdbus_item *item;
++
++			KDBUS_ITEM_FOREACH(item, name, items) {
++				if (item->type != KDBUS_ITEM_OWNED_NAME ||
++				    strcmp(item->name.name, t->name) != 0)
++					continue;
++
++				if (t->owner_id == name->id &&
++				    t->flags == item->name.flags) {
++					found = true;
++					break;
++				}
++			}
++		}
++
++		if (!found)
++			return false;
++	}
++
++	return true;
++}
++
++static bool conn_is_name_primary_owner(const struct kdbus_conn *conn,
++				       const char *needle)
++{
++	struct test_name t = {
++		.name = needle,
++		.owner_id = conn->id,
++		.flags = KDBUS_NAME_PRIMARY,
++	};
++
++	return conn_test_names(conn, &t, 1);
++}
++
++int kdbus_test_name_basic(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn;
++	char *name, *dot_name, *invalid_name, *wildcard_name;
++	int ret;
++
++	name = "foo.bla.blaz";
++	dot_name = ".bla.blaz";
++	invalid_name = "foo";
++	wildcard_name = "foo.bla.bl.*";
++
++	/* create a 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++
++	/* acquire name "foo.bar.xxx" name */
++	ret = kdbus_name_acquire(conn, "foo.bar.xxx", NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* Name is not valid, must fail */
++	ret = kdbus_name_acquire(env->conn, dot_name, NULL);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	ret = kdbus_name_acquire(env->conn, invalid_name, NULL);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	ret = kdbus_name_acquire(env->conn, wildcard_name, NULL);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	/* check that we can acquire a name */
++	ret = kdbus_name_acquire(env->conn, name, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = conn_is_name_primary_owner(env->conn, name);
++	ASSERT_RETURN(ret == true);
++
++	/* ... and release it again */
++	ret = kdbus_name_release(env->conn, name);
++	ASSERT_RETURN(ret == 0);
++
++	ret = conn_is_name_primary_owner(env->conn, name);
++	ASSERT_RETURN(ret == false);
++
++	/* check that we can't release it again */
++	ret = kdbus_name_release(env->conn, name);
++	ASSERT_RETURN(ret == -ESRCH);
++
++	/* check that we can't release a name that we don't own */
++	ret = kdbus_name_release(env->conn, "foo.bar.xxx");
++	ASSERT_RETURN(ret == -EADDRINUSE);
++
++	/* Name is not valid, must fail */
++	ret = kdbus_name_release(env->conn, dot_name);
++	ASSERT_RETURN(ret == -ESRCH);
++
++	ret = kdbus_name_release(env->conn, invalid_name);
++	ASSERT_RETURN(ret == -ESRCH);
++
++	ret = kdbus_name_release(env->conn, wildcard_name);
++	ASSERT_RETURN(ret == -ESRCH);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++int kdbus_test_name_conflict(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn;
++	char *name;
++	int ret;
++
++	name = "foo.bla.blaz";
++
++	/* create a 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++
++	/* allow the new connection to own the same name */
++	/* acquire name from the 1st connection */
++	ret = kdbus_name_acquire(env->conn, name, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = conn_is_name_primary_owner(env->conn, name);
++	ASSERT_RETURN(ret == true);
++
++	/* check that we also can't acquire it again from the 2nd connection */
++	ret = kdbus_name_acquire(conn, name, NULL);
++	ASSERT_RETURN(ret == -EEXIST);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++int kdbus_test_name_queue(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn;
++	struct test_name t[2];
++	const char *name;
++	uint64_t flags;
++	int ret;
++
++	name = "foo.bla.blaz";
++
++	flags = 0;
++
++	/* create a 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++
++	/* allow the new connection to own the same name */
++	/* acquire name from the 1st connection */
++	ret = kdbus_name_acquire(env->conn, name, &flags);
++	ASSERT_RETURN(ret == 0);
++
++	ret = conn_is_name_primary_owner(env->conn, name);
++	ASSERT_RETURN(ret == true);
++
++	/* queue the 2nd connection as waiting owner */
++	flags = KDBUS_NAME_QUEUE;
++	ret = kdbus_name_acquire(conn, name, &flags);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE);
++
++	t[0].name = name;
++	t[0].owner_id = env->conn->id;
++	t[0].flags = KDBUS_NAME_PRIMARY;
++	t[1].name = name;
++	t[1].owner_id = conn->id;
++	t[1].flags = KDBUS_NAME_QUEUE | KDBUS_NAME_IN_QUEUE;
++	ret = conn_test_names(conn, t, 2);
++	ASSERT_RETURN(ret == true);
++
++	/* release name from 1st connection */
++	ret = kdbus_name_release(env->conn, name);
++	ASSERT_RETURN(ret == 0);
++
++	/* now the name should be owned by the 2nd connection */
++	t[0].name = name;
++	t[0].owner_id = conn->id;
++	t[0].flags = KDBUS_NAME_PRIMARY | KDBUS_NAME_QUEUE;
++	ret = conn_test_names(conn, t, 1);
++	ASSERT_RETURN(ret == true);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
++
++int kdbus_test_name_takeover(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn;
++	struct test_name t;
++	const char *name;
++	uint64_t flags;
++	int ret;
++
++	name = "foo.bla.blaz";
++
++	flags = KDBUS_NAME_ALLOW_REPLACEMENT;
++
++	/* create a 2nd connection */
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn != NULL);
++
++	/* acquire name for 1st connection */
++	ret = kdbus_name_acquire(env->conn, name, &flags);
++	ASSERT_RETURN(ret == 0);
++
++	t.name = name;
++	t.owner_id = env->conn->id;
++	t.flags = KDBUS_NAME_ALLOW_REPLACEMENT | KDBUS_NAME_PRIMARY;
++	ret = conn_test_names(conn, &t, 1);
++	ASSERT_RETURN(ret == true);
++
++	/* now steal name with 2nd connection */
++	flags = KDBUS_NAME_REPLACE_EXISTING;
++	ret = kdbus_name_acquire(conn, name, &flags);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(flags & KDBUS_NAME_ACQUIRED);
++
++	ret = conn_is_name_primary_owner(conn, name);
++	ASSERT_RETURN(ret == true);
++
++	kdbus_conn_free(conn);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-policy-ns.c b/tools/testing/selftests/kdbus/test-policy-ns.c
+new file mode 100644
+index 0000000..3437012
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-policy-ns.c
+@@ -0,0 +1,632 @@
++/*
++ * Test metadata and policies in new namespaces. Even if our tests
++ * can run in a namespaced setup, this test is necessary so we can
++ * inspect policies on the same kdbusfs but between multiple
++ * namespaces.
++ *
++ * Copyright (C) 2014-2015 Djalal Harouni
++ *
++ * kdbus is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU Lesser General Public License as published by the
++ * Free Software Foundation; either version 2.1 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <pthread.h>
++#include <sched.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <stdint.h>
++#include <stdbool.h>
++#include <unistd.h>
++#include <errno.h>
++#include <signal.h>
++#include <sys/wait.h>
++#include <sys/prctl.h>
++#include <sys/eventfd.h>
++#include <sys/syscall.h>
++#include <sys/capability.h>
++#include <linux/sched.h>
++
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++#define MAX_CONN	64
++#define POLICY_NAME	"foo.test.policy-test"
++
++#define KDBUS_CONN_MAX_MSGS_PER_USER            16
++
++/**
++ * Note: this test can be used to inspect policy_db->talk_access_hash
++ *
++ * The purpose of these tests:
++ * 1) Check KDBUS_POLICY_TALK
++ * 2) Check the cache state: kdbus_policy_db->talk_access_hash
++ * Should be extended
++ */
++
++/**
++ * Check a list of connections against conn_db[0]
++ * conn_db[0] will own the name "foo.test.policy-test" and the
++ * policy holder connection for this name will update the policy
++ * entries, so different use cases can be tested.
++ */
++static struct kdbus_conn **conn_db;
++
++static void *kdbus_recv_echo(void *ptr)
++{
++	int ret;
++	struct kdbus_conn *conn = ptr;
++
++	ret = kdbus_msg_recv_poll(conn, 200, NULL, NULL);
++
++	return (void *)(long)ret;
++}
++
++/* Trigger kdbus_policy_set() */
++static int kdbus_set_policy_talk(struct kdbus_conn *conn,
++				 const char *name,
++				 uid_t id, unsigned int type)
++{
++	int ret;
++	struct kdbus_policy_access access = {
++		.type = type,
++		.id = id,
++		.access = KDBUS_POLICY_TALK,
++	};
++
++	ret = kdbus_conn_update_policy(conn, name, &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	return TEST_OK;
++}
++
++/* return TEST_OK or TEST_ERR on failure */
++static int kdbus_register_same_activator(char *bus, const char *name,
++					 struct kdbus_conn **c)
++{
++	int ret;
++	struct kdbus_conn *activator;
++
++	activator = kdbus_hello_activator(bus, name, NULL, 0);
++	if (activator) {
++		*c = activator;
++		fprintf(stderr, "--- error was able to register name twice '%s'.\n",
++			name);
++		return TEST_ERR;
++	}
++
++	ret = -errno;
++	/* -EEXIST means test succeeded */
++	if (ret == -EEXIST)
++		return TEST_OK;
++
++	return TEST_ERR;
++}
++
++/* return TEST_OK or TEST_ERR on failure */
++static int kdbus_register_policy_holder(char *bus, const char *name,
++					struct kdbus_conn **conn)
++{
++	struct kdbus_conn *c;
++	struct kdbus_policy_access access[2];
++
++	access[0].type = KDBUS_POLICY_ACCESS_USER;
++	access[0].access = KDBUS_POLICY_OWN;
++	access[0].id = geteuid();
++
++	access[1].type = KDBUS_POLICY_ACCESS_WORLD;
++	access[1].access = KDBUS_POLICY_TALK;
++	access[1].id = geteuid();
++
++	c = kdbus_hello_registrar(bus, name, access, 2,
++				  KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(c);
++
++	*conn = c;
++
++	return TEST_OK;
++}
++
++/**
++ * Create new threads for receiving from multiple senders,
++ * The 'conn_db' will be populated by newly created connections.
++ * Caller should free all allocated connections.
++ *
++ * return 0 on success, negative errno on failure.
++ */
++static int kdbus_recv_in_threads(const char *bus, const char *name,
++				 struct kdbus_conn **conn_db)
++{
++	int ret;
++	bool pool_full = false;
++	unsigned int sent_packets = 0;
++	unsigned int lost_packets = 0;
++	unsigned int i, tid;
++	unsigned long dst_id;
++	unsigned long cookie = 1;
++	unsigned int thread_nr = MAX_CONN - 1;
++	pthread_t thread_id[MAX_CONN - 1] = {'\0'};
++
++	dst_id = name ? KDBUS_DST_ID_NAME : conn_db[0]->id;
++
++	for (tid = 0, i = 1; tid < thread_nr; tid++, i++) {
++		ret = pthread_create(&thread_id[tid], NULL,
++				     kdbus_recv_echo, (void *)conn_db[0]);
++		if (ret < 0) {
++			ret = -errno;
++			kdbus_printf("error pthread_create: %d (%m)\n",
++				      ret);
++			break;
++		}
++
++		/* just free before re-using */
++		kdbus_conn_free(conn_db[i]);
++		conn_db[i] = NULL;
++
++		/* We need to create connections here */
++		conn_db[i] = kdbus_hello(bus, 0, NULL, 0);
++		if (!conn_db[i]) {
++			ret = -errno;
++			break;
++		}
++
++		ret = kdbus_add_match_empty(conn_db[i]);
++		if (ret < 0)
++			break;
++
++		ret = kdbus_msg_send(conn_db[i], name, cookie++,
++				     0, 0, 0, dst_id);
++		if (ret < 0) {
++			/*
++			 * Receivers are not reading their messages,
++			 * not scheduled ?!
++			 *
++			 * So set the pool full here, perhaps the
++			 * connection pool or queue was full, later
++			 * recheck receivers errors
++			 */
++			if (ret == -ENOBUFS || ret == -EXFULL)
++				pool_full = true;
++			break;
++		}
++
++		sent_packets++;
++	}
++
++	for (tid = 0; tid < thread_nr; tid++) {
++		int thread_ret = 0;
++
++		if (thread_id[tid]) {
++			pthread_join(thread_id[tid], (void *)&thread_ret);
++			if (thread_ret < 0) {
++				/* Update only if send did not fail */
++				if (ret == 0)
++					ret = thread_ret;
++
++				lost_packets++;
++			}
++		}
++	}
++
++	/*
++	 * When sending if we did fail with -ENOBUFS or -EXFULL
++	 * then we should have set lost_packet and we should at
++	 * least have sent_packets set to KDBUS_CONN_MAX_MSGS_PER_USER
++	 */
++	if (pool_full) {
++		ASSERT_RETURN(lost_packets > 0);
++
++		/*
++		 * We should at least send KDBUS_CONN_MAX_MSGS_PER_USER
++		 *
++		 * For every send operation we create a thread to
++		 * recv the packet, so we keep the queue clean
++		 */
++		ASSERT_RETURN(sent_packets >= KDBUS_CONN_MAX_MSGS_PER_USER);
++
++		/*
++		 * Set ret to zero since we only failed due to
++		 * the receiving threads that have not been
++		 * scheduled
++		 */
++		ret = 0;
++	}
++
++	return ret;
++}
++
++/* Return: TEST_OK or TEST_ERR on failure */
++static int kdbus_normal_test(const char *bus, const char *name,
++			     struct kdbus_conn **conn_db)
++{
++	int ret;
++
++	ret = kdbus_recv_in_threads(bus, name, conn_db);
++	ASSERT_RETURN(ret >= 0);
++
++	return TEST_OK;
++}
++
++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;
++}
++
++/*
++ * Return: TEST_OK, TEST_ERR or TEST_SKIP
++ * we return TEST_OK only if the children return with the expected
++ * 'expected_status' that is specified as an argument.
++ */
++static int kdbus_fork_test(const char *bus, const char *name,
++			   struct kdbus_conn **conn_db, int expected_status)
++{
++	pid_t pid;
++	int ret = 0;
++	int status = 0;
++
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, pid);
++
++	if (pid == 0) {
++		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
++		ASSERT_EXIT(ret == 0);
++
++		ret = drop_privileges(65534, 65534);
++		ASSERT_EXIT(ret == 0);
++
++		ret = kdbus_recv_in_threads(bus, name, conn_db);
++		_exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE);
++	}
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN(ret >= 0);
++
++	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
++}
++
++/* Return EXIT_SUCCESS, EXIT_FAILURE or negative errno */
++static int __kdbus_clone_userns_test(const char *bus,
++				     const char *name,
++				     struct kdbus_conn **conn_db,
++				     int expected_status)
++{
++	int efd;
++	pid_t pid;
++	int ret = 0;
++	unsigned int uid = 65534;
++	int status;
++
++	ret = drop_privileges(uid, uid);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	/*
++	 * Since we just dropped privileges, the dumpable flag was just
++	 * cleared which makes the /proc/$clone_child/uid_map to be
++	 * owned by root, hence any userns uid mapping will fail with
++	 * -EPERM since the mapping will be done by uid 65534.
++	 *
++	 * To avoid this set the dumpable flag again which makes procfs
++	 * update the /proc/$clone_child/ inodes owner to 65534.
++	 *
++	 * Using this we will be able write to /proc/$clone_child/uid_map
++	 * as uid 65534 and map the uid 65534 to 0 inside the user
++	 * namespace.
++	 */
++	ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	/* sync parent/child */
++	efd = eventfd(0, EFD_CLOEXEC);
++	ASSERT_RETURN_VAL(efd >= 0, efd);
++
++	pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWUSER, NULL);
++	if (pid < 0) {
++		ret = -errno;
++		kdbus_printf("error clone: %d (%m)\n", ret);
++		/*
++		 * Normal user not allowed to create userns,
++		 * so nothing to worry about ?
++		 */
++		if (ret == -EPERM) {
++			kdbus_printf("-- CLONE_NEWUSER TEST Failed for uid: %u\n"
++				"-- Make sure that your kernel do not allow "
++				"CLONE_NEWUSER for unprivileged users\n"
++				"-- Upstream Commit: "
++				"https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5eaf563e\n",
++				uid);
++			ret = 0;
++		}
++
++		return ret;
++	}
++
++	if (pid == 0) {
++		struct kdbus_conn *conn_src;
++		eventfd_t event_status = 0;
++
++		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
++		ASSERT_EXIT(ret == 0);
++
++		ret = eventfd_read(efd, &event_status);
++		ASSERT_EXIT(ret >= 0 && event_status == 1);
++
++		/* ping connection from the new user namespace */
++		conn_src = kdbus_hello(bus, 0, NULL, 0);
++		ASSERT_EXIT(conn_src);
++
++		ret = kdbus_add_match_empty(conn_src);
++		ASSERT_EXIT(ret == 0);
++
++		ret = kdbus_msg_send(conn_src, name, 0xabcd1234,
++				     0, 0, 0, KDBUS_DST_ID_NAME);
++		kdbus_conn_free(conn_src);
++
++		_exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE);
++	}
++
++	ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1");
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	/* Tell child we are ready */
++	ret = eventfd_write(efd, 1);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	close(efd);
++
++	return status == EXIT_SUCCESS ? TEST_OK : TEST_ERR;
++}
++
++static int kdbus_clone_userns_test(const char *bus,
++				   const char *name,
++				   struct kdbus_conn **conn_db,
++				   int expected_status)
++{
++	pid_t pid;
++	int ret = 0;
++	int status;
++
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, -errno);
++
++	if (pid == 0) {
++		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
++		if (ret < 0)
++			_exit(EXIT_FAILURE);
++
++		ret = __kdbus_clone_userns_test(bus, name, conn_db,
++						expected_status);
++		_exit(ret);
++	}
++
++	/*
++	 * Receive in the original (root privileged) user namespace,
++	 * must fail with -ETIMEDOUT.
++	 */
++	ret = kdbus_msg_recv_poll(conn_db[0], 100, NULL, NULL);
++	ASSERT_RETURN_VAL(ret == -ETIMEDOUT, ret);
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
++}
++
++int kdbus_test_policy_ns(struct kdbus_test_env *env)
++{
++	int i;
++	int ret;
++	struct kdbus_conn *activator = NULL;
++	struct kdbus_conn *policy_holder = NULL;
++	char *bus = env->buspath;
++
++	ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
++	ASSERT_RETURN(ret >= 0);
++
++	/* no enough privileges, SKIP test */
++	if (!ret)
++		return TEST_SKIP;
++
++	/* we require user-namespaces */
++	if (access("/proc/self/uid_map", F_OK) != 0)
++		return TEST_SKIP;
++
++	/* uids/gids must be mapped */
++	if (!all_uids_gids_are_mapped())
++		return TEST_SKIP;
++
++	conn_db = calloc(MAX_CONN, sizeof(struct kdbus_conn *));
++	ASSERT_RETURN(conn_db);
++
++	memset(conn_db, 0, MAX_CONN * sizeof(struct kdbus_conn *));
++
++	conn_db[0] = kdbus_hello(bus, 0, NULL, 0);
++	ASSERT_RETURN(conn_db[0]);
++
++	ret = kdbus_add_match_empty(conn_db[0]);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM);
++	ASSERT_EXIT(ret == 0);
++
++	ret = kdbus_register_policy_holder(bus, POLICY_NAME,
++					   &policy_holder);
++	ASSERT_RETURN(ret == 0);
++
++	/* Try to register the same name with an activator */
++	ret = kdbus_register_same_activator(bus, POLICY_NAME,
++					    &activator);
++	ASSERT_RETURN(ret == 0);
++
++	/* Acquire POLICY_NAME */
++	ret = kdbus_name_acquire(conn_db[0], POLICY_NAME, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_normal_test(bus, POLICY_NAME, conn_db);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_list(conn_db[0], KDBUS_LIST_NAMES |
++				     KDBUS_LIST_UNIQUE |
++				     KDBUS_LIST_ACTIVATORS |
++				     KDBUS_LIST_QUEUED);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, EXIT_SUCCESS);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * children connections are able to talk to conn_db[0] since
++	 * current POLICY_NAME TALK type is KDBUS_POLICY_ACCESS_WORLD,
++	 * so expect EXIT_SUCCESS when sending from child. However,
++	 * since the child's connection does not own any well-known
++	 * name, The parent connection conn_db[0] should fail with
++	 * -EPERM but since it is a privileged bus user the TALK is
++	 *  allowed.
++	 */
++	ret = kdbus_fork_test_by_id(bus, conn_db,
++				    EXIT_SUCCESS, EXIT_SUCCESS);
++	ASSERT_EXIT(ret == 0);
++
++	/*
++	 * Connections that can talk are perhaps being destroyed now.
++	 * Restrict the policy and purge cache entries where the
++	 * conn_db[0] is the destination.
++	 *
++	 * Now only connections with uid == 0 are allowed to talk.
++	 */
++	ret = kdbus_set_policy_talk(policy_holder, POLICY_NAME,
++				    geteuid(), KDBUS_POLICY_ACCESS_USER);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Testing connections (FORK+DROP) again:
++	 * After setting the policy re-check connections
++	 * we expect the children to fail with -EPERM
++	 */
++	ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, -EPERM);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Now expect that both parent and child to fail.
++	 *
++	 * Child should fail with -EPERM since we just restricted
++	 * the POLICY_NAME TALK to uid 0 and its uid is 65534.
++	 *
++	 * Since the parent's connection will timeout when receiving
++	 * from the child, we never continue. FWIW just put -EPERM.
++	 */
++	ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM);
++	ASSERT_EXIT(ret == 0);
++
++	/* Check if the name can be reached in a new userns */
++	ret = kdbus_clone_userns_test(bus, POLICY_NAME, conn_db, -EPERM);
++	ASSERT_RETURN(ret == 0);
++
++	for (i = 0; i < MAX_CONN; i++)
++		kdbus_conn_free(conn_db[i]);
++
++	kdbus_conn_free(activator);
++	kdbus_conn_free(policy_holder);
++
++	free(conn_db);
++
++	return ret;
++}
+diff --git a/tools/testing/selftests/kdbus/test-policy-priv.c b/tools/testing/selftests/kdbus/test-policy-priv.c
+new file mode 100644
+index 0000000..0208638
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-policy-priv.c
+@@ -0,0 +1,1285 @@
++#include <errno.h>
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <stdbool.h>
++#include <unistd.h>
++#include <time.h>
++#include <sys/capability.h>
++#include <sys/eventfd.h>
++#include <sys/wait.h>
++
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++static int test_policy_priv_by_id(const char *bus,
++				  struct kdbus_conn *conn_dst,
++				  bool drop_second_user,
++				  int parent_status,
++				  int child_status)
++{
++	int ret = 0;
++	uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef;
++
++	ASSERT_RETURN(conn_dst);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, bus, ({
++		ret = kdbus_msg_send(unpriv, NULL,
++				     expected_cookie, 0, 0, 0,
++				     conn_dst->id);
++		ASSERT_EXIT(ret == child_status);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(conn_dst, 300, NULL, NULL);
++	ASSERT_RETURN(ret == parent_status);
++
++	return 0;
++}
++
++static int test_policy_priv_by_broadcast(const char *bus,
++					 struct kdbus_conn *conn_dst,
++					 int drop_second_user,
++					 int parent_status,
++					 int child_status)
++{
++	int efd;
++	int ret = 0;
++	eventfd_t event_status = 0;
++	struct kdbus_msg *msg = NULL;
++	uid_t second_uid = UNPRIV_UID;
++	gid_t second_gid = UNPRIV_GID;
++	struct kdbus_conn *child_2 = conn_dst;
++	uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef;
++
++	/* Drop to another unprivileged user other than UNPRIV_UID */
++	if (drop_second_user == DROP_OTHER_UNPRIV) {
++		second_uid = UNPRIV_UID - 1;
++		second_gid = UNPRIV_GID - 1;
++	}
++
++	/* child will signal parent to send broadcast */
++	efd = eventfd(0, EFD_CLOEXEC);
++	ASSERT_RETURN_VAL(efd >= 0, efd);
++
++	ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({
++		struct kdbus_conn *child;
++
++		child = kdbus_hello(bus, 0, NULL, 0);
++		ASSERT_EXIT(child);
++
++		ret = kdbus_add_match_empty(child);
++		ASSERT_EXIT(ret == 0);
++
++		/* signal parent */
++		ret = eventfd_write(efd, 1);
++		ASSERT_EXIT(ret == 0);
++
++		/* Use a little bit high time */
++		ret = kdbus_msg_recv_poll(child, 500, &msg, NULL);
++		ASSERT_EXIT(ret == child_status);
++
++		/*
++		 * If we expect the child to get the broadcast
++		 * message, then check the received cookie.
++		 */
++		if (ret == 0) {
++			ASSERT_EXIT(expected_cookie == msg->cookie);
++		}
++
++		/* Use expected_cookie since 'msg' might be NULL */
++		ret = kdbus_msg_send(child, NULL, expected_cookie + 1,
++				     0, 0, 0, KDBUS_DST_ID_BROADCAST);
++		ASSERT_EXIT(ret == 0);
++
++		kdbus_msg_free(msg);
++		kdbus_conn_free(child);
++	}),
++	({
++		if (drop_second_user == DO_NOT_DROP) {
++			ASSERT_RETURN(child_2);
++
++			ret = eventfd_read(efd, &event_status);
++			ASSERT_RETURN(ret >= 0 && event_status == 1);
++
++			ret = kdbus_msg_send(child_2, NULL,
++					     expected_cookie, 0, 0, 0,
++					     KDBUS_DST_ID_BROADCAST);
++			ASSERT_RETURN(ret == 0);
++
++			/* drop own broadcast */
++			ret = kdbus_msg_recv(child_2, &msg, NULL);
++			ASSERT_RETURN(ret == 0);
++			ASSERT_RETURN(msg->src_id == child_2->id);
++			kdbus_msg_free(msg);
++
++			/* Use a little bit high time */
++			ret = kdbus_msg_recv_poll(child_2, 1000,
++						  &msg, NULL);
++			ASSERT_RETURN(ret == parent_status);
++
++			/*
++			 * Check returned cookie in case we expect
++			 * success.
++			 */
++			if (ret == 0) {
++				ASSERT_RETURN(msg->cookie ==
++					      expected_cookie + 1);
++			}
++
++			kdbus_msg_free(msg);
++		} else {
++			/*
++			 * Two unprivileged users will try to
++			 * communicate using broadcast.
++			 */
++			ret = RUN_UNPRIVILEGED(second_uid, second_gid, ({
++				child_2 = kdbus_hello(bus, 0, NULL, 0);
++				ASSERT_EXIT(child_2);
++
++				ret = kdbus_add_match_empty(child_2);
++				ASSERT_EXIT(ret == 0);
++
++				ret = eventfd_read(efd, &event_status);
++				ASSERT_EXIT(ret >= 0 && event_status == 1);
++
++				ret = kdbus_msg_send(child_2, NULL,
++						expected_cookie, 0, 0, 0,
++						KDBUS_DST_ID_BROADCAST);
++				ASSERT_EXIT(ret == 0);
++
++				/* drop own broadcast */
++				ret = kdbus_msg_recv(child_2, &msg, NULL);
++				ASSERT_RETURN(ret == 0);
++				ASSERT_RETURN(msg->src_id == child_2->id);
++				kdbus_msg_free(msg);
++
++				/* Use a little bit high time */
++				ret = kdbus_msg_recv_poll(child_2, 1000,
++							  &msg, NULL);
++				ASSERT_EXIT(ret == parent_status);
++
++				/*
++				 * Check returned cookie in case we expect
++				 * success.
++				 */
++				if (ret == 0) {
++					ASSERT_EXIT(msg->cookie ==
++						    expected_cookie + 1);
++				}
++
++				kdbus_msg_free(msg);
++				kdbus_conn_free(child_2);
++			}),
++			({ 0; }));
++			ASSERT_RETURN(ret == 0);
++		}
++	}));
++	ASSERT_RETURN(ret == 0);
++
++	close(efd);
++
++	return ret;
++}
++
++static void nosig(int sig)
++{
++}
++
++static int test_priv_before_policy_upload(struct kdbus_test_env *env)
++{
++	int ret = 0;
++	struct kdbus_conn *conn;
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	/*
++	 * Make sure unprivileged bus user cannot acquire names
++	 * before registring any policy holder.
++	 */
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret < 0);
++	}));
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Make sure unprivileged bus users cannot talk by default
++	 * to privileged ones, unless a policy holder that allows
++	 * this was uploaded.
++	 */
++
++	ret = test_policy_priv_by_id(env->buspath, conn, false,
++				     -ETIMEDOUT, -EPERM);
++	ASSERT_RETURN(ret == 0);
++
++	/* Activate matching for a privileged connection */
++	ret = kdbus_add_match_empty(conn);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * First make sure that BROADCAST with msg flag
++	 * KDBUS_MSG_EXPECT_REPLY will fail with -ENOTUNIQ
++	 */
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, NULL, 0xdeadbeef,
++				     KDBUS_MSG_EXPECT_REPLY,
++				     5000000000ULL, 0,
++				     KDBUS_DST_ID_BROADCAST);
++		ASSERT_EXIT(ret == -ENOTUNIQ);
++	}));
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Test broadcast with a privileged connection.
++	 *
++	 * The first unprivileged receiver should not get the
++	 * broadcast message sent by the privileged connection,
++	 * since there is no a TALK policy that allows the
++	 * unprivileged to TALK to the privileged connection. It
++	 * will fail with -ETIMEDOUT
++	 *
++	 * Then second case:
++	 * The privileged connection should get the broadcast
++	 * message from the unprivileged one. Since the receiver is
++	 * a privileged bus user and it has default TALK access to
++	 * all connections it will receive those.
++	 */
++
++	ret = test_policy_priv_by_broadcast(env->buspath, conn,
++					    DO_NOT_DROP,
++					    0, -ETIMEDOUT);
++	ASSERT_RETURN(ret == 0);
++
++
++	/*
++	 * Test broadcast with two unprivileged connections running
++	 * under the same user.
++	 *
++	 * Both connections should succeed.
++	 */
++
++	ret = test_policy_priv_by_broadcast(env->buspath, NULL,
++					    DROP_SAME_UNPRIV, 0, 0);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Test broadcast with two unprivileged connections running
++	 * under different users.
++	 *
++	 * Both connections will fail with -ETIMEDOUT.
++	 */
++
++	ret = test_policy_priv_by_broadcast(env->buspath, NULL,
++					    DROP_OTHER_UNPRIV,
++					    -ETIMEDOUT, -ETIMEDOUT);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_conn_free(conn);
++
++	return ret;
++}
++
++static int test_broadcast_after_policy_upload(struct kdbus_test_env *env)
++{
++	int ret;
++	int efd;
++	eventfd_t event_status = 0;
++	struct kdbus_msg *msg = NULL;
++	struct kdbus_conn *owner_a, *owner_b;
++	struct kdbus_conn *holder_a, *holder_b;
++	struct kdbus_policy_access access = {};
++	uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef;
++
++	owner_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(owner_a);
++
++	ret = kdbus_name_acquire(owner_a, "com.example.broadcastA", NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	/*
++	 * Make sure unprivileged bus users cannot talk by default
++	 * to privileged ones, unless a policy holder that allows
++	 * this was uploaded.
++	 */
++
++	++expected_cookie;
++	ret = test_policy_priv_by_id(env->buspath, owner_a, false,
++				     -ETIMEDOUT, -EPERM);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Make sure that privileged won't receive broadcasts unless
++	 * it installs a match. It will fail with -ETIMEDOUT
++	 *
++	 * At same time check that the unprivileged connection will
++	 * not receive the broadcast message from the privileged one
++	 * since the privileged one owns a name with a restricted
++	 * policy TALK (actually the TALK policy is still not
++	 * registered so we fail by default), thus the unprivileged
++	 * receiver is not able to TALK to that name.
++	 */
++
++	/* Activate matching for a privileged connection */
++	ret = kdbus_add_match_empty(owner_a);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Redo the previous test. The privileged conn owner_a is
++	 * able to TALK to any connection so it will receive the
++	 * broadcast message now.
++	 */
++
++	ret = test_policy_priv_by_broadcast(env->buspath, owner_a,
++					    DO_NOT_DROP,
++					    0, -ETIMEDOUT);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Test that broadcast between two unprivileged users running
++	 * under the same user still succeed.
++	 */
++
++	ret = test_policy_priv_by_broadcast(env->buspath, NULL,
++					    DROP_SAME_UNPRIV, 0, 0);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Test broadcast with two unprivileged connections running
++	 * under different users.
++	 *
++	 * Both connections will fail with -ETIMEDOUT.
++	 */
++
++	ret = test_policy_priv_by_broadcast(env->buspath, NULL,
++					    DROP_OTHER_UNPRIV,
++					    -ETIMEDOUT, -ETIMEDOUT);
++	ASSERT_RETURN(ret == 0);
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_USER,
++		.id = geteuid(),
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	holder_a = kdbus_hello_registrar(env->buspath,
++					 "com.example.broadcastA",
++					 &access, 1,
++					 KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(holder_a);
++
++	holder_b = kdbus_hello_registrar(env->buspath,
++					 "com.example.broadcastB",
++					 &access, 1,
++					 KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(holder_b);
++
++	/* Free connections and their received messages and restart */
++	kdbus_conn_free(owner_a);
++
++	owner_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(owner_a);
++
++	/* Activate matching for a privileged connection */
++	ret = kdbus_add_match_empty(owner_a);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_name_acquire(owner_a, "com.example.broadcastA", NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	owner_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(owner_b);
++
++	ret = kdbus_name_acquire(owner_b, "com.example.broadcastB", NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	/* Activate matching for a privileged connection */
++	ret = kdbus_add_match_empty(owner_b);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Test that even if "com.example.broadcastA" and
++	 * "com.example.broadcastB" do have a TALK access by default
++	 * they are able to signal each other using broadcast due to
++	 * the fact they are privileged connections, they receive
++	 * all broadcasts if the match allows it.
++	 */
++
++	++expected_cookie;
++	ret = kdbus_msg_send(owner_a, NULL, expected_cookie, 0,
++			     0, 0, KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv_poll(owner_a, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == expected_cookie);
++
++	/* Check src ID */
++	ASSERT_RETURN(msg->src_id == owner_a->id);
++
++	kdbus_msg_free(msg);
++
++	ret = kdbus_msg_recv_poll(owner_b, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++	ASSERT_RETURN(msg->cookie == expected_cookie);
++
++	/* Check src ID */
++	ASSERT_RETURN(msg->src_id == owner_a->id);
++
++	kdbus_msg_free(msg);
++
++	/* Release name "com.example.broadcastB" */
++
++	ret = kdbus_name_release(owner_b, "com.example.broadcastB");
++	ASSERT_EXIT(ret >= 0);
++
++	/* KDBUS_POLICY_OWN for unprivileged connections */
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = geteuid(),
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	/* Update the policy so unprivileged will own the name */
++
++	ret = kdbus_conn_update_policy(holder_b,
++				       "com.example.broadcastB",
++				       &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Send broadcasts from an unprivileged connection that
++	 * owns a name "com.example.broadcastB".
++	 *
++	 * We'll have four destinations here:
++	 *
++	 * 1) destination owner_a: privileged connection that owns
++	 * "com.example.broadcastA". It will receive the broadcast
++	 * since it is a privileged has default TALK access to all
++	 * connections, and it is subscribed to the match.
++	 * Will succeed.
++	 *
++	 * owner_b: privileged connection (running under a different
++	 * uid) that do not own names, but with an empty broadcast
++	 * match, so it will receive broadcasts since it has default
++	 * TALK access to all connection.
++	 *
++	 * unpriv_a: unpriv connection that do not own any name.
++	 * It will receive the broadcast since it is running under
++	 * the same user of the one broadcasting and did install
++	 * matches. It should get the message.
++	 *
++	 * unpriv_b: unpriv connection is not interested in broadcast
++	 * messages, so it did not install broadcast matches. Should
++	 * fail with -ETIMEDOUT
++	 */
++
++	++expected_cookie;
++	efd = eventfd(0, EFD_CLOEXEC);
++	ASSERT_RETURN_VAL(efd >= 0, efd);
++
++	ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({
++		struct kdbus_conn *unpriv_owner;
++		struct kdbus_conn *unpriv_a, *unpriv_b;
++
++		unpriv_owner = kdbus_hello(env->buspath, 0, NULL, 0);
++		ASSERT_EXIT(unpriv_owner);
++
++		unpriv_a = kdbus_hello(env->buspath, 0, NULL, 0);
++		ASSERT_EXIT(unpriv_a);
++
++		unpriv_b = kdbus_hello(env->buspath, 0, NULL, 0);
++		ASSERT_EXIT(unpriv_b);
++
++		ret = kdbus_name_acquire(unpriv_owner,
++					 "com.example.broadcastB",
++					 NULL);
++		ASSERT_EXIT(ret >= 0);
++
++		ret = kdbus_add_match_empty(unpriv_a);
++		ASSERT_EXIT(ret == 0);
++
++		/* Signal that we are doing broadcasts */
++		ret = eventfd_write(efd, 1);
++		ASSERT_EXIT(ret == 0);
++
++		/*
++		 * Do broadcast from a connection that owns the
++		 * names "com.example.broadcastB".
++		 */
++		ret = kdbus_msg_send(unpriv_owner, NULL,
++				     expected_cookie,
++				     0, 0, 0,
++				     KDBUS_DST_ID_BROADCAST);
++		ASSERT_EXIT(ret == 0);
++
++		/*
++		 * Unprivileged connection running under the same
++		 * user. It should succeed.
++		 */
++		ret = kdbus_msg_recv_poll(unpriv_a, 300, &msg, NULL);
++		ASSERT_EXIT(ret == 0 && msg->cookie == expected_cookie);
++
++		/*
++		 * Did not install matches, not interested in
++		 * broadcasts
++		 */
++		ret = kdbus_msg_recv_poll(unpriv_b, 300, NULL, NULL);
++		ASSERT_EXIT(ret == -ETIMEDOUT);
++	}),
++	({
++		ret = eventfd_read(efd, &event_status);
++		ASSERT_RETURN(ret >= 0 && event_status == 1);
++
++		/*
++		 * owner_a must fail with -ETIMEDOUT, since it owns
++		 * name "com.example.broadcastA" and its TALK
++		 * access is restriced.
++		 */
++		ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL);
++		ASSERT_RETURN(ret == 0);
++
++		/* confirm the received cookie */
++		ASSERT_RETURN(msg->cookie == expected_cookie);
++
++		kdbus_msg_free(msg);
++
++		/*
++		 * owner_b got the broadcast from an unprivileged
++		 * connection.
++		 */
++		ret = kdbus_msg_recv_poll(owner_b, 300, &msg, NULL);
++		ASSERT_RETURN(ret == 0);
++
++		/* confirm the received cookie */
++		ASSERT_RETURN(msg->cookie == expected_cookie);
++
++		kdbus_msg_free(msg);
++
++	}));
++	ASSERT_RETURN(ret == 0);
++
++	close(efd);
++
++	/*
++	 * Test broadcast with two unprivileged connections running
++	 * under different users.
++	 *
++	 * Both connections will fail with -ETIMEDOUT.
++	 */
++
++	ret = test_policy_priv_by_broadcast(env->buspath, NULL,
++					    DROP_OTHER_UNPRIV,
++					    -ETIMEDOUT, -ETIMEDOUT);
++	ASSERT_RETURN(ret == 0);
++
++	/* Drop received broadcasts by privileged */
++	ret = kdbus_msg_recv_poll(owner_a, 100, NULL, NULL);
++	ret = kdbus_msg_recv_poll(owner_a, 100, NULL, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(owner_a, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	ret = kdbus_msg_recv_poll(owner_b, 100, NULL, NULL);
++	ret = kdbus_msg_recv_poll(owner_b, 100, NULL, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_msg_recv(owner_b, NULL, NULL);
++	ASSERT_RETURN(ret == -EAGAIN);
++
++	/*
++	 * Perform last tests, allow others to talk to name
++	 * "com.example.broadcastA". So now receiving broadcasts
++	 * from it should succeed since the TALK policy allow it.
++	 */
++
++	/* KDBUS_POLICY_OWN for unprivileged connections */
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = geteuid(),
++		.access = KDBUS_POLICY_TALK,
++	};
++
++	ret = kdbus_conn_update_policy(holder_a,
++				       "com.example.broadcastA",
++				       &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Unprivileged is able to TALK to "com.example.broadcastA"
++	 * now so it will receive its broadcasts
++	 */
++	ret = test_policy_priv_by_broadcast(env->buspath, owner_a,
++					    DO_NOT_DROP, 0, 0);
++	ASSERT_RETURN(ret == 0);
++
++	++expected_cookie;
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.broadcastB",
++					 NULL);
++		ASSERT_EXIT(ret >= 0);
++		ret = kdbus_msg_send(unpriv, NULL, expected_cookie,
++				     0, 0, 0, KDBUS_DST_ID_BROADCAST);
++		ASSERT_EXIT(ret == 0);
++	}));
++	ASSERT_RETURN(ret == 0);
++
++	/* owner_a is privileged it will get the broadcast now. */
++	ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* confirm the received cookie */
++	ASSERT_RETURN(msg->cookie == expected_cookie);
++
++	kdbus_msg_free(msg);
++
++	/*
++	 * owner_a released name "com.example.broadcastA". It should
++	 * receive broadcasts since it is still privileged and has
++	 * the right match.
++	 *
++	 * Unprivileged connection will own a name and will try to
++	 * signal to the privileged connection.
++	 */
++
++	ret = kdbus_name_release(owner_a, "com.example.broadcastA");
++	ASSERT_EXIT(ret >= 0);
++
++	++expected_cookie;
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.broadcastB",
++					 NULL);
++		ASSERT_EXIT(ret >= 0);
++		ret = kdbus_msg_send(unpriv, NULL, expected_cookie,
++				     0, 0, 0, KDBUS_DST_ID_BROADCAST);
++		ASSERT_EXIT(ret == 0);
++	}));
++	ASSERT_RETURN(ret == 0);
++
++	/* owner_a will get the broadcast now. */
++	ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL);
++	ASSERT_RETURN(ret == 0);
++
++	/* confirm the received cookie */
++	ASSERT_RETURN(msg->cookie == expected_cookie);
++
++	kdbus_msg_free(msg);
++
++	kdbus_conn_free(owner_a);
++	kdbus_conn_free(owner_b);
++	kdbus_conn_free(holder_a);
++	kdbus_conn_free(holder_b);
++
++	return 0;
++}
++
++static int test_policy_priv(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn_a, *conn_b, *conn, *owner;
++	struct kdbus_policy_access access, *acc;
++	sigset_t sset;
++	size_t num;
++	int ret;
++
++	/*
++	 * Make sure we have CAP_SETUID/SETGID so we can drop privileges
++	 */
++
++	ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
++	ASSERT_RETURN(ret >= 0);
++
++	if (!ret)
++		return TEST_SKIP;
++
++	/* make sure that uids and gids are mapped */
++	if (!all_uids_gids_are_mapped())
++		return TEST_SKIP;
++
++	/*
++	 * Setup:
++	 *  conn_a: policy holder for com.example.a
++	 *  conn_b: name holder of com.example.b
++	 */
++
++	signal(SIGUSR1, nosig);
++	sigemptyset(&sset);
++	sigaddset(&sset, SIGUSR1);
++	sigprocmask(SIG_BLOCK, &sset, NULL);
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	/*
++	 * Before registering any policy holder, make sure that the
++	 * bus is secure by default. This test is necessary, it catches
++	 * several cases where old D-Bus was vulnerable.
++	 */
++
++	ret = test_priv_before_policy_upload(env);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Make sure unprivileged are not able to register policy
++	 * holders
++	 */
++
++	ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({
++		struct kdbus_conn *holder;
++
++		holder = kdbus_hello_registrar(env->buspath,
++					       "com.example.a", NULL, 0,
++					       KDBUS_HELLO_POLICY_HOLDER);
++		ASSERT_EXIT(holder == NULL && errno == EPERM);
++	}),
++	({ 0; }));
++	ASSERT_RETURN(ret == 0);
++
++
++	/* Register policy holder */
++
++	conn_a = kdbus_hello_registrar(env->buspath, "com.example.a",
++				       NULL, 0, KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(conn_a);
++
++	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_b);
++
++	ret = kdbus_name_acquire(conn_b, "com.example.b", NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	/*
++	 * Make sure bus-owners can always acquire names.
++	 */
++	ret = kdbus_name_acquire(conn, "com.example.a", NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	kdbus_conn_free(conn);
++
++	/*
++	 * Make sure unprivileged users cannot acquire names with default
++	 * policy assigned.
++	 */
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret < 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged users can acquire names if we make them
++	 * world-accessible.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = 0,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	/*
++	 * Make sure unprivileged/normal connections are not able
++	 * to update policies
++	 */
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_conn_update_policy(unpriv, "com.example.a",
++					       &access, 1);
++		ASSERT_EXIT(ret == -EOPNOTSUPP);
++	}));
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged users can acquire names if we make them
++	 * gid-accessible. But only if the gid matches.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_GROUP,
++		.id = UNPRIV_GID,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_GROUP,
++		.id = 1,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret < 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged users can acquire names if we make them
++	 * uid-accessible. But only if the uid matches.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_USER,
++		.id = UNPRIV_UID,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_USER,
++		.id = 1,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret < 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged users cannot acquire names if no owner-policy
++	 * matches, even if SEE/TALK policies match.
++	 */
++
++	num = 4;
++	acc = (struct kdbus_policy_access[]){
++		{
++			.type = KDBUS_POLICY_ACCESS_GROUP,
++			.id = UNPRIV_GID,
++			.access = KDBUS_POLICY_SEE,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = UNPRIV_UID,
++			.access = KDBUS_POLICY_TALK,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_WORLD,
++			.id = 0,
++			.access = KDBUS_POLICY_TALK,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_WORLD,
++			.id = 0,
++			.access = KDBUS_POLICY_SEE,
++		},
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", acc, num);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret < 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged users can acquire names if the only matching
++	 * policy is somewhere in the middle.
++	 */
++
++	num = 5;
++	acc = (struct kdbus_policy_access[]){
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 1,
++			.access = KDBUS_POLICY_OWN,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 2,
++			.access = KDBUS_POLICY_OWN,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = UNPRIV_UID,
++			.access = KDBUS_POLICY_OWN,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 3,
++			.access = KDBUS_POLICY_OWN,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 4,
++			.access = KDBUS_POLICY_OWN,
++		},
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", acc, num);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_name_acquire(unpriv, "com.example.a", NULL);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Clear policies
++	 */
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", NULL, 0);
++	ASSERT_RETURN(ret == 0);
++
++	/*
++	 * Make sure privileged bus users can _always_ talk to others.
++	 */
++
++	conn = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn);
++
++	ret = kdbus_msg_send(conn, "com.example.b", 0xdeadbeef, 0, 0, 0, 0);
++	ASSERT_EXIT(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(conn_b, 300, NULL, NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	kdbus_conn_free(conn);
++
++	/*
++	 * Make sure unprivileged bus users cannot talk by default.
++	 */
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged bus users can talk to equals, even without
++	 * policy.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_USER,
++		.id = UNPRIV_UID,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.c", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		struct kdbus_conn *owner;
++
++		owner = kdbus_hello(env->buspath, 0, NULL, 0);
++		ASSERT_RETURN(owner);
++
++		ret = kdbus_name_acquire(owner, "com.example.c", NULL);
++		ASSERT_EXIT(ret >= 0);
++
++		ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret >= 0);
++		ret = kdbus_msg_recv_poll(owner, 100, NULL, NULL);
++		ASSERT_EXIT(ret >= 0);
++
++		kdbus_conn_free(owner);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged bus users can talk to privileged users if a
++	 * suitable UID policy is set.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_USER,
++		.id = UNPRIV_UID,
++		.access = KDBUS_POLICY_TALK,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	/*
++	 * Make sure unprivileged bus users can talk to privileged users if a
++	 * suitable GID policy is set.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_GROUP,
++		.id = UNPRIV_GID,
++		.access = KDBUS_POLICY_TALK,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	/*
++	 * Make sure unprivileged bus users can talk to privileged users if a
++	 * suitable WORLD policy is set.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = 0,
++		.access = KDBUS_POLICY_TALK,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	/*
++	 * Make sure unprivileged bus users cannot talk to privileged users if
++	 * no suitable policy is set.
++	 */
++
++	num = 5;
++	acc = (struct kdbus_policy_access[]){
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 0,
++			.access = KDBUS_POLICY_OWN,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 1,
++			.access = KDBUS_POLICY_TALK,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = UNPRIV_UID,
++			.access = KDBUS_POLICY_SEE,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 3,
++			.access = KDBUS_POLICY_TALK,
++		},
++		{
++			.type = KDBUS_POLICY_ACCESS_USER,
++			.id = 4,
++			.access = KDBUS_POLICY_TALK,
++		},
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.b", acc, num);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure unprivileged bus users can talk to privileged users if a
++	 * suitable OWN privilege overwrites TALK.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = 0,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret >= 0);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL);
++	ASSERT_EXIT(ret >= 0);
++
++	/*
++	 * Make sure the TALK cache is reset correctly when policies are
++	 * updated.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = 0,
++		.access = KDBUS_POLICY_TALK,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret >= 0);
++
++		ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL);
++		ASSERT_EXIT(ret >= 0);
++
++		ret = kdbus_conn_update_policy(conn_a, "com.example.b",
++					       NULL, 0);
++		ASSERT_RETURN(ret == 0);
++
++		ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret == -EPERM);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++	/*
++	 * Make sure the TALK cache is reset correctly when policy holders
++	 * disconnect.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_WORLD,
++		.id = 0,
++		.access = KDBUS_POLICY_OWN,
++	};
++
++	conn = kdbus_hello_registrar(env->buspath, "com.example.c",
++				     NULL, 0, KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(conn);
++
++	ret = kdbus_conn_update_policy(conn, "com.example.c", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	owner = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(owner);
++
++	ret = kdbus_name_acquire(owner, "com.example.c", NULL);
++	ASSERT_RETURN(ret >= 0);
++
++	ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({
++		struct kdbus_conn *unpriv;
++
++		/* wait for parent to be finished */
++		sigemptyset(&sset);
++		ret = sigsuspend(&sset);
++		ASSERT_RETURN(ret == -1 && errno == EINTR);
++
++		unpriv = kdbus_hello(env->buspath, 0, NULL, 0);
++		ASSERT_RETURN(unpriv);
++
++		ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret >= 0);
++
++		ret = kdbus_msg_recv_poll(owner, 100, NULL, NULL);
++		ASSERT_EXIT(ret >= 0);
++
++		/* free policy holder */
++		kdbus_conn_free(conn);
++
++		ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0,
++				     0, 0);
++		ASSERT_EXIT(ret == -EPERM);
++
++		kdbus_conn_free(unpriv);
++	}), ({
++		/* make sure policy holder is only valid in child */
++		kdbus_conn_free(conn);
++		kill(pid, SIGUSR1);
++	}));
++	ASSERT_RETURN(ret >= 0);
++
++
++	/*
++	 * The following tests are necessary.
++	 */
++
++	ret = test_broadcast_after_policy_upload(env);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_conn_free(owner);
++
++	/*
++	 * cleanup resources
++	 */
++
++	kdbus_conn_free(conn_b);
++	kdbus_conn_free(conn_a);
++
++	return TEST_OK;
++}
++
++int kdbus_test_policy_priv(struct kdbus_test_env *env)
++{
++	pid_t pid;
++	int ret;
++
++	/* make sure to exit() if a child returns from fork() */
++	pid = getpid();
++	ret = test_policy_priv(env);
++	if (pid != getpid())
++		exit(1);
++
++	return ret;
++}
+diff --git a/tools/testing/selftests/kdbus/test-policy.c b/tools/testing/selftests/kdbus/test-policy.c
+new file mode 100644
+index 0000000..96d20d5
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-policy.c
+@@ -0,0 +1,80 @@
++#include <errno.h>
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <stdbool.h>
++#include <unistd.h>
++
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++int kdbus_test_policy(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn_a, *conn_b;
++	struct kdbus_policy_access access;
++	int ret;
++
++	/* Invalid name */
++	conn_a = kdbus_hello_registrar(env->buspath, ".example.a",
++				       NULL, 0, KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(conn_a == NULL);
++
++	conn_a = kdbus_hello_registrar(env->buspath, "example",
++				       NULL, 0, KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(conn_a == NULL);
++
++	conn_a = kdbus_hello_registrar(env->buspath, "com.example.a",
++				       NULL, 0, KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(conn_a);
++
++	conn_b = kdbus_hello_registrar(env->buspath, "com.example.b",
++				       NULL, 0, KDBUS_HELLO_POLICY_HOLDER);
++	ASSERT_RETURN(conn_b);
++
++	/*
++	 * Verify there cannot be any duplicate entries, except for specific vs.
++	 * wildcard entries.
++	 */
++
++	access = (struct kdbus_policy_access){
++		.type = KDBUS_POLICY_ACCESS_USER,
++		.id = geteuid(),
++		.access = KDBUS_POLICY_SEE,
++	};
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_conn_update_policy(conn_b, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == -EEXIST);
++
++	ret = kdbus_conn_update_policy(conn_b, "com.example.a.*", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.a.*", &access, 1);
++	ASSERT_RETURN(ret == -EEXIST);
++
++	ret = kdbus_conn_update_policy(conn_a, "com.example.*", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_conn_update_policy(conn_b, "com.example.a", &access, 1);
++	ASSERT_RETURN(ret == 0);
++
++	ret = kdbus_conn_update_policy(conn_b, "com.example.*", &access, 1);
++	ASSERT_RETURN(ret == -EEXIST);
++
++	/* Invalid name */
++	ret = kdbus_conn_update_policy(conn_b, ".example.*", &access, 1);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	ret = kdbus_conn_update_policy(conn_b, "example", &access, 1);
++	ASSERT_RETURN(ret == -EINVAL);
++
++	kdbus_conn_free(conn_b);
++	kdbus_conn_free(conn_a);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-sync.c b/tools/testing/selftests/kdbus/test-sync.c
+new file mode 100644
+index 0000000..0655a54
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-sync.c
+@@ -0,0 +1,369 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <pthread.h>
++#include <stdbool.h>
++#include <signal.h>
++#include <sys/wait.h>
++#include <sys/eventfd.h>
++
++#include "kdbus-api.h"
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++static struct kdbus_conn *conn_a, *conn_b;
++static unsigned int cookie = 0xdeadbeef;
++
++static void nop_handler(int sig) {}
++
++static int interrupt_sync(struct kdbus_conn *conn_src,
++			  struct kdbus_conn *conn_dst)
++{
++	pid_t pid;
++	int ret, status;
++	struct kdbus_msg *msg = NULL;
++	struct sigaction sa = {
++		.sa_handler = nop_handler,
++		.sa_flags = SA_NOCLDSTOP|SA_RESTART,
++	};
++
++	cookie++;
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, pid);
++
++	if (pid == 0) {
++		ret = sigaction(SIGINT, &sa, NULL);
++		ASSERT_EXIT(ret == 0);
++
++		ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
++					  KDBUS_MSG_EXPECT_REPLY,
++					  100000000ULL, 0, conn_src->id, -1);
++		ASSERT_EXIT(ret == -ETIMEDOUT);
++
++		_exit(EXIT_SUCCESS);
++	}
++
++	ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++
++	ret = kill(pid, SIGINT);
++	ASSERT_RETURN_VAL(ret == 0, ret);
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	if (WIFSIGNALED(status))
++		return TEST_ERR;
++
++	ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL);
++	ASSERT_RETURN(ret == -ETIMEDOUT);
++
++	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
++}
++
++static int close_epipe_sync(const char *bus)
++{
++	pid_t pid;
++	int ret, status;
++	struct kdbus_conn *conn_src;
++	struct kdbus_conn *conn_dst;
++	struct kdbus_msg *msg = NULL;
++
++	conn_src = kdbus_hello(bus, 0, NULL, 0);
++	ASSERT_RETURN(conn_src);
++
++	ret = kdbus_add_match_empty(conn_src);
++	ASSERT_RETURN(ret == 0);
++
++	conn_dst = kdbus_hello(bus, 0, NULL, 0);
++	ASSERT_RETURN(conn_dst);
++
++	cookie++;
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, pid);
++
++	if (pid == 0) {
++		uint64_t dst_id;
++
++		/* close our reference */
++		dst_id = conn_dst->id;
++		kdbus_conn_free(conn_dst);
++
++		ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
++		ASSERT_EXIT(ret == 0 && msg->cookie == cookie);
++		ASSERT_EXIT(msg->src_id == dst_id);
++
++		cookie++;
++		ret = kdbus_msg_send_sync(conn_src, NULL, cookie,
++					  KDBUS_MSG_EXPECT_REPLY,
++					  100000000ULL, 0, dst_id, -1);
++		ASSERT_EXIT(ret == -EPIPE);
++
++		_exit(EXIT_SUCCESS);
++	}
++
++	ret = kdbus_msg_send(conn_dst, NULL, cookie, 0, 0, 0,
++			     KDBUS_DST_ID_BROADCAST);
++	ASSERT_RETURN(ret == 0);
++
++	cookie++;
++	ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++
++	/* destroy connection */
++	kdbus_conn_free(conn_dst);
++	kdbus_conn_free(conn_src);
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	if (!WIFEXITED(status))
++		return TEST_ERR;
++
++	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
++}
++
++static int cancel_fd_sync(struct kdbus_conn *conn_src,
++			  struct kdbus_conn *conn_dst)
++{
++	pid_t pid;
++	int cancel_fd;
++	int ret, status;
++	uint64_t counter = 1;
++	struct kdbus_msg *msg = NULL;
++
++	cancel_fd = eventfd(0, 0);
++	ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd);
++
++	cookie++;
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, pid);
++
++	if (pid == 0) {
++		ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
++					  KDBUS_MSG_EXPECT_REPLY,
++					  100000000ULL, 0, conn_src->id,
++					  cancel_fd);
++		ASSERT_EXIT(ret == -ECANCELED);
++
++		_exit(EXIT_SUCCESS);
++	}
++
++	ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
++	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
++
++	kdbus_msg_free(msg);
++
++	ret = write(cancel_fd, &counter, sizeof(counter));
++	ASSERT_RETURN(ret == sizeof(counter));
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	if (WIFSIGNALED(status))
++		return TEST_ERR;
++
++	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
++}
++
++static int no_cancel_sync(struct kdbus_conn *conn_src,
++			  struct kdbus_conn *conn_dst)
++{
++	pid_t pid;
++	int cancel_fd;
++	int ret, status;
++	struct kdbus_msg *msg = NULL;
++
++	/* pass eventfd, but never signal it so it shouldn't have any effect */
++
++	cancel_fd = eventfd(0, 0);
++	ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd);
++
++	cookie++;
++	pid = fork();
++	ASSERT_RETURN_VAL(pid >= 0, pid);
++
++	if (pid == 0) {
++		ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
++					  KDBUS_MSG_EXPECT_REPLY,
++					  100000000ULL, 0, conn_src->id,
++					  cancel_fd);
++		ASSERT_EXIT(ret == 0);
++
++		_exit(EXIT_SUCCESS);
++	}
++
++	ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
++	ASSERT_RETURN_VAL(ret == 0 && msg->cookie == cookie, -1);
++
++	kdbus_msg_free(msg);
++
++	ret = kdbus_msg_send_reply(conn_src, cookie, conn_dst->id);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	ret = waitpid(pid, &status, 0);
++	ASSERT_RETURN_VAL(ret >= 0, ret);
++
++	if (WIFSIGNALED(status))
++		return -1;
++
++	return (status == EXIT_SUCCESS) ? 0 : -1;
++}
++
++static void *run_thread_reply(void *data)
++{
++	int ret;
++	unsigned long status = TEST_OK;
++
++	ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL);
++	if (ret < 0)
++		goto exit_thread;
++
++	kdbus_printf("Thread received message, sending reply ...\n");
++
++	/* using an unknown cookie must fail */
++	ret = kdbus_msg_send_reply(conn_a, ~cookie, conn_b->id);
++	if (ret != -EBADSLT) {
++		status = TEST_ERR;
++		goto exit_thread;
++	}
++
++	ret = kdbus_msg_send_reply(conn_a, cookie, conn_b->id);
++	if (ret != 0) {
++		status = TEST_ERR;
++		goto exit_thread;
++	}
++
++exit_thread:
++	pthread_exit(NULL);
++	return (void *) status;
++}
++
++int kdbus_test_sync_reply(struct kdbus_test_env *env)
++{
++	unsigned long status;
++	pthread_t thread;
++	int ret;
++
++	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_a && conn_b);
++
++	pthread_create(&thread, NULL, run_thread_reply, NULL);
++
++	ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
++				  KDBUS_MSG_EXPECT_REPLY,
++				  5000000000ULL, 0, conn_a->id, -1);
++
++	pthread_join(thread, (void *) &status);
++	ASSERT_RETURN(status == 0);
++	ASSERT_RETURN(ret == 0);
++
++	ret = interrupt_sync(conn_a, conn_b);
++	ASSERT_RETURN(ret == 0);
++
++	ret = close_epipe_sync(env->buspath);
++	ASSERT_RETURN(ret == 0);
++
++	ret = cancel_fd_sync(conn_a, conn_b);
++	ASSERT_RETURN(ret == 0);
++
++	ret = no_cancel_sync(conn_a, conn_b);
++	ASSERT_RETURN(ret == 0);
++
++	kdbus_printf("-- closing bus connections\n");
++
++	kdbus_conn_free(conn_a);
++	kdbus_conn_free(conn_b);
++
++	return TEST_OK;
++}
++
++#define BYEBYE_ME ((void*)0L)
++#define BYEBYE_THEM ((void*)1L)
++
++static void *run_thread_byebye(void *data)
++{
++	struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) };
++	int ret;
++
++	ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL);
++	if (ret == 0) {
++		kdbus_printf("Thread received message, invoking BYEBYE ...\n");
++		kdbus_msg_recv(conn_a, NULL, NULL);
++		if (data == BYEBYE_ME)
++			kdbus_cmd_byebye(conn_b->fd, &cmd_byebye);
++		else if (data == BYEBYE_THEM)
++			kdbus_cmd_byebye(conn_a->fd, &cmd_byebye);
++	}
++
++	pthread_exit(NULL);
++	return NULL;
++}
++
++int kdbus_test_sync_byebye(struct kdbus_test_env *env)
++{
++	pthread_t thread;
++	int ret;
++
++	/*
++	 * This sends a synchronous message to a thread, which waits until it
++	 * received the message and then invokes BYEBYE on the *ORIGINAL*
++	 * connection. That is, on the same connection that synchronously waits
++	 * for an reply.
++	 * This should properly wake the connection up and cause ECONNRESET as
++	 * the connection is disconnected now.
++	 *
++	 * The second time, we do the same but invoke BYEBYE on the *TARGET*
++	 * connection. This should also wake up the synchronous sender as the
++	 * reply cannot be sent by a disconnected target.
++	 */
++
++	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_a && conn_b);
++
++	pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_ME);
++
++	ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
++				  KDBUS_MSG_EXPECT_REPLY,
++				  5000000000ULL, 0, conn_a->id, -1);
++
++	ASSERT_RETURN(ret == -ECONNRESET);
++
++	pthread_join(thread, NULL);
++
++	kdbus_conn_free(conn_a);
++	kdbus_conn_free(conn_b);
++
++	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_a && conn_b);
++
++	pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_THEM);
++
++	ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
++				  KDBUS_MSG_EXPECT_REPLY,
++				  5000000000ULL, 0, conn_a->id, -1);
++
++	ASSERT_RETURN(ret == -EPIPE);
++
++	pthread_join(thread, NULL);
++
++	kdbus_conn_free(conn_a);
++	kdbus_conn_free(conn_b);
++
++	return TEST_OK;
++}
+diff --git a/tools/testing/selftests/kdbus/test-timeout.c b/tools/testing/selftests/kdbus/test-timeout.c
+new file mode 100644
+index 0000000..cfd1930
+--- /dev/null
++++ b/tools/testing/selftests/kdbus/test-timeout.c
+@@ -0,0 +1,99 @@
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <errno.h>
++#include <assert.h>
++#include <poll.h>
++#include <stdbool.h>
++
++#include "kdbus-api.h"
++#include "kdbus-test.h"
++#include "kdbus-util.h"
++#include "kdbus-enum.h"
++
++int timeout_msg_recv(struct kdbus_conn *conn, uint64_t *expected)
++{
++	struct kdbus_cmd_recv recv = { .size = sizeof(recv) };
++	struct kdbus_msg *msg;
++	int ret;
++
++	ret = kdbus_cmd_recv(conn->fd, &recv);
++	if (ret < 0) {
++		kdbus_printf("error receiving message: %d (%m)\n", ret);
++		return ret;
++	}
++
++	msg = (struct kdbus_msg *)(conn->buf + recv.msg.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.msg.offset);
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
++int kdbus_test_timeout(struct kdbus_test_env *env)
++{
++	struct kdbus_conn *conn_a, *conn_b;
++	struct pollfd fd;
++	int ret, i, n_msgs = 4;
++	uint64_t expected = 0;
++	uint64_t cookie = 0xdeadbeef;
++
++	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
++	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
++	ASSERT_RETURN(conn_a && conn_b);
++
++	fd.fd = conn_b->fd;
++
++	/*
++	 * send messages that expect a reply (within 100 msec),
++	 * but never answer it.
++	 */
++	for (i = 0; i < n_msgs; i++, cookie++) {
++		kdbus_printf("Sending message with cookie %llu ...\n",
++			     (unsigned long long)cookie);
++		ASSERT_RETURN(kdbus_msg_send(conn_b, NULL, cookie,
++			      KDBUS_MSG_EXPECT_REPLY,
++			      (i + 1) * 100ULL * 1000000ULL, 0,
++			      conn_a->id) == 0);
++		expected |= 1ULL << cookie;
++	}
++
++	for (;;) {
++		fd.events = POLLIN | POLLPRI | POLLHUP;
++		fd.revents = 0;
++
++		ret = poll(&fd, 1, (n_msgs + 1) * 100);
++		if (ret == 0)
++			kdbus_printf("--- timeout\n");
++		if (ret <= 0)
++			break;
++
++		if (fd.revents & POLLIN)
++			ASSERT_RETURN(!timeout_msg_recv(conn_b, &expected));
++
++		if (expected == 0)
++			break;
++	}
++
++	ASSERT_RETURN(expected == 0);
++
++	kdbus_conn_free(conn_a);
++	kdbus_conn_free(conn_b);
++
++	return TEST_OK;
++}


             reply	other threads:[~2015-08-19 14:58 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-19 14:58 Mike Pagano [this message]
  -- strict thread matches above, loose matches on Subject: below --
2015-09-02 16:34 [gentoo-commits] proj/linux-patches:4.2 commit in: / Mike Pagano
2015-09-15 12:31 Mike Pagano
2015-09-21 22:19 Mike Pagano
2015-09-22 11:43 Mike Pagano
2015-09-28 16:49 Mike Pagano
2015-09-28 23:44 Mike Pagano
2015-09-29 17:51 Mike Pagano
2015-09-29 19:16 Mike Pagano
2015-10-03 16:12 Mike Pagano
2015-10-23 17:14 Mike Pagano
2015-10-23 17:19 Mike Pagano
2015-10-27 13:36 Mike Pagano
2015-11-05 23:30 Mike Pagano
2015-11-10  0:58 Mike Pagano
2015-12-11 14:31 Mike Pagano
2015-12-15 11:15 Mike Pagano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1439996286.1e94ed6b2554ee5b2a7770481aa5d64ad6a2332b.mpagano@gentoo \
    --to=mpagano@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox