+enum {
+ CFG_INTERFACES,
+ CFG_KEEP,
+ CFG_MAX
+};
+
+static const struct blobmsg_policy config_policy[] = {
+ [CFG_INTERFACES] = { "interfaces", BLOBMSG_TYPE_ARRAY },
+ [CFG_KEEP] = { "keep", BLOBMSG_TYPE_BOOL },
+};
+
+static int
+mdns_set_config(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *data[CFG_MAX], *cur;
+ int rem, keep = false;
+
+ blobmsg_parse(config_policy, CFG_MAX, data, blob_data(msg), blob_len(msg));
+ if (!data[CFG_INTERFACES])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (!blobmsg_check_attr_list(data[CFG_INTERFACES], BLOBMSG_TYPE_STRING))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ keep = data[CFG_KEEP] && blobmsg_get_bool(data[CFG_KEEP]);
+ if (!keep) {
+ vlist_update(&interfaces);
+ ubus_notify(ctx, obj, "set_config", NULL, 1000);
+ }
+
+ blobmsg_for_each_attr(cur, data[CFG_INTERFACES], rem)
+ interface_add(blobmsg_data(cur));
+
+ if (!keep)
+ vlist_flush(&interfaces);
+
+ return 0;
+}
+
+enum query_attr {
+ QUERY_QUESTION,
+ QUERY_IFACE,
+ QUERY_TYPE,
+ QUERY_MAX
+};
+
+static const struct blobmsg_policy query_policy[QUERY_MAX] = {
+ [QUERY_QUESTION]= { "question", BLOBMSG_TYPE_STRING },
+ [QUERY_IFACE] = { "interface", BLOBMSG_TYPE_STRING },
+ [QUERY_TYPE] = { "type", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+mdns_query(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[QUERY_MAX], *c;
+ const char *question = "_services._dns-sd._udp.local";
+ const char *ifname;
+ int type = TYPE_ANY;
+
+ blobmsg_parse(query_policy, QUERY_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!(c = tb[QUERY_IFACE]))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ ifname = blobmsg_get_string(c);
+
+ if ((c = tb[QUERY_QUESTION]))
+ question = blobmsg_get_string(c);
+
+ if ((c = tb[QUERY_TYPE]))
+ type = blobmsg_get_u32(c);
+
+ struct interface *iface_v4 = interface_get(ifname, 0, 1);
+ struct interface *iface_v6 = interface_get(ifname, 1, 1);
+
+ if (!iface_v4 && !iface_v6)
+ return UBUS_STATUS_NOT_FOUND;
+
+ if (!strcmp(method, "query")) {
+ if (iface_v4)
+ dns_send_question(iface_v4, question, type, 0);
+
+ if (iface_v6)
+ dns_send_question(iface_v6, question, type, 0);
+
+ return UBUS_STATUS_OK;
+ } else if (!strcmp(method, "fetch")) {
+ blob_buf_init(&b, 0);
+ void *k = blobmsg_open_array(&b, "records");
+ cache_dump_recursive(&b, question, type, iface_v4 ? iface_v4 : iface_v6);
+ blobmsg_close_array(&b, k);
+ ubus_send_reply(ctx, req, b.head);
+ return UBUS_STATUS_OK;
+ } else {
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+}
+
+