+ assert(bus);
+ assert(match);
+
+ if (bus->is_kernel) {
+ struct kdbus_cmd_match *m;
+ struct kdbus_item *item;
+ uint64_t bloom[BLOOM_SIZE/8];
+ size_t sz;
+ const char *sender = NULL;
+ size_t sender_length = 0;
+ uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
+ bool using_bloom = false;
+ unsigned i;
+ bool matches_name_change = true;
+ const char *name_change_arg[3] = {};
+
+ zero(bloom);
+
+ sz = offsetof(struct kdbus_cmd_match, items);
+
+ for (i = 0; i < n_components; i++) {
+ struct bus_match_component *c = &components[i];
+
+ switch (c->type) {
+
+ case BUS_MATCH_SENDER:
+ if (!streq(c->value_str, "org.freedesktop.DBus"))
+ matches_name_change = false;
+
+ r = bus_kernel_parse_unique_name(c->value_str, &src_id);
+ if (r < 0)
+ return r;
+
+ if (r > 0) {
+ sender = c->value_str;
+ sender_length = strlen(sender);
+ sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
+ }
+
+ break;
+
+ case BUS_MATCH_MESSAGE_TYPE:
+ if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
+ matches_name_change = false;
+
+ bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
+ using_bloom = true;
+ break;
+
+ case BUS_MATCH_INTERFACE:
+ if (!streq(c->value_str, "org.freedesktop.DBus"))
+ matches_name_change = false;
+
+ bloom_add_pair(bloom, "interface", c->value_str);
+ using_bloom = true;
+ break;
+
+ case BUS_MATCH_MEMBER:
+ if (!streq(c->value_str, "NameOwnerChanged"))
+ matches_name_change = false;
+
+ bloom_add_pair(bloom, "member", c->value_str);
+ using_bloom = true;
+ break;
+
+ case BUS_MATCH_PATH:
+ if (!streq(c->value_str, "/org/freedesktop/DBus"))
+ matches_name_change = false;
+
+ bloom_add_pair(bloom, "path", c->value_str);
+ using_bloom = true;
+ break;
+
+ case BUS_MATCH_PATH_NAMESPACE:
+ if (!streq(c->value_str, "/")) {
+ bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
+ using_bloom = true;
+ }
+ break;
+
+ case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
+ char buf[sizeof("arg")-1 + 2 + 1];
+
+ if (c->type - BUS_MATCH_ARG < 3)
+ name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
+
+ snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
+ bloom_add_pair(bloom, buf, c->value_str);
+ using_bloom = true;
+ break;
+ }
+
+ case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
+ char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+
+ snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
+ bloom_add_pair(bloom, buf, c->value_str);
+ using_bloom = true;
+ break;
+ }
+
+ case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
+ char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
+
+ snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
+ bloom_add_pair(bloom, buf, c->value_str);
+ using_bloom = true;
+ break;
+ }
+
+ case BUS_MATCH_DESTINATION:
+ /* The bloom filter does not include
+ the destination, since it is only
+ available for broadcast messages
+ which do not carry a destination
+ since they are undirected. */
+ break;
+
+ case BUS_MATCH_ROOT:
+ case BUS_MATCH_VALUE:
+ case BUS_MATCH_LEAF:
+ case _BUS_MATCH_NODE_TYPE_MAX:
+ case _BUS_MATCH_NODE_TYPE_INVALID:
+ assert_not_reached("Invalid match type?");
+ }
+ }
+
+ if (using_bloom)
+ sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
+
+ m = alloca0(sz);
+ m->size = sz;
+ m->cookie = cookie;
+ m->src_id = src_id;
+
+ item = m->items;
+
+ if (using_bloom) {
+ item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
+ item->type = KDBUS_MATCH_BLOOM;
+ memcpy(item->data64, bloom, BLOOM_SIZE);
+
+ item = KDBUS_PART_NEXT(item);
+ }
+
+ if (sender) {
+ item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
+ item->type = KDBUS_MATCH_SRC_NAME;
+ memcpy(item->str, sender, sender_length + 1);
+ }
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+ if (r < 0)
+ return -errno;
+
+ if (matches_name_change) {
+
+ /* If this match could theoretically match
+ * NameOwnerChanged messages, we need to
+ * install a second non-bloom filter explitly
+ * for it */
+
+ r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+ } else
+ return sd_bus_call_method(
+ bus,
+ "org.freedesktop.DBus",
+ "/",
+ "org.freedesktop.DBus",
+ "AddMatch",
+ NULL,
+ NULL,
+ "s",
+ match);
+}