hook gvariant vectors up to kdbus
[platform/upstream/glib.git] / gio / gkdbus.c
index fa5083c..f249b2f 100644 (file)
@@ -34,6 +34,7 @@
 #include <sys/mman.h>
 #include <sys/ioctl.h>
 #include <stdio.h>
+#include <stdint.h>
 
 #ifdef HAVE_SYS_FILIO_H
 # include <sys/filio.h>
 #include <sys/uio.h>
 #endif
 
+#include <glib/gstdio.h>
+#include <glib/glib-private.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+
+#include "glibintl.h"
+#include "gunixfdmessage.h"
+
 #define KDBUS_POOL_SIZE (16 * 1024LU * 1024LU)
 #define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
 #define KDBUS_ALIGN8_PTR(p) ((void*) (uintptr_t)(p))
@@ -89,8 +98,19 @@ struct _GKdbusPrivate
   gchar             *unique_name;
   guint64            unique_id;
 
-  guint64            hello_flags;
-  guint64            attach_flags;
+  guint64            flags;
+  guint64            attach_flags_send;
+  guint64            attach_flags_recv;
+
+  GString           *msg_sender;
+  GString           *msg_destination;
+  GSList            *kdbus_msg_items;
+
+  gint              *fds;
+  gint               num_fds;
+
+  gsize              bloom_size;
+  guint              bloom_n_hash;
 
   guint              closed : 1;
   guint              inited : 1;
@@ -116,6 +136,94 @@ typedef gboolean (*GKdbusSourceFunc) (GKdbus *kdbus,
                                       GIOCondition condition,
                                       gpointer user_data);
 
+/* Hash keys for bloom filters*/
+const guint8 hash_keys[8][16] =
+{
+  {0xb9,0x66,0x0b,0xf0,0x46,0x70,0x47,0xc1,0x88,0x75,0xc4,0x9c,0x54,0xb9,0xbd,0x15},
+  {0xaa,0xa1,0x54,0xa2,0xe0,0x71,0x4b,0x39,0xbf,0xe1,0xdd,0x2e,0x9f,0xc5,0x4a,0x3b},
+  {0x63,0xfd,0xae,0xbe,0xcd,0x82,0x48,0x12,0xa1,0x6e,0x41,0x26,0xcb,0xfa,0xa0,0xc8},
+  {0x23,0xbe,0x45,0x29,0x32,0xd2,0x46,0x2d,0x82,0x03,0x52,0x28,0xfe,0x37,0x17,0xf5},
+  {0x56,0x3b,0xbf,0xee,0x5a,0x4f,0x43,0x39,0xaf,0xaa,0x94,0x08,0xdf,0xf0,0xfc,0x10},
+  {0x31,0x80,0xc8,0x73,0xc7,0xea,0x46,0xd3,0xaa,0x25,0x75,0x0f,0x9e,0x4c,0x09,0x29},
+  {0x7d,0xf7,0x18,0x4b,0x7b,0xa4,0x44,0xd5,0x85,0x3c,0x06,0xe0,0x65,0x53,0x96,0x6d},
+  {0xf2,0x77,0xe9,0x6f,0x93,0xb5,0x4e,0x71,0x9a,0x0c,0x34,0x88,0x39,0x25,0xbf,0x35}
+};
+
+
+/**
+ * _g_kdbus_get_last_msg_sender
+ *
+ */
+gchar *
+_g_kdbus_get_last_msg_sender (GKdbus  *kdbus)
+{
+  return kdbus->priv->msg_sender->str;
+}
+
+
+/**
+ * _g_kdbus_get_last_msg_destination
+ *
+ */
+gchar *
+_g_kdbus_get_last_msg_destination (GKdbus  *kdbus)
+{
+  return kdbus->priv->msg_destination->str;
+}
+
+
+/**
+ * _g_kdbus_get_last_msg_items:
+ *
+ */
+GSList *
+_g_kdbus_get_last_msg_items (GKdbus  *kdbus)
+{
+  return kdbus->priv->kdbus_msg_items;
+}
+
+
+/**
+ * g_kdbus_add_msg_part:
+ *
+ */
+static void
+g_kdbus_add_msg_part (GKdbus  *kdbus,
+                      gchar   *data,
+                      gsize    size)
+{
+  msg_part* part = g_new (msg_part, 1);
+  part->data = data;
+  part->size = size;
+  kdbus->priv->kdbus_msg_items = g_slist_append (kdbus->priv->kdbus_msg_items, part);
+}
+
+
+/**
+ * _g_kdbus_hexdump_all_items:
+ *
+ */
+gchar *
+_g_kdbus_hexdump_all_items (GSList  *kdbus_msg_items)
+{
+
+  GString *ret;
+  gint item = 1;
+  ret = g_string_new (NULL);
+
+  while (kdbus_msg_items != NULL)
+    {
+      g_string_append_printf (ret, "\n  Item %d\n", item);
+      g_string_append (ret, _g_dbus_hexdump (((msg_part*)kdbus_msg_items->data)->data, ((msg_part*)kdbus_msg_items->data)->size, 2));
+
+      kdbus_msg_items = g_slist_next(kdbus_msg_items);
+      item++;
+    }
+
+  return g_string_free (ret, FALSE);
+}
+
+
 /**
  * g_kdbus_finalize:
  *
@@ -133,6 +241,9 @@ g_kdbus_finalize (GObject  *object)
   if (kdbus->priv->fd != -1 && !kdbus->priv->closed)
     _g_kdbus_close (kdbus, NULL);
 
+  g_string_free (kdbus->priv->msg_sender, TRUE);
+  g_string_free (kdbus->priv->msg_destination, TRUE);
+
   if (G_OBJECT_CLASS (g_kdbus_parent_class)->finalize)
     (*G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) (object);
 }
@@ -178,9 +289,17 @@ g_kdbus_init (GKdbus  *kdbus)
   kdbus->priv->unique_name = NULL;
 
   kdbus->priv->kdbus_buffer = NULL;
+  kdbus->priv->kdbus_msg_items = NULL;
 
-  kdbus->priv->hello_flags = 0; /* KDBUS_HELLO_ACCEPT_FD */
-  kdbus->priv->attach_flags = KDBUS_ATTACH_NAMES;
+  kdbus->priv->msg_sender = g_string_new (NULL);
+  kdbus->priv->msg_destination = g_string_new (NULL);
+
+  kdbus->priv->flags = 0; /* KDBUS_HELLO_ACCEPT_FD */
+  kdbus->priv->attach_flags_send = _KDBUS_ATTACH_ALL;
+  kdbus->priv->attach_flags_recv = _KDBUS_ATTACH_ALL;
+
+  kdbus->priv->fds = NULL;
+  kdbus->priv->num_fds = 0;
 }
 
 
@@ -286,7 +405,6 @@ kdbus_source_dispatch  (GSource      *source,
   if (kdbus->priv->timeout)
     kdbus_source->timeout_time = g_get_monotonic_time ()
                                + kdbus->priv->timeout * 1000000;
-
   else
     kdbus_source->timeout_time = 0;
 
@@ -562,14 +680,15 @@ _g_kdbus_Hello (GIOStream  *stream,
          KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1);
 
   hello = g_alloca0 (size);
-  hello->conn_flags = kdbus->priv->hello_flags;
-  hello->attach_flags =  kdbus->priv->attach_flags;
+  hello->flags = kdbus->priv->flags;
+  hello->attach_flags_send = kdbus->priv->attach_flags_send;
+  hello->attach_flags_recv = kdbus->priv->attach_flags_recv;
   hello->size = size;
   hello->pool_size = KDBUS_POOL_SIZE;
 
   item = hello->items;
   item->size = G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1;
-  item->type = KDBUS_ITEM_CONN_NAME;
+  item->type = KDBUS_ITEM_CONN_DESCRIPTION;
   memcpy (item->str, conn_name, conn_name_size+1);
   item = KDBUS_ITEM_NEXT (item);
 
@@ -606,11 +725,15 @@ _g_kdbus_Hello (GIOStream  *stream,
   kdbus->priv->unique_id = hello->id;
   asprintf(&kdbus->priv->unique_name, ":1.%llu", (unsigned long long) hello->id);
 
+  /* read bloom filters parameters */
+  kdbus->priv->bloom_size = (gsize) hello->bloom.size;
+  kdbus->priv->bloom_n_hash = (guint) hello->bloom.n_hash;
+
   return g_variant_new ("(s)", kdbus->priv->unique_name);
 }
 
 
-/*
+/**
  * _g_kdbus_RequestName:
  *
  */
@@ -694,7 +817,7 @@ _g_kdbus_RequestName (GDBusConnection     *connection,
 }
 
 
-/*
+/**
  * _g_kdbus_ReleaseName:
  *
  */
@@ -820,7 +943,7 @@ _g_kdbus_GetListNames (GDBusConnection  *connection,
 
   struct kdbus_cmd_name_list cmd = {};
   struct kdbus_name_list *name_list;
-  struct kdbus_cmd_name *name;
+  struct kdbus_name_info *name;
 
   guint64 prev_id;
   gint ret;
@@ -871,8 +994,8 @@ _g_kdbus_GetListNames (GDBusConnection  *connection,
         }
 
        KDBUS_ITEM_FOREACH(item, name, items)
-         if (item->type == KDBUS_ITEM_NAME)
-           item_name = item->str;
+         if (item->type == KDBUS_ITEM_OWNED_NAME)
+           item_name = item->name.name;
 
         if (g_dbus_is_name (item_name))
           g_variant_builder_add (builder, "s", item_name);
@@ -895,20 +1018,20 @@ g_kdbus_NameHasOwner_internal (GKdbus       *kdbus,
                                const gchar  *name,
                                GError      **error)
 {
-  struct kdbus_cmd_conn_info *cmd;
+  struct kdbus_cmd_info *cmd;
   gssize size, len;
   gint ret;
 
   if (g_dbus_is_unique_name(name))
     {
-       size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, items);
+       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
        cmd = g_alloca0 (size);
        cmd->id = g_ascii_strtoull (name+3, NULL, 10);
     }
   else
     {
        len = strlen(name) + 1;
-       size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, items) + KDBUS_ITEM_SIZE(len);
+       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
        cmd = g_alloca0 (size);
        cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
        cmd->items[0].type = KDBUS_ITEM_NAME;
@@ -943,7 +1066,7 @@ _g_kdbus_GetListQueuedOwners (GDBusConnection  *connection,
 
   struct kdbus_cmd_name_list cmd = {};
   struct kdbus_name_list *name_list;
-  struct kdbus_cmd_name *kname;
+  struct kdbus_name_info *kname;
 
   kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
   if (kdbus == NULL)
@@ -1014,46 +1137,6 @@ _g_kdbus_GetListQueuedOwners (GDBusConnection  *connection,
 
 
 /**
- * _g_kdbus_NameHasOwner:
- *
- */
-GVariant *
-_g_kdbus_NameHasOwner (GDBusConnection  *connection,
-                       const gchar      *name,
-                       GError          **error)
-{
-  GKdbus *kdbus;
-  GVariant *result;
-
-  kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
-  if (kdbus == NULL)
-    {
-      g_set_error_literal (error,
-                           G_DBUS_ERROR,
-                           G_DBUS_ERROR_IO_ERROR,
-                           _("The connection is closed"));
-      return NULL;
-    }
-
-  if (!g_dbus_is_name (name))
-    {
-      g_set_error (error,
-                   G_DBUS_ERROR,
-                   G_DBUS_ERROR_INVALID_ARGS,
-                   "Given bus name \"%s\" is not valid", name);
-      return NULL;
-    }
-
-  if (!g_kdbus_NameHasOwner_internal (kdbus, name, error))
-    result = g_variant_new ("(b)", FALSE);
-  else
-    result = g_variant_new ("(b)", TRUE);
-
-  return result;
-}
-
-
-/**
  * g_kdbus_GetConnInfo_internal:
  *
  */
@@ -1066,8 +1149,8 @@ g_kdbus_GetConnInfo_internal (GDBusConnection  *connection,
   GKdbus *kdbus;
   GVariant *result;
 
-  struct kdbus_cmd_conn_info *cmd;
-  struct kdbus_conn_info *conn_info;
+  struct kdbus_cmd_info *cmd;
+  struct kdbus_info *conn_info;
   struct kdbus_item *item;
   gssize size, len;
   gint ret;
@@ -1103,21 +1186,21 @@ g_kdbus_GetConnInfo_internal (GDBusConnection  *connection,
 
   if (g_dbus_is_unique_name(name))
     {
-       size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, items);
+       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
        cmd = g_alloca0 (size);
        cmd->id = g_ascii_strtoull (name+3, NULL, 10);
     }
   else
     {
        len = strlen(name) + 1;
-       size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, items) + KDBUS_ITEM_SIZE(len);
+       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
        cmd = g_alloca0 (size);
        cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
        cmd->items[0].type = KDBUS_ITEM_NAME;
        memcpy (cmd->items[0].str, name, len);
     }
 
-  cmd->flags = KDBUS_ATTACH_NAMES;
+  cmd->flags = _KDBUS_ATTACH_ALL;
   cmd->size = size;
 
   ret = ioctl(kdbus->priv->fd, KDBUS_CMD_CONN_INFO, cmd);
@@ -1130,7 +1213,7 @@ g_kdbus_GetConnInfo_internal (GDBusConnection  *connection,
       return NULL;
     }
 
-  conn_info = (struct kdbus_conn_info *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd->offset);
+  conn_info = (struct kdbus_info *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd->offset);
 
   /*
   if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
@@ -1152,14 +1235,16 @@ g_kdbus_GetConnInfo_internal (GDBusConnection  *connection,
    {
       switch (item->type)
         {
-          case KDBUS_ITEM_CREDS:
+          case KDBUS_ITEM_PIDS:
 
             if (flag == G_BUS_CREDS_PID)
               {
-                guint pid = item->creds.pid;
+                guint pid = item->pids.pid;
                 result = g_variant_new ("(u)", pid);
                 goto exit;
-               }
+              }
+
+          case KDBUS_ITEM_CREDS:
 
             if (flag == G_BUS_CREDS_UID)
               {
@@ -1175,8 +1260,10 @@ g_kdbus_GetConnInfo_internal (GDBusConnection  *connection,
           case KDBUS_ITEM_CMDLINE:
           case KDBUS_ITEM_CGROUP:
           case KDBUS_ITEM_CAPS:
-          case KDBUS_ITEM_NAME:
           case KDBUS_ITEM_AUDIT:
+          case KDBUS_ITEM_CONN_DESCRIPTION:
+          case KDBUS_ITEM_AUXGROUPS:
+          case KDBUS_ITEM_OWNED_NAME:
             break;
         }
    }
@@ -1235,7 +1322,7 @@ _g_kdbus_GetConnectionUnixUser (GDBusConnection  *connection,
 }
 
 
-/*
+/**
  * _g_kdbus_match_remove:
  *
  */
@@ -1258,7 +1345,7 @@ _g_kdbus_match_remove (GDBusConnection  *connection,
 }
 
 
-/*
+/**
  * _g_kdbus_subscribe_name_acquired:
  *
  */
@@ -1333,7 +1420,7 @@ _g_kdbus_subscribe_name_owner_changed (GDBusConnection  *connection,
 }
 
 
-/*
+/**
  * _g_kdbus_subscribe_name_acquired:
  *
  */
@@ -1378,7 +1465,7 @@ _g_kdbus_subscribe_name_acquired (GDBusConnection  *connection,
 }
 
 
-/*
+/**
  * _g_kdbus_subscribe_name_lost:
  *
  */
@@ -1423,7 +1510,7 @@ _g_kdbus_subscribe_name_lost (GDBusConnection  *connection,
 }
 
 
-/*
+/**
  * _g_kdbus_unsubscribe_name_acquired:
  *
  */
@@ -1437,7 +1524,7 @@ _g_kdbus_unsubscribe_name_acquired (GDBusConnection  *connection)
 }
 
 
-/*
+/**
  * _g_kdbus_unsubscribe_name_lost:
  *
  */
@@ -1452,9 +1539,351 @@ _g_kdbus_unsubscribe_name_lost (GDBusConnection  *connection)
 
 
 /**
-* g_kdbus_decode_kernel_msg:
-*
-*/
+ * _g_kdbus_release_msg:
+ *
+ */
+void
+_g_kdbus_release_kmsg (GKdbus  *kdbus)
+{
+  struct kdbus_item *item = NULL;
+  GSList *iterator = NULL;
+  guint64 offset;
+
+  offset = (guint8 *)kdbus->priv->kmsg - (guint8 *)kdbus->priv->kdbus_buffer;
+  ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &offset);
+
+  for (iterator = kdbus->priv->kdbus_msg_items; iterator; iterator = iterator->next)
+    g_free ((msg_part*)iterator->data);
+
+  g_slist_free (kdbus->priv->kdbus_msg_items);
+  kdbus->priv->kdbus_msg_items = NULL;
+
+  KDBUS_ITEM_FOREACH (item, kdbus->priv->kmsg, items)
+    {
+      if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD)
+        close(item->memfd.fd);
+      else if (item->type == KDBUS_ITEM_FDS)
+        {
+          gint i;
+          gint num_fds = (item->size - G_STRUCT_OFFSET(struct kdbus_item, fds)) / sizeof(int);
+
+          for (i = 0; i < num_fds; i++)
+            close(item->fds[i]);
+        }
+    }
+}
+
+
+/**
+ * g_kdbus_append_payload_vec:
+ *
+ */
+static void
+g_kdbus_append_payload_vec (struct kdbus_item **item,
+                            const void         *data_ptr,
+                            gssize              size)
+{
+  *item = KDBUS_ALIGN8_PTR(*item);
+  (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, vec) + sizeof(struct kdbus_vec);
+  (*item)->type = KDBUS_ITEM_PAYLOAD_VEC;
+  (*item)->vec.address = (guint64)((guintptr)data_ptr);
+  (*item)->vec.size = size;
+  *item = KDBUS_ITEM_NEXT(*item);
+}
+
+/**
+ * g_kdbus_append_payload_memfd:
+ *
+ */
+static void
+g_kdbus_append_payload_memfd (struct kdbus_item **item,
+                              gint                fd,
+                              gssize              size)
+{
+  *item = KDBUS_ALIGN8_PTR(*item);
+  (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
+  (*item)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
+  (*item)->memfd.fd = fd;
+  (*item)->memfd.size = size;
+  *item = KDBUS_ITEM_NEXT(*item);
+}
+
+
+/**
+ * g_kdbus_append_payload_destiantion:
+ *
+ */
+static void
+g_kdbus_append_destination (struct kdbus_item **item,
+                            const gchar        *destination,
+                            gsize               size)
+{
+  *item = KDBUS_ALIGN8_PTR(*item);
+  (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, str) + size + 1;
+  (*item)->type = KDBUS_ITEM_DST_NAME;
+  memcpy ((*item)->str, destination, size+1);
+  *item = KDBUS_ITEM_NEXT(*item);
+}
+
+
+/**
+ * g_kdbus_append_payload_bloom:
+ *
+ */
+static struct kdbus_bloom_filter *
+g_kdbus_append_bloom (struct kdbus_item **item,
+                      gsize               size)
+{
+  struct kdbus_item *bloom_item;
+
+  bloom_item = KDBUS_ALIGN8_PTR(*item);
+  bloom_item->size = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
+                     G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
+                     size;
+
+  bloom_item->type = KDBUS_ITEM_BLOOM_FILTER;
+
+  *item = KDBUS_ITEM_NEXT(bloom_item);
+  return &bloom_item->bloom_filter;
+}
+
+
+/**
+ * g_kdbus_append_fds:
+ *
+ */
+static void
+g_kdbus_append_fds (struct kdbus_item **item,
+                    GUnixFDList        *fd_list)
+{
+  *item = KDBUS_ALIGN8_PTR(*item);
+  (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list);
+  (*item)->type = KDBUS_ITEM_FDS;
+  memcpy ((*item)->fds, g_unix_fd_list_peek_fds(fd_list, NULL), sizeof(int) * g_unix_fd_list_get_length(fd_list));
+
+  *item = KDBUS_ITEM_NEXT(*item);
+}
+
+
+/**
+ * _g_kdbus_attach_fds_to_msg:
+ *
+ */
+void
+_g_kdbus_attach_fds_to_msg (GKdbus       *kdbus,
+                            GUnixFDList **fd_list)
+{
+  if ((kdbus->priv->fds != NULL) && (kdbus->priv->num_fds > 0))
+    {
+      gint n;
+
+      if (*fd_list == NULL)
+        *fd_list = g_unix_fd_list_new();
+
+      for (n = 0; n < kdbus->priv->num_fds; n++)
+        {
+          g_unix_fd_list_append (*fd_list, kdbus->priv->fds[n], NULL);
+          (void) g_close (kdbus->priv->fds[n], NULL);
+        }
+
+      g_free (kdbus->priv->fds);
+      kdbus->priv->fds = NULL;
+      kdbus->priv->num_fds = 0;
+    }
+}
+
+/**
+ * g_kdbus_bloom_add_data:
+ * Based on bus-bloom.c from systemd
+ * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
+ */
+static void
+g_kdbus_bloom_add_data (GKdbus      *kdbus,
+                        guint64      bloom_data [],
+                        const void  *data,
+                        gsize        n)
+{
+  guint8 hash[8];
+  guint64 bit_num;
+  guint bytes_num = 0;
+  guint cnt_1, cnt_2;
+
+  guint c = 0;
+  guint64 p = 0;
+
+  bit_num = kdbus->priv->bloom_size * 8;
+
+  if (bit_num > 1)
+    bytes_num = ((__builtin_clzll(bit_num) ^ 63U) + 7) / 8;
+
+  for (cnt_1 = 0; cnt_1 < (kdbus->priv->bloom_n_hash); cnt_1++)
+    {
+      for (cnt_2 = 0; cnt_2 < bytes_num; cnt_2++)
+        {
+          if (c <= 0)
+            {
+              g_siphash24(hash, data, n, hash_keys[cnt_1++]);
+              c += 8;
+            }
+
+          p = (p << 8ULL) | (guint64) hash[8 - c];
+          c--;
+        }
+
+      p &= bit_num - 1;
+      bloom_data[p >> 6] |= 1ULL << (p & 63);
+    }
+}
+
+
+/**
+ * g_kdbus_bloom_add_pair:
+ *
+ */
+static void
+g_kdbus_bloom_add_pair (GKdbus       *kdbus,
+                        guint64       bloom_data [],
+                        const gchar  *parameter,
+                        const gchar  *value)
+{
+  GString *data = g_string_new (NULL);
+
+  g_string_printf (data,"%s:%s",parameter,value);
+  g_kdbus_bloom_add_data(kdbus, bloom_data, data->str, data->len);
+  g_string_free (data, TRUE);
+}
+
+
+/**
+ * g_kdbus_bloom_add_prefixes:
+ *
+ */
+static void
+g_kdbus_bloom_add_prefixes (GKdbus       *kdbus,
+                            guint64       bloom_data [],
+                            const gchar  *parameter,
+                            const gchar  *value,
+                            gchar         separator)
+{
+  GString *data = g_string_new (NULL);
+
+  g_string_printf (data,"%s:%s",parameter,value);
+
+  for (;;)
+    {
+      gchar *last_sep;
+      last_sep = strrchr(data->str, separator);
+      if (!last_sep || last_sep == data->str)
+        break;
+
+      *last_sep = 0;
+      g_kdbus_bloom_add_data(kdbus, bloom_data, data->str, last_sep-(data->str));
+    }
+  g_string_free (data, TRUE);
+}
+
+
+/**
+ * g_kdbus_setup_bloom:
+ * Based on bus-bloom.c from systemd
+ * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
+ */
+static void
+g_kdbus_setup_bloom (GKdbus                     *kdbus,
+                     GDBusMessage               *dbus_msg,
+                     struct kdbus_bloom_filter  *bloom_filter)
+{
+  GVariant *body;
+  GVariantIter iter;
+  GVariant *child;
+
+  const gchar *message_type;
+  const gchar *interface;
+  const gchar *member;
+  const gchar *path;
+
+  void *bloom_data;
+  gint cnt = 0;
+
+  body = g_dbus_message_get_body (dbus_msg);
+  message_type = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, g_dbus_message_get_message_type (dbus_msg));
+  interface = g_dbus_message_get_interface (dbus_msg);
+  member = g_dbus_message_get_member (dbus_msg);
+  path = g_dbus_message_get_path (dbus_msg);
+
+  bloom_data = bloom_filter->data;
+  memset (bloom_data, 0, kdbus->priv->bloom_size);
+  bloom_filter->generation = 0;
+
+  g_kdbus_bloom_add_pair(kdbus, bloom_data, "message-type", message_type);
+
+  if (interface)
+    g_kdbus_bloom_add_pair(kdbus, bloom_data, "interface", interface);
+
+  if (member)
+    g_kdbus_bloom_add_pair(kdbus, bloom_data, "member", member);
+
+  if (path)
+    {
+      g_kdbus_bloom_add_pair(kdbus, bloom_data, "path", path);
+      g_kdbus_bloom_add_pair(kdbus, bloom_data, "path-slash-prefix", path);
+      g_kdbus_bloom_add_prefixes(kdbus, bloom_data, "path-slash-prefix", path, '/');
+    }
+
+  if (body != NULL)
+    {
+      g_variant_iter_init (&iter, body);
+      while ((child = g_variant_iter_next_value (&iter)))
+        {
+          gchar buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+          gchar *child_string;
+          gchar *e;
+
+          /* Is it necessary? */
+          //if (g_variant_is_container (child))
+          //  iterate_container_recursive (child);
+
+          if (!(g_variant_is_of_type (child, G_VARIANT_TYPE_STRING)) &&
+              !(g_variant_is_of_type (child, G_VARIANT_TYPE_OBJECT_PATH)) &&
+              !(g_variant_is_of_type (child, G_VARIANT_TYPE_SIGNATURE)))
+            break;
+
+          child_string = g_variant_dup_string (child, NULL);
+
+          e = stpcpy(buf, "arg");
+          if (cnt < 10)
+            *(e++) = '0' + (char) cnt;
+          else
+            {
+              *(e++) = '0' + (char) (cnt / 10);
+              *(e++) = '0' + (char) (cnt % 10);
+            }
+
+          *e = 0;
+          g_kdbus_bloom_add_pair(kdbus, bloom_data, buf, child_string);
+
+          strcpy(e, "-dot-prefix");
+          g_kdbus_bloom_add_prefixes(kdbus, bloom_data, buf, child_string, '.');
+
+          strcpy(e, "-slash-prefix");
+          g_kdbus_bloom_add_prefixes(kdbus, bloom_data, buf, child_string, '/');
+
+          g_free (child_string);
+          g_variant_unref (child);
+          cnt++;
+        }
+    }
+}
+
+
+/*
+ * TODO: g_kdbus_NameOwnerChanged_generate, g_kdbus_KernelMethodError_generate
+ */
+
+/**
+ * g_kdbus_decode_kernel_msg:
+ *
+ */
 static gssize
 g_kdbus_decode_kernel_msg (GKdbus  *kdbus)
 {
@@ -1485,7 +1914,7 @@ g_kdbus_decode_kernel_msg (GKdbus  *kdbus)
        }
     }
 
-#if 0
+
   /* Override information from the user header with data from the kernel */
   g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus");
 
@@ -1497,13 +1926,191 @@ g_kdbus_decode_kernel_msg (GKdbus  *kdbus)
     g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->unique_id);
   else
    g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
-#endif
 
   return size;
 }
 
 
 /**
+ * g_kdbus_decode_dbus_msg:
+ *
+ */
+static GDBusMessage *
+g_kdbus_decode_dbus_msg (GKdbus                *kdbus,
+                         struct kdbus_cmd_recv *recv)
+{
+  struct kdbus_item *item;
+  gssize data_size = 0;
+  const gchar *destination = NULL;
+  GArray *body_vectors;
+  gsize body_size;
+  GVariant *body;
+  guint i;
+
+  body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
+  body_size = 0;
+
+  KDBUS_ITEM_FOREACH(item, (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv->offset), items)
+    {
+      if (item->size <= KDBUS_ITEM_HEADER_SIZE)
+        g_error("[KDBUS] %llu bytes - invalid data record\n", item->size);
+
+      data_size = item->size - KDBUS_ITEM_HEADER_SIZE;
+
+      switch (item->type)
+        {
+         /* KDBUS_ITEM_DST_NAME */
+         case KDBUS_ITEM_DST_NAME:
+           destination = item->str;
+           break;
+
+        /* KDBUS_ITEM_PALOAD_OFF */
+        case KDBUS_ITEM_PAYLOAD_OFF:
+          {
+            GVariantVector vector;
+            gsize flavour;
+
+            /* We want to make sure the bytes are aligned the same as
+             * they would be if they appeared in a contiguously
+             * allocated chunk of aligned memory.
+             *
+             * We decide what the alignment 'should' be by consulting
+             * body_size, which has been tracking the total size of the
+             * message up to this point.
+             *
+             * We then play around with the pointer by removing as many
+             * bytes as required to get it to the proper alignment (and
+             * copy extra bytes accordingly).  This means that we will
+             * grab some extra data in the 'bytes', but it won't be
+             * shared with GVariant (which means there is no chance of
+             * it being accidentally retransmitted).
+             *
+             * The kernel does the same thing, so make sure we get the
+             * expected result.  Because of the kernel doing the same,
+             * the result is that we will always be rounding-down to a
+             * multiple of 8 for the pointer, which means that the
+             * pointer will always be valid, assuming the original
+             * address was.
+             *
+             * We could fix this with a new GBytes constructor that took
+             * 'flavour' as a parameter, but it's not worth it...
+             */
+            flavour = body_size & 7;
+            //g_assert ((item->vec.offset & 7) == flavour); FIXME: kdbus bug doesn't count memfd in flavouring
+
+            vector.gbytes = g_bytes_new (((guchar *) kdbus->priv->kmsg) + item->vec.offset - flavour,
+                                         item->vec.size + flavour);
+            vector.data.pointer = g_bytes_get_data (vector.gbytes, NULL);
+            vector.data.pointer += flavour;
+            vector.size = item->vec.size;
+
+            g_array_append_val (body_vectors, vector);
+            body_size += vector.size;
+          }
+          break;
+
+        /* KDBUS_ITEM_PAYLOAD_MEMFD */
+        case KDBUS_ITEM_PAYLOAD_MEMFD:
+          {
+            GVariantVector vector;
+
+            vector.gbytes = g_bytes_new_take_zero_copy_fd (item->memfd.fd);
+            vector.data.pointer = g_bytes_get_data (vector.gbytes, &vector.size);
+            g_print ("GB was %p/%d\n", vector.data.pointer, (guint) vector.size);
+
+            g_array_append_val (body_vectors, vector);
+            body_size += vector.size;
+          }
+          break;
+
+        /* KDBUS_ITEM_FDS */
+        case KDBUS_ITEM_FDS:
+
+          kdbus->priv->num_fds = data_size / sizeof(int);
+          kdbus->priv->fds = g_malloc0 (sizeof(int) * kdbus->priv->num_fds);
+          memcpy(kdbus->priv->fds, item->fds, sizeof(int) * kdbus->priv->num_fds);
+
+          break;
+
+        /* All of the following items, like CMDLINE,
+           CGROUP, etc. need some GDBUS API extensions and
+           should be implemented in the future */
+        case KDBUS_ITEM_TIMESTAMP:
+          {
+            g_print ("time: seq %llu mon %llu real %llu\n",
+                     item->timestamp.seqnum, item->timestamp.monotonic_ns, item->timestamp.realtime_ns);
+            //g_dbus_message_set_timestamp (message, item->timestamp.monotonic_ns / 1000);
+            //g_dbus_message_set_serial (message, item->timestamp.seqnum);
+            break;
+          }
+
+        case KDBUS_ITEM_CREDS:
+          {
+            g_print ("creds: u%u eu %u su%u fsu%u g%u eg%u sg%u fsg%u\n",
+                     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:
+          {
+          }
+
+        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_AUDIT:
+        case KDBUS_ITEM_CAPS:
+        case KDBUS_ITEM_SECLABEL:
+        case KDBUS_ITEM_CONN_DESCRIPTION:
+        case KDBUS_ITEM_AUXGROUPS:
+        case KDBUS_ITEM_OWNED_NAME:
+        case KDBUS_ITEM_NAME:
+          g_print ("unhandled %04x\n", (int) item->type);
+          break;
+
+        default:
+          g_error ("[KDBUS] DBUS_PAYLOAD: Unknown filed - %lld", item->type);
+          break;
+        }
+    }
+
+  body = GLIB_PRIVATE_CALL(g_variant_from_vectors) (G_VARIANT_TYPE ("(ssa{sv})"),
+                                                    (GVariantVector *) body_vectors->data,
+                                                    body_vectors->len, body_size, FALSE);
+  g_assert (body);
+
+  for (i = 0; i < body_vectors->len; i++)
+    g_bytes_unref (g_array_index (body_vectors, GVariantVector, i).gbytes);
+
+  g_array_free (body_vectors, TRUE);
+
+  g_print ("body is %s\n", g_variant_print (body, TRUE));
+
+  /* Override information from the user header with data from the kernel */
+
+  if (kdbus->priv->kmsg->src_id == KDBUS_SRC_ID_KERNEL)
+    g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus");
+  else
+    g_string_printf (kdbus->priv->msg_sender, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->src_id);
+
+  if (destination)
+    g_string_printf (kdbus->priv->msg_destination, "%s", destination);
+  else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_BROADCAST)
+    /* for broadcast messages we don't have to set destination */
+    ;
+  else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_NAME)
+    g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->unique_id);
+  else
+    g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
+
+  return NULL;
+}
+
+
+/**
  * _g_kdbus_receive:
  *
  */
@@ -1513,7 +2120,6 @@ _g_kdbus_receive (GKdbus        *kdbus,
                   GError       **error)
 {
   struct kdbus_cmd_recv recv = {};
-  gssize size = 0;
 
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     return -1;
@@ -1534,9 +2140,9 @@ again:
    kdbus->priv->kmsg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset);
 
    if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_DBUS)
-     g_error ("Received standard dbus message - not supported yet");
+     g_kdbus_decode_dbus_msg (kdbus, &recv);
    else if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_KERNEL)
-     size = g_kdbus_decode_kernel_msg (kdbus);
+     g_kdbus_decode_kernel_msg (kdbus);
    else
      {
        g_set_error (error,
@@ -1546,5 +2152,220 @@ again:
        return -1;
      }
 
-   return size;
+   return 0;
+}
+
+/**
+ * _g_kdbus_send:
+ * Returns: size of data sent or -1 when error
+ */
+gboolean
+_g_kdbus_send (GDBusWorker   *worker,
+               GKdbus        *kdbus,
+               GDBusMessage  *dbus_msg,
+               GUnixFDList   *fd_list,
+               GCancellable  *cancellable,
+               GError       **error)
+{
+  GVariantVectors body_vectors;
+  GVariant *body;
+  struct kdbus_msg* kmsg;
+  struct kdbus_item *item;
+  guint64 kmsg_size = 0;
+  const gchar *name;
+  guint64 dst_id = KDBUS_DST_ID_BROADCAST;
+  guint i;
+
+  g_return_val_if_fail (G_IS_KDBUS (kdbus), -1);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return FALSE;
+
+  body = g_dbus_message_get_body (dbus_msg);
+  if (body == NULL)
+    {
+      g_warning ("no body!");
+      body = g_variant_new ("()");
+      g_variant_ref_sink (body);
+    }
+  else
+    g_variant_ref (body);
+  GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, &body_vectors);
+
+  /*
+   * check destination
+   */
+  if ((name = g_dbus_message_get_destination(dbus_msg)))
+    {
+      dst_id = KDBUS_DST_ID_NAME;
+      if ((name[0] == ':') && (name[1] == '1') && (name[2] == '.'))
+        {
+          dst_id = strtoull(&name[3], NULL, 10);
+          name=NULL;
+        }
+    }
+
+  /*
+   * check and set message size
+   */
+  kmsg_size = sizeof(struct kdbus_msg);
+
+    { G_STATIC_ASSERT (sizeof (struct kdbus_vec) == sizeof (struct kdbus_memfd)); }
+  kmsg_size += KDBUS_ITEM_SIZE(sizeof (struct kdbus_vec)) * body_vectors.vectors->len;
+
+  if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0)
+    kmsg_size += KDBUS_ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list));
+
+  if (name)
+    kmsg_size += KDBUS_ITEM_SIZE(strlen(name) + 1);
+  else if (dst_id == KDBUS_DST_ID_BROADCAST)
+    kmsg_size += KDBUS_ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, bloom_filter) +
+                        G_STRUCT_OFFSET(struct kdbus_bloom_filter, data) +
+                        kdbus->priv->bloom_size);
+
+  kmsg = malloc(kmsg_size);
+  if (!kmsg)
+    g_error ("[KDBUS] kmsg malloc error");
+
+
+  /*
+   * set message header
+   */
+  memset(kmsg, 0, kmsg_size);
+  kmsg->size = kmsg_size;
+  kmsg->payload_type = KDBUS_PAYLOAD_DBUS;
+  kmsg->dst_id = name ? 0 : dst_id;
+  kmsg->src_id = kdbus->priv->unique_id;
+  kmsg->cookie = g_dbus_message_get_serial(dbus_msg);
+  kmsg->priority = 0;
+
+
+  /*
+   * set message flags
+   */
+  kmsg->flags = ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
+                ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
+
+  if ((kmsg->flags) & KDBUS_MSG_FLAGS_EXPECT_REPLY)
+    kmsg->timeout_ns = 2000000000;
+  else
+    kmsg->cookie_reply = g_dbus_message_get_reply_serial(dbus_msg);
+
+
+  /*
+   * append payload
+   */
+  item = kmsg->items;
+  for (i = 0; i < body_vectors.vectors->len; i++)
+    {
+      GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i);
+
+      if (vector.gbytes)
+        {
+          gint fd;
+
+          fd = g_bytes_get_zero_copy_fd (vector.gbytes);
+
+          if (fd >= 0)
+            {
+              gconstpointer bytes_data;
+              gsize bytes_size;
+
+              bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size);
+
+              if (bytes_data == vector.data.pointer && bytes_size == vector.size)
+                g_kdbus_append_payload_memfd (&item, fd, vector.size);
+              else
+                g_kdbus_append_payload_vec (&item, vector.data.pointer, vector.size);
+            }
+          else
+            g_kdbus_append_payload_vec (&item, vector.data.pointer, vector.size);
+        }
+      else
+        g_kdbus_append_payload_vec (&item, body_vectors.extra_bytes->data + vector.data.offset, vector.size);
+    }
+
+  /* if we don't use memfd, send whole message as a PAYLOAD_VEC item */
+
+
+  /*
+   * append destination or bloom filters
+   */
+  if (name)
+    g_kdbus_append_destination (&item, name, strlen(name));
+  else if (dst_id == KDBUS_DST_ID_BROADCAST)
+    {
+      struct kdbus_bloom_filter *bloom_filter;
+
+      bloom_filter = g_kdbus_append_bloom (&item, kdbus->priv->bloom_size);
+      g_kdbus_setup_bloom (kdbus, dbus_msg, bloom_filter);
+    }
+
+  /*
+   * append fds if any
+   */
+  if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0)
+    g_kdbus_append_fds (&item, fd_list);
+
+
+  /*
+   * send message
+   */
+//again:
+  if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, kmsg))
+    {
+/*
+      GString *error_name;
+      error_name = g_string_new (NULL);
+
+      if(errno == EINTR)
+        {
+          g_string_free (error_name,TRUE);
+          goto again;
+        }
+      else if (errno == ENXIO)
+        {
+          g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg));
+          g_kdbus_generate_local_error (worker,
+                                        dbus_msg,
+                                        g_variant_new ("(s)",error_name->str),
+                                        G_DBUS_ERROR_SERVICE_UNKNOWN);
+          g_string_free (error_name,TRUE);
+          return 0;
+        }
+      else if ((errno == ESRCH) || (errno == EADDRNOTAVAIL))
+        {
+          if (kmsg->flags & KDBUS_MSG_FLAGS_NO_AUTO_START)
+            {
+              g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg));
+              g_kdbus_generate_local_error (worker,
+                                            dbus_msg,
+                                            g_variant_new ("(s)",error_name->str),
+                                            G_DBUS_ERROR_SERVICE_UNKNOWN);
+              g_string_free (error_name,TRUE);
+              return 0;
+            }
+          else
+            {
+              g_string_printf (error_name, "The name %s was not provided by any .service files", g_dbus_message_get_destination(dbus_msg));
+              g_kdbus_generate_local_error (worker,
+                                            dbus_msg,
+                                            g_variant_new ("(s)",error_name->str),
+                                            G_DBUS_ERROR_SERVICE_UNKNOWN);
+              g_string_free (error_name,TRUE);
+              return 0;
+            }
+        }
+
+      g_print ("[KDBUS] ioctl error sending kdbus message:%d (%m)\n",errno);
+      g_set_error (error, G_IO_ERROR, g_io_error_from_errno(errno), _("Error sending message - KDBUS_CMD_MSG_SEND error"));
+*/
+      perror("ioctl send");
+      g_error ("IOCTL SEND: %d\n",errno);
+      return FALSE;
+    }
+
+  free(kmsg);
+
+  return TRUE;
 }