+static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ int r;
+
+ assert(bus);
+
+ r = sd_bus_message_new_signal(
+ bus,
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameOwnerChanged",
+ &m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
+ if (r < 0)
+ return r;
+
+ m->sender = "org.freedesktop.DBus";
+
+ r = bus_seal_synthetic_message(bus, m);
+ if (r < 0)
+ return r;
+
+ bus->rqueue[bus->rqueue_size++] = m;
+ m = NULL;
+
+ return 1;
+}
+
+static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+ char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
+
+ assert(bus);
+ assert(k);
+ assert(d);
+
+ if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old_flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
+ old_owner[0] = 0;
+ else
+ sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old_id);
+
+ if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new_flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
+
+ if (isempty(old_owner))
+ return 0;
+
+ new_owner[0] = 0;
+ } else
+ sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new_id);
+
+ return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
+}
+
+static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+ char owner[UNIQUE_NAME_MAX];
+
+ assert(bus);
+ assert(k);
+ assert(d);
+
+ sprintf(owner, ":1.%llu", d->id_change.id);
+
+ return push_name_owner_changed(
+ bus, owner,
+ d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
+ d->type == KDBUS_ITEM_ID_ADD ? owner : NULL);
+}
+
+static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ int r;
+
+ assert(bus);
+ assert(k);
+ assert(d);
+
+ r = bus_message_new_synthetic_error(
+ bus,
+ k->cookie_reply,
+ d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
+ &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
+ &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
+ &m);
+ if (r < 0)
+ return r;
+
+ m->sender = "org.freedesktop.DBus";
+
+ r = bus_seal_synthetic_message(bus, m);
+ if (r < 0)
+ return r;
+
+ bus->rqueue[bus->rqueue_size++] = m;
+ m = NULL;
+
+ return 1;
+}
+
+static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
+ struct kdbus_item *d, *found = NULL;
+
+ static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = {
+ [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+ [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+ [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+
+ [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+ [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+
+ [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+ [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+ };
+
+ assert(bus);
+ assert(k);
+ assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
+
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
+ if (found)
+ return -EBADMSG;
+ found = d;
+ } else
+ log_debug("Got unknown field from kernel %llu", d->type);
+ }
+
+ if (!found) {
+ log_debug("Didn't find a kernel message to translate.");
+ return 0;
+ }
+
+ return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found);
+}
+
+static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {