diff options
Diffstat (limited to '0001-kdbus-interprocess-message-router.patch')
| -rw-r--r-- | 0001-kdbus-interprocess-message-router.patch | 1618 |
1 files changed, 0 insertions, 1618 deletions
diff --git a/0001-kdbus-interprocess-message-router.patch b/0001-kdbus-interprocess-message-router.patch deleted file mode 100644 index c563642cdf968c..00000000000000 --- a/0001-kdbus-interprocess-message-router.patch +++ /dev/null @@ -1,1618 +0,0 @@ -Subject: kdbus: interprocess message router - -Nothing to see here, move along... - - ---- - drivers/Kconfig | 2 - drivers/Makefile | 1 - drivers/kdbus/Kconfig | 5 - drivers/kdbus/Makefile | 4 - drivers/kdbus/bus.c | 122 ++++++++ - drivers/kdbus/ep.c | 200 ++++++++++++++ - drivers/kdbus/kdbus.c | 611 +++++++++++++++++++++++++++++++++++++++++++++ - drivers/kdbus/kdbus.h | 185 +++++++++++++ - drivers/kdbus/ns.c | 217 +++++++++++++++ - include/uapi/kdbus/kdbus.h | 123 +++++++++ - include/uapi/linux/major.h | 2 - kdbus.c | 77 +++++ - 12 files changed, 1549 insertions(+) - ---- a/drivers/Kconfig -+++ b/drivers/Kconfig -@@ -158,4 +158,6 @@ source "drivers/irqchip/Kconfig" - - source "drivers/ipack/Kconfig" - -+source "drivers/kdbus/Kconfig" -+ - endmenu ---- a/drivers/Makefile -+++ b/drivers/Makefile -@@ -146,3 +146,4 @@ obj-$(CONFIG_MEMORY) += memory/ - obj-$(CONFIG_IIO) += iio/ - obj-$(CONFIG_VME_BUS) += vme/ - obj-$(CONFIG_IPACK_BUS) += ipack/ -+obj-$(CONFIG_KDBUS) += kdbus/ ---- /dev/null -+++ b/drivers/kdbus/Kconfig -@@ -0,0 +1,5 @@ -+config KDBUS -+ tristate "kdbus interprocess message router" -+ help -+ kdbus provides efficient kernel-aided message exchange and routing -+ between processes. It is used as the low-level transport of D-Bus. ---- /dev/null -+++ b/drivers/kdbus/Makefile -@@ -0,0 +1,4 @@ -+dbus-y := kdbus.o ep.o bus.o ns.o -+ -+obj-$(CONFIG_KDBUS) += dbus.o -+ ---- /dev/null -+++ b/drivers/kdbus/bus.c -@@ -0,0 +1,122 @@ -+/* -+ * Copyright (C) 2013 Kay Sievers -+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013 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/module.h> -+#include <linux/device.h> -+#include <linux/idr.h> -+#include <linux/fs.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <uapi/kdbus/kdbus.h> -+ -+#include "kdbus.h" -+ -+void kdbus_release(struct device *dev) -+{ -+ kfree(dev); -+} -+ -+ -+struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus) -+{ -+ if (!bus) -+ return NULL; -+ bus->ref++; -+ return bus; -+} -+ -+struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus) -+{ -+ if (!bus) -+ return NULL; -+ bus->ref--; -+ if (bus->ref > 0) -+ return bus; -+ -+ kdbus_bus_disconnect(bus); -+ pr_info("clean up bus %s/%s\n", -+ bus->ns->devpath, bus->name); -+ -+ kfree(bus->name); -+ kfree(bus); -+ return NULL; -+} -+ -+void kdbus_bus_disconnect(struct kdbus_bus *bus) -+{ -+ struct kdbus_ep *ep, *tmp; -+ -+ if (bus->disconnected) -+ return; -+ bus->disconnected = true; -+ -+ /* remove default endpoint */ -+ kdbus_ep_disconnect(bus->ep); -+ kdbus_ep_unref(bus->ep); -+ -+ /* remove any endpoints attached to this bus */ -+ list_for_each_entry_safe(ep, tmp, &bus->ep_list, bus_entry) { -+ kdbus_ep_disconnect(ep); -+ kdbus_ep_unref(ep); -+ } -+ -+ pr_info("closing bus %s/%s\n", bus->ns->devpath, bus->name); -+} -+ -+int kdbus_bus_new(struct kdbus_ns *ns, const char *name, umode_t mode, -+ uid_t uid, gid_t gid, struct kdbus_bus **bus) -+{ -+ struct kdbus_bus *b; -+ int err; -+ -+ b = kzalloc(sizeof(struct kdbus_bus), GFP_KERNEL); -+ if (!b) -+ return -ENOMEM; -+ -+ b->ref = 1; -+ b->ns = ns; -+ /* connection 0 == kernel/multi-cast */ -+ b->conn_id_next = 1; -+ mutex_init(&b->lock); -+ idr_init(&b->conn_idr); -+ INIT_LIST_HEAD(&b->ep_list); -+ -+ if (uid > 0) -+ b->name = kasprintf(GFP_KERNEL, "%u-%s", uid, name); -+ else -+ b->name = kstrdup(name, GFP_KERNEL); -+ if (!b->name) { -+ err = -ENOMEM; -+ goto err; -+ } -+ -+ err = kdbus_ep_new(b, "bus", mode, uid, gid, &b->ep); -+ if (err < 0) -+ goto err; -+ -+ mutex_lock(&ns->lock); -+ b->id = ns->bus_id_next++; -+ mutex_unlock(&ns->lock); -+ -+ *bus = b; -+ pr_info("created bus %llu '%s/%s'\n", -+ (unsigned long long)b->id, ns->devpath, b->name); -+ return 0; -+err: -+ kdbus_bus_unref(b); -+ return err; -+} -+ -+ ---- /dev/null -+++ b/drivers/kdbus/ep.c -@@ -0,0 +1,200 @@ -+/* -+ * Copyright (C) 2013 Kay Sievers -+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013 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/module.h> -+#include <linux/device.h> -+#include <linux/idr.h> -+#include <linux/fs.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <uapi/linux/major.h> -+#include <uapi/kdbus/kdbus.h> -+ -+#include "kdbus.h" -+ -+/* endpoints are by default owned by the bus owner */ -+static char *kdbus_devnode_ep(struct device *dev, -+ umode_t *mode, uid_t *uid, gid_t *gid) -+{ -+ struct kdbus_ep *ep = dev_get_drvdata(dev); -+ -+ if (mode) -+ *mode = ep->mode; -+ if (uid) -+ *uid = ep->uid; -+ if (gid) -+ *gid = ep->gid; -+ return NULL; -+} -+ -+static struct device_type kdbus_devtype_ep = { -+ .name = "ep", -+ .release = kdbus_release, -+ .devnode = kdbus_devnode_ep, -+}; -+ -+struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep) -+{ -+ if (!ep) -+ return NULL; -+ ep->ref++; -+ return ep; -+} -+ -+void kdbus_ep_disconnect(struct kdbus_ep *ep) -+{ -+ if (ep->disconnected) -+ return; -+ ep->disconnected = true; -+ -+ if (ep->dev) { -+ device_unregister(ep->dev); -+ ep->dev = NULL; -+ } -+ if (ep->minor > 0) { -+ idr_remove(&ep->bus->ns->idr, ep->minor); -+ ep->minor = 0; -+ } -+ pr_info("closing endpoint %s/%s/%s\n", -+ ep->bus->ns->devpath, ep->bus->name, ep->name); -+} -+ -+struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep) -+{ -+ if (!ep) -+ return NULL; -+ ep->ref--; -+ if (ep->ref > 0) -+ return ep; -+ -+ mutex_lock(&ep->bus->lock); -+ kdbus_ep_disconnect(ep); -+ pr_info("clean up endpoint %s/%s/%s\n", -+ ep->bus->ns->devpath, ep->bus->name, ep->name); -+ kdbus_bus_unref(ep->bus); -+ mutex_unlock(&ep->bus->lock); -+ -+ kfree(ep->name); -+ kfree(ep); -+ return NULL; -+} -+ -+/* Find the endpoint for a specific bus */ -+struct kdbus_ep *kdbus_ep_find(struct kdbus_bus *bus, const char *name) -+{ -+ struct kdbus_ep *ep; -+ -+ mutex_lock(&bus->lock); -+ list_for_each_entry(ep, &bus->ep_list, bus_entry) { -+ if (!strcmp(ep->name, name)) -+ goto exit; -+ } -+ /* Endpoint not found so return NULL */ -+ ep = NULL; -+exit: -+ mutex_unlock(&bus->lock); -+ -+ return ep; -+} -+ -+int kdbus_ep_new(struct kdbus_bus *bus, const char *name, umode_t mode, -+ uid_t uid, gid_t gid, struct kdbus_ep **ep) -+{ -+ struct kdbus_ep *e; -+ int err; -+ int i; -+ -+ e = kzalloc(sizeof(struct kdbus_ep), GFP_KERNEL); -+ if (!e) -+ return -ENOMEM; -+ -+ mutex_lock(&bus->ns->lock); -+ e->ref = 1; -+ e->mode = mode; -+ e->uid = uid; -+ e->gid = gid; -+ -+ e->name = kstrdup(name, GFP_KERNEL); -+ if (!e->name) { -+ err = -ENOMEM; -+ goto err; -+ } -+ -+ /* register minor in our endpoint map */ -+ if (!idr_pre_get(&bus->ns->idr, GFP_KERNEL)) { -+ err = -ENOMEM; -+ goto err_unlock; -+ } -+ err = idr_get_new_above(&bus->ns->idr, e, 1, &i); -+ if (err < 0) -+ goto err_unlock; -+ e->minor = i; -+ -+ /* get id for this endpoint from bus */ -+ mutex_lock(&bus->lock); -+ e->id = bus->ep_id_next++; -+ mutex_unlock(&bus->lock); -+ -+ /* register bus endpoint device */ -+ e->dev = kzalloc(sizeof(struct device), GFP_KERNEL); -+ if (!e->dev) -+ goto err; -+ dev_set_name(e->dev, "%s/%s/%s", bus->ns->devpath, bus->name, name); -+ e->dev->bus = &kdbus_subsys; -+ e->dev->type = &kdbus_devtype_ep; -+ e->dev->devt = MKDEV(bus->ns->major, e->minor); -+ dev_set_drvdata(e->dev, e); -+ err = device_register(e->dev); -+ if (err < 0) { -+ put_device(e->dev); -+ e->dev = NULL; -+ } -+ -+ init_waitqueue_head(&e->wait); -+ -+ /* Link this endpoint to the bus it is on */ -+ e->bus = kdbus_bus_ref(bus); -+ list_add_tail(&e->bus_entry, &bus->ep_list); -+ -+ mutex_unlock(&bus->ns->lock); -+ -+ if (ep) -+ *ep = e; -+ pr_info("created endpoint %llu for bus '%s/%s/%s'\n", -+ (unsigned long long)e->id, bus->ns->devpath, bus->name, name); -+ return 0; -+ -+err_unlock: -+ mutex_unlock(&bus->ns->lock); -+err: -+ kdbus_ep_unref(e); -+ return err; -+} -+ -+int kdbus_ep_remove(struct kdbus_ep *ep) -+{ -+ struct kdbus_bus *bus = ep->bus; -+ -+ mutex_lock(&bus->ns->lock); -+ device_unregister(ep->dev); -+ list_del(&ep->bus_entry); -+ kdbus_ep_unref(ep); -+ mutex_unlock(&bus->ns->lock); -+ kdbus_bus_unref(bus); -+ return 0; -+} -+ -+ ---- /dev/null -+++ b/drivers/kdbus/kdbus.c -@@ -0,0 +1,611 @@ -+/* -+ * kdbus - interprocess message routing -+ * -+ * Copyright (C) 2013 Kay Sievers -+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013 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/module.h> -+#include <linux/device.h> -+#include <linux/idr.h> -+#include <linux/fs.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/mutex.h> -+#include <linux/init.h> -+#include <linux/poll.h> -+//#include <asm/uaccess.h> -+#include <uapi/linux/major.h> -+#include <uapi/kdbus/kdbus.h> -+ -+#include "kdbus.h" -+ -+/* -+ * TODO: -+ * - set parent for driver-core /sys/devices/kdbus!... devices to virtual/kdbus/, -+ * the bus subsys misses the "no parent" logic the class subsys has -+ * -+ * - switch to a 64bit idr for connection id <--> kdbus_conn -+ */ -+ -+/* -+ * Example of device nodes in /dev. For any future changes, keep in mind, -+ * that the layout should support a possible /dev/kdbus/ filesystem for the -+ * init namspace and one for each sub-namespace. -+ * -+ * /dev/kdbus/ -+ * |-- control -+ * |-- system -+ * | |-- bus -+ * | |-- ep-epiphany -+ * | `-- ep-firefox -+ * |-- 2702-user -+ * | `-- bus -+ * |-- 1000-user -+ * | `-- bus -+ * `-- ns -+ * |-- myfedoracontainer -+ * | |-- control -+ * | |-- system -+ * | | `-- bus -+ * | `-- 1000-user -+ * | `-- bus -+ * `-- mydebiancontainer -+ * |-- control -+ * |-- system -+ * `-- bus -+ */ -+ -+/* kdbus sysfs subsystem */ -+struct bus_type kdbus_subsys = { -+ .name = "kdbus", -+}; -+ -+/* List of all connections in the system. */ -+/* Well, really only the endpoint connections, -+ * that's all we care about for now */ -+static LIST_HEAD(connection_list); -+ -+/* kdbus initial namespace */ -+static struct kdbus_ns *kdbus_ns_init; -+ -+/* map of majors to namespaces */ -+DEFINE_IDR(kdbus_ns_major_idr); -+ -+/* namespace list lock */ -+DEFINE_MUTEX(kdbus_subsys_lock); -+ -+static int kdbus_msg_new(struct kdbus_conn *conn, struct kdbus_msg __user *umsg, -+ struct kdbus_msg **msg); -+static int kdbus_msg_send(struct kdbus_conn *conn, struct kdbus_msg *msg); -+ -+ -+static void kdbus_msg_release(struct kref *kref) -+{ -+ struct kdbus_test_msg *msg = container_of(kref, struct kdbus_test_msg, kref); -+ kfree(msg); -+} -+ -+ -+/* kdbus file operations */ -+static int kdbus_conn_open(struct inode *inode, struct file *file) -+{ -+ struct kdbus_conn *conn; -+ struct kdbus_ns *ns; -+ struct kdbus_ep *ep; -+ int i; -+ int err; -+ -+ conn = kzalloc(sizeof(struct kdbus_conn), GFP_KERNEL); -+ if (!conn) -+ return -ENOMEM; -+ -+ /* find and reference namespace */ -+ mutex_lock(&kdbus_subsys_lock); -+ ns = idr_find(&kdbus_ns_major_idr, MAJOR(inode->i_rdev)); -+ if (!ns || ns->disconnected) { -+ kfree(conn); -+ mutex_unlock(&kdbus_subsys_lock); -+ return -ENOENT; -+ } -+ conn->ns = kdbus_ns_ref(ns); -+ file->private_data = conn; -+ mutex_unlock(&kdbus_subsys_lock); -+ -+ /* control device node */ -+ if (MINOR(inode->i_rdev) == 0) { -+ conn->type = KDBUS_CONN_CONTROL; -+ file->private_data = conn; -+ pr_info("opened control device '%s/control'\n", -+ conn->ns->devpath); -+ return 0; -+ } -+ -+ /* find endpoint for device node */ -+ mutex_lock(&conn->ns->lock); -+ ep = idr_find(&conn->ns->idr, MINOR(inode->i_rdev)); -+ if (!ep || ep->disconnected) { -+ err = -ENOENT; -+ goto err_unlock; -+ } -+ -+ /* create endpoint connection */ -+ conn->type = KDBUS_CONN_EP; -+ conn->ep = kdbus_ep_ref(ep); -+ -+ /* get and register new id for this connection */ -+ conn->id = conn->ep->bus->conn_id_next++; -+ if (!idr_pre_get(&conn->ep->bus->conn_idr, GFP_KERNEL)) { -+ err = -ENOMEM; -+ goto err_unlock; -+ } -+ /* FIXME: get 64 bit working, this will fail for the 2^31th connection */ -+ err = idr_get_new_above(&conn->ep->bus->conn_idr, conn, conn->id, &i); -+ if (err >= 0 && conn->id != i) { -+ idr_remove(&conn->ep->bus->conn_idr, i); -+ err = -EEXIST; -+ goto err_unlock; -+ } -+ -+ mutex_init(&conn->msg_lock); -+ INIT_LIST_HEAD(&conn->msg_list); -+ -+ list_add_tail(&connection_list, &conn->connection_entry); -+ -+ file->private_data = conn; -+ mutex_unlock(&conn->ns->lock); -+ -+ pr_info("created endpoint bus connection %llu '%s/%s'\n", -+ (unsigned long long)conn->id, conn->ns->devpath, -+ conn->ep->bus->name); -+ return 0; -+ -+err_unlock: -+ mutex_unlock(&conn->ns->lock); -+ kfree(conn); -+ return err; -+} -+ -+static int kdbus_conn_release(struct inode *inode, struct file *file) -+{ -+ struct kdbus_conn *conn = file->private_data; -+ struct kdbus_test_msg *msg; -+ struct kdbus_msg_list_entry *msg_entry, *tmp_entry; -+ -+ switch (conn->type) { -+ case KDBUS_CONN_NS_OWNER: -+ break; -+ -+ case KDBUS_CONN_BUS_OWNER: -+ kdbus_bus_disconnect(conn->bus_owner); -+ kdbus_bus_unref(conn->bus_owner); -+ break; -+ -+ case KDBUS_CONN_EP: -+ kdbus_ep_unref(conn->ep); -+ list_del(&conn->connection_entry); -+ /* clean up any messages still left on this endpoint */ -+ mutex_lock(&conn->msg_lock); -+ list_for_each_entry_safe(msg_entry, tmp_entry, &conn->msg_list, entry) { -+ msg = msg_entry->msg; -+ list_del(&msg_entry->entry); -+ kfree(msg_entry); -+ kref_put(&msg->kref, kdbus_msg_release); -+ } -+ mutex_unlock(&conn->msg_lock); -+ -+ break; -+ -+ default: -+ break; -+ } -+ -+ mutex_lock(&conn->ns->lock); -+ kdbus_ns_unref(conn->ns); -+ mutex_unlock(&conn->ns->lock); -+ kfree(conn); -+ return 0; -+} -+ -+/* kdbus control device commands */ -+static long kdbus_conn_ioctl_control(struct file *file, unsigned int cmd, -+ void __user *argp) -+{ -+ struct kdbus_conn *conn = file->private_data; -+ struct kdbus_cmd_name name; -+ struct kdbus_bus *bus = NULL; -+ struct kdbus_ns *ns = NULL; -+ int err; -+ -+ switch (cmd) { -+ case KDBUS_CMD_BUS_CREATE: -+ if (copy_from_user(&name, argp, sizeof(struct kdbus_cmd_name))) -+ return -EFAULT; -+ -+ err = kdbus_bus_new(conn->ns, name.name, -+ 0660, current_fsuid(), current_fsgid(), -+ &bus); -+ if (err < 0) -+ return err; -+ -+ /* turn the control fd into a new bus owner device */ -+ conn->type = KDBUS_CONN_BUS_OWNER; -+ conn->bus_owner = bus; -+ break; -+ -+#if 0 /* FIXME Don't know if we really want this... */ -+ case KDBUS_CMD_BUS_REMOVE: -+ if (copy_from_user(&name, argp, sizeof(struct kdbus_cmd_name))) -+ return -EFAULT; -+ -+ bus = kdbus_bus_find(name.name); -+ if (!bus) -+ return -EINVAL; -+ kdbus_bus_disconnect(bus); // FIXME needed? -+ kdbus_bus_unref(bus); -+ break; -+#endif -+ case KDBUS_CMD_NS_CREATE: -+ if (copy_from_user(&name, argp, sizeof(struct kdbus_cmd_name))) -+ return -EFAULT; -+ -+ err = kdbus_ns_new(kdbus_ns_init, name.name, &ns); -+ if (err < 0) { -+ pr_err("failed to create namespace %s, err=%i\n", -+ name.name, err); -+ return err; -+ } -+ break; -+ -+ case KDBUS_CMD_NS_REMOVE: -+ if (copy_from_user(&name, argp, sizeof(struct kdbus_cmd_name))) -+ return -EFAULT; -+ -+ ns = kdbus_ns_find(name.name); -+ if (!ns) -+ return -EINVAL; -+ -+ /* we can not remove the "default" namespace */ -+ if (ns == kdbus_ns_init) -+ return -EINVAL; -+ -+ kdbus_ns_unref(ns); -+ break; -+ -+ default: -+ return -ENOTTY; -+ } -+ return 0; -+} -+ -+/* kdbus bus endpoint commands */ -+static long kdbus_conn_ioctl_ep(struct file *file, unsigned int cmd, -+ void __user *argp) -+{ -+ struct kdbus_conn *conn = file->private_data; -+ struct kdbus_cmd_name name; -+ struct kdbus_msg *msg; -+ struct kdbus_ep *ep; -+ long err; -+ -+ /* We need a connection before we can do anything with an ioctl */ -+ if (!conn) -+ return -EINVAL; -+ -+ switch (cmd) { -+ case KDBUS_CMD_EP_CREATE: -+ /* create a new endpoint for this bus */ -+ if (copy_from_user(&name, argp, sizeof(struct kdbus_cmd_name))) -+ return -EFAULT; -+ return kdbus_ep_new(conn->ep->bus, name.name, -+ 0660, current_fsuid(), current_fsgid(), -+ NULL); -+ -+ case KDBUS_CMD_EP_REMOVE: -+ /* remove an endpoint from this bus */ -+ if (copy_from_user(&name, argp, sizeof(struct kdbus_cmd_name))) -+ return -EFAULT; -+ ep = kdbus_ep_find(conn->bus_owner, name.name); -+ if (!ep) -+ return -EINVAL; -+ -+ return kdbus_ep_remove(ep); -+ -+ case KDBUS_CMD_EP_POLICY_SET: -+ /* upload a policy for this bus */ -+ return -ENOSYS; -+ -+ case KDBUS_CMD_NAME_ACQUIRE: -+ /* acquire a well-known name */ -+ return -ENOSYS; -+ -+ case KDBUS_CMD_NAME_RELEASE: -+ /* release a well-known name */ -+ return -ENOSYS; -+ -+ case KDBUS_CMD_NAME_LIST: -+ /* return all current well-known names */ -+ return -ENOSYS; -+ -+ case KDBUS_CMD_MATCH_ADD: -+ /* subscribe to/filter for broadcast messages */ -+ return -ENOSYS; -+ -+ case KDBUS_CMD_MATCH_REMOVE: -+ /* unsubscribe from broadcast messages */ -+ return -ENOSYS; -+ -+ case KDBUS_CMD_MSG_SEND: -+ /* send a message */ -+ err = kdbus_msg_new(conn, argp, &msg); -+ if (err < 0) -+ return err; -+ return kdbus_msg_send(conn, msg); -+ -+ case KDBUS_CMD_MSG_RECV: -+ /* receive a message, needs to be freed */ -+ return -ENOSYS; -+ -+ default: -+ return -ENOTTY; -+ } -+} -+ -+static long kdbus_conn_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct kdbus_conn *conn = file->private_data; -+ void __user *argp = (void __user *)arg; -+ -+ pr_info("%s, cmd=%d\n", __func__, cmd); -+ switch (conn->type) { -+ case KDBUS_CONN_CONTROL: -+ pr_info("control ioctl\n"); -+ return kdbus_conn_ioctl_control(file, cmd, argp); -+ -+ case KDBUS_CONN_EP: -+ pr_info("endpoint ioctl\n"); -+ return kdbus_conn_ioctl_ep(file, cmd, argp); -+ -+ default: -+ pr_info("bad type\n"); -+ return -EINVAL; -+ } -+} -+ -+static unsigned int kdbus_conn_poll(struct file *file, -+ struct poll_table_struct *wait) -+{ -+ struct kdbus_conn *conn = file->private_data; -+ unsigned int mask = 0; -+ -+ /* Only an endpoint can read/write data */ -+ if (conn->type != KDBUS_CONN_EP) -+ return POLLERR | POLLHUP; -+ -+ poll_wait(file, &conn->ep->wait, wait); -+ -+ mutex_lock(&conn->msg_lock); -+ if (!list_empty(&conn->msg_list)) -+ mask |= POLLIN | POLLRDNORM; -+ mutex_unlock(&conn->msg_lock); -+ -+ return 0; -+} -+ -+static int kdbus_conn_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ return -EINVAL; -+} -+ -+static ssize_t kdbus_conn_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) -+{ -+ struct kdbus_conn *conn = file->private_data; -+ struct kdbus_conn *temp_conn; -+ struct kdbus_test_msg *msg; -+ -+ /* Only an endpoint can read/write data */ -+ if (conn->type != KDBUS_CONN_EP) -+ return -EINVAL; -+ -+ /* FIXME: Let's cap a message size at PAGE_SIZE for now */ -+ if (count > PAGE_SIZE) -+ return -EINVAL; -+ -+ if (count == 0) -+ return 0; -+ -+ msg = kmalloc((sizeof(*msg) + count), GFP_KERNEL); -+ if (!msg) -+ return -ENOMEM; -+ -+ if (copy_from_user(&msg->data[0], ubuf, count)) -+ return -EFAULT; -+ -+ kref_init(&msg->kref); -+ msg->length = count; -+ -+ /* Walk the list of connections, -+ * find any endpoints that match our endpoint, -+ * create a kdbus_msg_list_entry for it, -+ * attach the message to the endpoint list, -+ * wake the connection up. */ -+ -+ /* what do we lock here? FIXME */ -+ -+ list_for_each_entry(temp_conn, &connection_list, connection_entry) { -+ if (temp_conn->type != KDBUS_CONN_EP) -+ continue; -+ if (temp_conn->ep == conn->ep) { -+ /* Matching endpoints */ -+ struct kdbus_msg_list_entry *msg_list_entry; -+ -+ msg_list_entry = kmalloc(sizeof(*msg_list_entry), GFP_KERNEL); -+ kref_get(&msg->kref); -+ msg_list_entry->msg = msg; -+ mutex_lock(&temp_conn->msg_lock); -+ list_add_tail(&temp_conn->msg_list, &msg_list_entry->entry); -+ mutex_unlock(&temp_conn->msg_lock); -+ /* wake up the other processes. Hopefully... */ -+ wake_up_interruptible_all(&temp_conn->ep->wait); -+ } -+ } -+ -+ /* drop our reference on the message, as we are done with it */ -+ kref_put(&msg->kref, kdbus_msg_release); -+ return count; -+} -+ -+static ssize_t kdbus_conn_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) -+{ -+ struct kdbus_conn *conn = file->private_data; -+ struct kdbus_msg_list_entry *msg_list_entry; -+ struct kdbus_test_msg *msg; -+ ssize_t retval = 0; -+ -+ /* Only an endpoint can read/write data */ -+ if (conn->type != KDBUS_CONN_EP) -+ return -EINVAL; -+ -+ if (count == 0) -+ return 0; -+ -+ if (mutex_lock_interruptible(&conn->msg_lock)) -+ return -ERESTARTSYS; -+ -+ while (list_empty(&conn->msg_list)) { -+ /* Nothing to read, so try again or sleep */ -+ mutex_unlock(&conn->msg_lock); -+ -+ if (file->f_flags & O_NONBLOCK) -+ return -EAGAIN; -+ -+ /* sleep until we get something */ -+ if (wait_event_interruptible(conn->ep->wait, list_empty(&conn->msg_list))) -+ return -ERESTARTSYS; -+ -+ if (mutex_lock_interruptible(&conn->msg_lock)) -+ return -ERESTARTSYS; -+ } -+ -+ /* let's grab a message from our list to write out */ -+ if (!list_empty(&conn->msg_list)) { -+ msg_list_entry = list_entry(&conn->msg_list, struct kdbus_msg_list_entry, entry); -+ msg = msg_list_entry->msg; -+ if (msg->length > count) { -+ retval = -E2BIG; // FIXME wrong error code, I know, what should we use? -+ goto exit; -+ } -+ if (copy_to_user(ubuf, &msg->data[0], msg->length)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ list_del(&msg_list_entry->entry); -+ kfree(msg_list_entry); -+ retval = msg->length; -+ kref_put(&msg->kref, kdbus_msg_release); -+ } -+ -+exit: -+ mutex_unlock(&conn->msg_lock); -+ return retval; -+} -+ -+const struct file_operations kdbus_device_ops = { -+ .owner = THIS_MODULE, -+ .open = kdbus_conn_open, -+ .release = kdbus_conn_release, -+ .unlocked_ioctl = kdbus_conn_ioctl, -+ .compat_ioctl = kdbus_conn_ioctl, -+ .poll = kdbus_conn_poll, -+ .mmap = kdbus_conn_mmap, -+ .llseek = noop_llseek, -+ .write = kdbus_conn_write, -+ .read = kdbus_conn_read, -+}; -+ -+static void kdbus_msg_free(struct kdbus_msg *msg) -+{ -+ kfree(msg); -+} -+ -+static int kdbus_msg_new(struct kdbus_conn *conn, struct kdbus_msg __user *umsg, -+ struct kdbus_msg **msg) -+{ -+ struct kdbus_msg *m; -+ int err; -+ -+ m = kmalloc(sizeof(struct kdbus_msg), GFP_KERNEL); -+ if (!m) -+ return -ENOMEM; -+ if (copy_from_user(m, umsg, sizeof(struct kdbus_msg))) { -+ err = -EFAULT; -+ goto out_err; -+ } -+ -+ m->src_id = conn->id; -+ m->msg_id = conn->ep->bus->msg_id_next++; -+ *msg = m; -+ return 0; -+out_err: -+ kdbus_msg_free(m); -+ return err; -+} -+ -+static int kdbus_msg_send(struct kdbus_conn *conn, struct kdbus_msg *msg) -+{ -+ struct kdbus_conn *conn_dst; -+ -+ conn_dst = idr_find(&conn->ep->bus->conn_idr, msg->dst_id); -+ if (!conn_dst) -+ return -ENOENT; -+ -+ pr_info("sending message %llu from %llu to %llu\n", -+ (unsigned long long)msg->msg_id, -+ (unsigned long long)msg->src_id, -+ (unsigned long long)msg->dst_id); -+ -+ kdbus_msg_free(msg); -+ return 0; -+} -+ -+static int __init kdbus_init(void) -+{ -+ int err; -+ -+ err = bus_register(&kdbus_subsys); -+ if (err < 0) -+ return err; -+ -+ err = kdbus_ns_new(NULL, NULL, &kdbus_ns_init); -+ if (err < 0) { -+ bus_unregister(&kdbus_subsys); -+ pr_err("failed to initialize err=%i\n", err); -+ return err; -+ } -+ -+ pr_info("initialized\n"); -+ return 0; -+} -+ -+static void __exit kdbus_exit(void) -+{ -+ kdbus_ns_unref(kdbus_ns_init); -+ bus_unregister(&kdbus_subsys); -+ pr_info("unloaded\n"); -+} -+ -+module_init(kdbus_init); -+module_exit(kdbus_exit); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("kdbus interprocess message router"); -+MODULE_ALIAS_CHARDEV(KDBUS_CHAR_MAJOR, 0); -+MODULE_ALIAS("devname:kdbus/control"); ---- /dev/null -+++ b/drivers/kdbus/kdbus.h -@@ -0,0 +1,185 @@ -+/* -+ * Copyright (C) 2013 Kay Sievers -+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013 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 __INTERNAL_KDBUS_H -+#define __INTERNAL_KDBUS_H -+ -+/* -+ * kdbus namespace -+ * - provides a "control" node -+ * - owns a major number -+ * - owns all created buses -+ * - the initial namespace is unnamed and stays around for forver -+ * - new namespaces are created by opening the control node and -+ * issuing KDBUS_NS_CREATE -+ * - closing the connection destroys the created namespace -+ */ -+struct kdbus_ns { -+ unsigned int ref; /* reference count */ -+ const char *name; /* name of the namespace */ -+ bool disconnected; /* invalidated data */ -+ struct kdbus_ns *parent;/* parent namespace */ -+ __u64 id; /* global id of this namespace */ -+ const char *devpath; /* /dev base directory path */ -+ int major; /* device major number for all nodes */ -+ struct idr idr; /* map of endpoint minors to buses */ -+ struct device *dev; /* control device node, minor == 0 */ -+ struct mutex lock; /* ns data lock */ -+ __u64 bus_id_next; /* next bus id sequence number */ -+ struct list_head list_entry; -+}; -+ -+/* -+ * kdbus bus -+ * - provides a "bus" endpoint -+ * - owns additional endpoints -+ * - own all bus connections -+ * - new buses are created by opening the control node and -+ * issuing KDBUS_BUS_CREATE -+ * - closing the connection destroys the created bus -+ */ -+struct kdbus_bus { -+ unsigned int ref; /* reference count */ -+ bool disconnected; /* invalidated data */ -+ struct kdbus_ns *ns; /* namespace of this bus */ -+ const char *name; /* bus name */ -+ __u64 id; /* id of this bus in the namespace */ -+ struct mutex lock; /* bus data lock */ -+ __u64 ep_id_next; /* next endpoint id sequence number */ -+ __u64 conn_id_next; /* next connection id sequence number */ -+ __u64 msg_id_next; /* next message id sequence number */ -+ struct idr conn_idr; /* map of connection ids */ -+ struct kdbus_ep *ep; /* "bus" default endpoint */ -+ struct list_head ep_list; /* endpoints assigned to this bus */ -+}; -+ -+/* -+ * kdbus endpoint -+ * - offers access to a bus, the default device node name is "bus" -+ * - additional endpoints can carry a specific policy/filters -+ */ -+struct kdbus_ep { -+ unsigned int ref; /* reference count */ -+ bool disconnected; /* invalidated data */ -+ struct kdbus_bus *bus; /* bus behind this endpoint */ -+ const char *name; /* name, prefixed with uid */ -+ __u64 id; /* id of this endpoint on the bus */ -+ unsigned int minor; /* minor of this endpoint in the namespace major */ -+ struct device *dev; /* device node of this endpoint */ -+ umode_t mode; /* file mode of this endpoint device node */ -+ uid_t uid; /* uid owning this endpoint */ -+ gid_t gid; /* gid owning this endpoint */ -+ struct list_head bus_entry; /* list of endpoints for this bus */ -+ struct list_head message_list; /* messages in flight for this endpoint */ -+ wait_queue_head_t wait; /* wake up this endpoint */ -+}; -+ -+/* -+ * kdbus connection -+ * - connection to a control node or an endpoint -+ */ -+enum kdbus_conn_type { -+ KDBUS_CONN_UNDEFINED, -+ KDBUS_CONN_CONTROL, -+ KDBUS_CONN_NS_OWNER, -+ KDBUS_CONN_BUS_OWNER, -+ KDBUS_CONN_EP, -+}; -+ -+struct kdbus_conn { -+ enum kdbus_conn_type type; -+ struct kdbus_ns *ns; -+ union { -+ struct kdbus_ns *ns_owner; -+ struct kdbus_bus *bus_owner; -+ struct kdbus_ep *ep; -+ }; -+ __u64 id; /* id of the connection on the bus */ -+ -+ /* -+ * first, horrible cut at messages assigned to connections -+ * odds are, this is going to be slow, but let's measure it first to -+ * see what the real numbers are, and where the bottlenecks are. -+ * Premature optimization and all... -+ */ -+ struct mutex msg_lock; -+ struct list_head msg_list; -+ -+ /* Ugh a list of all connections in the system? Ugly, but we need to -+ * be able to walk them all somehow. Maybe just have a list on the -+ * endpoints of the connections associated with that endpoint? That's -+ * all we really need in the end... */ -+ struct list_head connection_entry; -+}; -+ -+/* kdbus message */ -+enum kdbus_msg_data_type { -+ KDBUS_MSG_DATA_UNDEFINED, -+ KDBUS_MSG_DATA_MEM, -+}; -+ -+struct kdbus_msg_data { -+ u64 data; -+ u64 size; -+ u32 type; -+ u32 flags; -+}; -+ -+/* To knock around with for now */ -+struct kdbus_test_msg { -+ struct kref kref; -+ u32 length; -+ u8 data[0]; -+}; -+ -+struct kdbus_msg_list_entry { -+ struct kdbus_test_msg *msg; -+ struct list_head entry; -+}; -+ -+/* namespace stuff */ -+ -+extern const struct file_operations kdbus_device_ops; -+extern struct mutex kdbus_subsys_lock; -+extern struct idr kdbus_ns_major_idr; -+struct kdbus_ns *kdbus_ns_ref(struct kdbus_ns *ns); -+void kdbus_ns_disconnect(struct kdbus_ns *ns); -+struct kdbus_ns *kdbus_ns_unref(struct kdbus_ns *ns); -+int kdbus_ns_new(struct kdbus_ns *parent, const char *name, struct kdbus_ns **ns); -+struct kdbus_ns *kdbus_ns_find(const char *name); -+ -+ -+/* bus stuff */ -+extern struct bus_type kdbus_subsys; -+void kdbus_release(struct device *dev); -+ -+struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus); -+struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus); -+void kdbus_bus_disconnect(struct kdbus_bus *bus); -+int kdbus_bus_new(struct kdbus_ns *ns, const char *name, umode_t mode, -+ uid_t uid, gid_t gid, struct kdbus_bus **bus); -+ -+ -+/* endpoint stuff */ -+struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep); -+struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep); -+ -+struct kdbus_ep *kdbus_ep_find(struct kdbus_bus *bus, const char *name); -+int kdbus_ep_new(struct kdbus_bus *bus, const char *name, umode_t mode, -+ uid_t uid, gid_t gid, struct kdbus_ep **ep); -+int kdbus_ep_remove(struct kdbus_ep *ep); -+void kdbus_ep_disconnect(struct kdbus_ep *ep); -+ -+ -+ -+#endif ---- /dev/null -+++ b/drivers/kdbus/ns.c -@@ -0,0 +1,217 @@ -+/* -+ * Copyright (C) 2013 Kay Sievers -+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013 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/module.h> -+#include <linux/device.h> -+#include <linux/idr.h> -+#include <linux/fs.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <uapi/linux/major.h> -+#include <uapi/kdbus/kdbus.h> -+ -+#include "kdbus.h" -+ -+/* global list of all namespaces */ -+static LIST_HEAD(namespace_list); -+ -+/* next namespace id sequence number */ -+static __u64 kdbus_ns_id_next; -+ -+/* control nodes are world accessible */ -+static char *kdbus_devnode_control(struct device *dev, -+ umode_t *mode, uid_t *uid, gid_t *gid) -+{ -+ if (mode) -+ *mode = 0666; -+ return NULL; -+} -+ -+static struct device_type kdbus_devtype_control = { -+ .name = "control", -+ .release = kdbus_release, -+ .devnode = kdbus_devnode_control, -+}; -+ -+ -+/* kdbus namespace */ -+struct kdbus_ns *kdbus_ns_ref(struct kdbus_ns *ns) -+{ -+ if (!ns) -+ return NULL; -+ ns->ref++; -+ return ns; -+} -+ -+void kdbus_ns_disconnect(struct kdbus_ns *ns) -+{ -+ if (ns->disconnected) -+ return; -+ ns->disconnected = true; -+ -+ if (ns->dev) { -+ device_unregister(ns->dev); -+ ns->dev = NULL; -+ } -+ if (ns->major > 0) { -+ idr_remove(&kdbus_ns_major_idr, ns->major); -+ unregister_chrdev(ns->major, "kdbus"); -+ ns->major = 0; -+ } -+ pr_info("closing namespace %s\n", ns->devpath); -+} -+ -+struct kdbus_ns *kdbus_ns_unref(struct kdbus_ns *ns) -+{ -+ if (!ns) -+ return NULL; -+ ns->ref--; -+ if (ns->ref > 0) -+ return ns; -+ -+ kdbus_ns_disconnect(ns); -+ pr_info("clean up namespace %s\n", ns->devpath); -+ list_del(&ns->list_entry); -+ kfree(ns->name); -+ kfree(ns->devpath); -+ kfree(ns); -+ return NULL; -+} -+ -+int kdbus_ns_new(struct kdbus_ns *parent, const char *name, struct kdbus_ns **ns) -+{ -+ struct kdbus_ns *n; -+ const char *ns_name = NULL; -+ int i; -+ int err; -+ -+ pr_info("%s, %s\n", __func__, name); -+ -+ if ((parent && !name) || (!parent && name)) -+ return -EINVAL; -+ -+ n = kzalloc(sizeof(struct kdbus_ns), GFP_KERNEL); -+ if (!n) -+ return -ENOMEM; -+ -+ if (name) { -+ ns_name = kstrdup(name, GFP_KERNEL); -+ if (!ns_name) { -+ kfree(n); -+ return -ENOMEM; -+ } -+ } -+ -+ n->ref = 1; -+ idr_init(&n->idr); -+ mutex_init(&n->lock); -+ -+ /* compose name and path of base directory in /dev */ -+ if (!parent) { -+ /* initial namespace */ -+ n->devpath = kstrdup("kdbus", GFP_KERNEL); -+ if (!n->devpath) { -+ err = -ENOMEM; -+ goto err; -+ } -+ -+ /* register static major to support module auto-loading */ -+ err = register_chrdev(KDBUS_CHAR_MAJOR, "kdbus", &kdbus_device_ops); -+ if (err) -+ goto err; -+ n->major = KDBUS_CHAR_MAJOR; -+ } else { -+ n->parent = parent; -+ n->devpath = kasprintf(GFP_KERNEL, "kdbus/ns/%s/%s", parent->devpath, name); -+// n->devpath = kasprintf(GFP_KERNEL, "kdbus/ns/%s", name); -+ if (!n->devpath) { -+ err = -ENOMEM; -+ goto err; -+ } -+ -+ /* get dynamic major */ -+ n->major = register_chrdev(0, "kdbus", &kdbus_device_ops); -+ if (n->major < 0) { -+ err = n->major; -+ goto err; -+ } -+ n->name = ns_name; -+ } -+ -+ /* register major in our namespace map */ -+ mutex_lock(&kdbus_subsys_lock); -+ if (!idr_pre_get(&kdbus_ns_major_idr, GFP_KERNEL)) { -+ err = -ENOMEM; -+ goto err_unlock; -+ } -+ err = idr_get_new_above(&kdbus_ns_major_idr, n, n->major, &i); -+ if (err >= 0 && n->major != i) { -+ idr_remove(&kdbus_ns_major_idr, i); -+ err = -EEXIST; -+ goto err_unlock; -+ } -+ -+ /* get id for this namespace */ -+ n->id = kdbus_ns_id_next++; -+ -+ /* register control device for this namespace */ -+ n->dev = kzalloc(sizeof(struct device), GFP_KERNEL); -+ if (!n->dev) -+ goto err_unlock; -+ dev_set_name(n->dev, "%s/%s", n->devpath, "control"); -+ n->dev->bus = &kdbus_subsys; -+ n->dev->type = &kdbus_devtype_control; -+ n->dev->devt = MKDEV(n->major, 0); -+ dev_set_drvdata(n->dev, n); -+ err = device_register(n->dev); -+ if (err < 0) { -+ put_device(n->dev); -+ n->dev = NULL; -+ goto err_unlock; -+ } -+ -+ /* Add to global list of namespaces so we can find it again */ -+ list_add_tail(&n->list_entry, &namespace_list); -+ -+ mutex_unlock(&kdbus_subsys_lock); -+ -+ *ns = n; -+ pr_info("created namespace %llu '%s/'\n", -+ (unsigned long long)n->id, n->devpath); -+ return 0; -+ -+err_unlock: -+ mutex_unlock(&kdbus_subsys_lock); -+err: -+ kdbus_ns_unref(n); -+ return err; -+} -+ -+struct kdbus_ns *kdbus_ns_find(const char *name) -+{ -+ struct kdbus_ns *ns; -+ -+ mutex_lock(&kdbus_subsys_lock); -+ list_for_each_entry(ns, &namespace_list, list_entry) { -+ if (!strcmp(ns->name, name)) -+ goto exit; -+ } -+ /* namespace not found so return NULL */ -+ ns = NULL; -+exit: -+ mutex_unlock(&kdbus_subsys_lock); -+ return ns; -+} -+ ---- /dev/null -+++ b/include/uapi/kdbus/kdbus.h -@@ -0,0 +1,123 @@ -+/* -+ * Copyright (C) 2013 Kay Sievers -+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013 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_H_ -+#define _KDBUS_H_ -+ -+#define KDBUS_IOC_MAGIC 0x95 -+ -+/* kdbus control device commands */ -+struct kdbus_cmd_name { -+ uint64_t capabilities; -+ char name[256]; -+ char reserved[256]; -+}; -+ -+struct kdbus_fake_message { -+ char msg[256]; /* FIXME obviously... */ -+}; -+ -+/** -+ * struct kdbus_msg -+ * -+ * set by userspace: -+ * dst_id: destination id -+ * filter: bloom filter for the kernel to use to filter messages -+ * data_count: number of data structures for this message -+ * data: data for the message -+ * -+ * set by kernel: -+ * msg_id: message id, to allow userspace to sort messages -+ * src_id: who sent the message -+ * src_uid: uid of sending process -+ * src_gid: gid of sending process -+ * src_pid: pid of sending process -+ * src_tid: tid of sending process -+ * ts_nsec: timestamp when message was sent to the kernel -+ * -+ */ -+struct kdbus_msg { -+ __u64 dst_id; -+ __u64 filter; -+ -+ __u64 msg_id; -+ __u64 src_id; -+ __u64 flags; -+ __kernel_uid_t src_uid; -+ __kernel_gid_t src_gid; -+ __kernel_pid_t src_pid; -+ __kernel_pid_t src_tid; -+ __u64 ts_nsec; -+ __u64 reserved[8]; -+ __u32 data_count; -+ struct kdbus_msg_data *data; -+}; -+ -+ -+ -+#if 0 -+/* Old-style dbus had the following message type: */ -+struct old_dbus_header { -+ u8 endianness; /* 'l' for little endian, 'B' for big endian */ -+ u8 type; /* message type */ -+ u8 flags; -+ u8 protocol_version; -+ u32 message_length -+ u32 cookie; -+} -+ -+#define DBUS_TYPE_INVALID 0 -+#define DBUS_TYPE_METHOD_CALL 1 -+#define DBUS_TYPE_METHOD_RETURN 2 -+#define DBUS_TYPE_ERROR 3 -+#define DBUS_TYPE_SIGNAL 4 -+ -+#define DBUS_FLAG_NO_REPLY_EXPECTED 0x01 -+#define DBUS_FLAG_NO_AUTO_START 0x02 -+ -+#define DBUS_FIELD_INVALID 0 -+#define DBUS_FIELD_PATH 1 -+#define DBUS_FIELD_INTERFACE 2 -+#define DBUS_FIELD_MEMBER 3 -+#define DBUS_FIELD_ERROR_NAME 4 -+#define DBUS_FIELD_REPLY_SERIAL 5 -+#define DBUS_FIELD_DESTINATION 6 -+#define DBUS_FIELD_SENDER 7 -+#define DBUS_FIELD_SIGNATURE 8 -+#define DBUS_FIELD_UNIX_FDS 9 -+ -+#endif -+ -+enum kdbus_cmd { -+ /* kdbus control commands */ -+ KDBUS_CMD_BUS_CREATE = _IOW(KDBUS_IOC_MAGIC, 0x00, struct kdbus_cmd_name), -+ KDBUS_CMD_BUS_REMOVE = _IOW(KDBUS_IOC_MAGIC, 0x01, struct kdbus_cmd_name), -+ KDBUS_CMD_NS_CREATE = _IOW(KDBUS_IOC_MAGIC, 0x10, struct kdbus_cmd_name), -+ KDBUS_CMD_NS_REMOVE = _IOW(KDBUS_IOC_MAGIC, 0x11, struct kdbus_cmd_name), -+ -+ /* kdbus endpoint commands */ -+ KDBUS_CMD_EP_CREATE = _IOWR(KDBUS_IOC_MAGIC, 0x30, struct kdbus_cmd_name), -+ KDBUS_CMD_EP_REMOVE = _IOWR(KDBUS_IOC_MAGIC, 0x31, struct kdbus_cmd_name), -+ KDBUS_CMD_EP_POLICY_SET = _IOWR(KDBUS_IOC_MAGIC, 0x32, int), -+ -+ KDBUS_CMD_NAME_ACQUIRE = _IOWR(KDBUS_IOC_MAGIC, 0x50, int), -+ KDBUS_CMD_NAME_RELEASE = _IOWR(KDBUS_IOC_MAGIC, 0x51, int), -+ KDBUS_CMD_NAME_LIST = _IOWR(KDBUS_IOC_MAGIC, 0x52, int), -+ -+ KDBUS_CMD_MATCH_ADD = _IOWR(KDBUS_IOC_MAGIC, 0x60, int), -+ KDBUS_CMD_MATCH_REMOVE = _IOWR(KDBUS_IOC_MAGIC, 0x61, int), -+ -+ KDBUS_CMD_MSG_SEND = _IOWR(KDBUS_IOC_MAGIC, 0x80, struct kdbus_fake_message), -+ KDBUS_CMD_MSG_RECV = _IOWR(KDBUS_IOC_MAGIC, 0x81, struct kdbus_fake_message), -+}; -+ -+#endif ---- a/include/uapi/linux/major.h -+++ b/include/uapi/linux/major.h -@@ -166,6 +166,8 @@ - - #define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */ - -+#define KDBUS_CHAR_MAJOR 222 -+ - #define IBM_TTY3270_MAJOR 227 - #define IBM_FS3270_MAJOR 228 - ---- /dev/null -+++ b/kdbus.c -@@ -0,0 +1,77 @@ -+#define _GNU_SOURCE -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <sys/ioctl.h> -+ -+#include "include/uapi/kdbus/kdbus.h" -+ -+int main(int argc, char *argv[]) -+{ -+ int fdc; -+ int fdb; -+ struct kdbus_cmd_name name; -+ char *busname; -+ char *bus; -+ char *ep; -+ char *ns; -+ uid_t uid; -+ int err; -+ -+ uid = getuid(); -+ if (argv[1]) -+ busname = argv[1]; -+ else if (uid > 0) -+ busname = "system"; -+ else -+ busname = "user"; -+ strcpy(name.name, busname); -+ -+ printf("-- opening /dev/kdbus/control\n"); -+ fdc = open("/dev/kdbus/control", O_RDWR|O_CLOEXEC); -+ if (fdc < 0) -+ return EXIT_FAILURE; -+ -+ asprintf(&ns, "mydebiancontainer"); -+ strcpy(name.name, ns); -+ printf("-- creating namespace called %s\n", ns); -+ err = ioctl(fdc, KDBUS_CMD_NS_CREATE, &name); -+ if (err) -+ printf("--- error \"%s\"\n", err, strerror(errno)); -+ -+ printf("-- creating bus '%s'\n", name.name); -+ err = ioctl(fdc, KDBUS_CMD_BUS_CREATE, &name); -+ if (err) -+ printf("--- error \"%s\"\n", err, strerror(errno)); -+ -+ if (uid > 0) -+ asprintf(&bus, "/dev/kdbus/%u-%s/bus", uid, busname); -+ else -+ asprintf(&bus, "/dev/kdbus/%s/bus", busname); -+ printf("-- opening bus connection %s\n", bus); -+ fdb = open(bus, O_RDWR|O_CLOEXEC); -+ -+ -+ asprintf(&ep, "ep-42"); -+ strcpy(name.name, ep); -+ printf("-- creating endpoint for bus %s called %s\n", bus, ep); -+ err = ioctl(fdb, KDBUS_CMD_EP_CREATE, &name); -+ if (err) -+ printf("--- error \"%s\"\n", err, strerror(errno)); -+ -+ printf("-- sleeping 10s\n"); -+ sleep(10); -+ -+ printf("-- closing bus connection\n"); -+ close(fdb); -+ -+ printf("-- closing bus master\n"); -+ close(fdc); -+ return EXIT_SUCCESS; -+} |
