/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991, or (at your option) version 3 dated 29 June, 2007. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "dnsmasq.h" #ifdef HAVE_UBUS #include static struct blob_buf b; static int notify; static int error_logged = 0; static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg); static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj); static const struct ubus_method ubus_object_methods[] = { UBUS_METHOD_NOARG("metrics", ubus_handle_metrics), }; static struct ubus_object_type ubus_object_type = UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods); static struct ubus_object ubus_object = { .name = NULL, .type = &ubus_object_type, .methods = ubus_object_methods, .n_methods = ARRAY_SIZE(ubus_object_methods), .subscribe_cb = ubus_subscribe_cb, }; static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj) { (void)ctx; my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0"); notify = obj->has_subscribers; } static void ubus_destroy(struct ubus_context *ubus) { // Forces re-initialization when we're reusing the same definitions later on. ubus_object.id = 0; ubus_object_type.id = 0; ubus_free(ubus); daemon->ubus = NULL; } static void ubus_disconnect_cb(struct ubus_context *ubus) { int ret; ret = ubus_reconnect(ubus, NULL); if (ret) { my_syslog(LOG_ERR, _("Cannot reconnect to UBus: %s"), ubus_strerror(ret)); ubus_destroy(ubus); } } void ubus_init() { struct ubus_context *ubus = NULL; int ret = 0; ubus = ubus_connect(NULL); if (!ubus) { if (!error_logged) { my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed")); error_logged = 1; } ubus_destroy(ubus); return; } ubus_object.name = daemon->ubus_name; ret = ubus_add_object(ubus, &ubus_object); if (ret) { if (!error_logged) { my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret)); error_logged = 1; } ubus_destroy(ubus); return; } ubus->connection_lost = ubus_disconnect_cb; daemon->ubus = ubus; error_logged = 0; my_syslog(LOG_INFO, _("Connected to system UBus")); } void set_ubus_listeners() { struct ubus_context *ubus = (struct ubus_context *)daemon->ubus; if (!ubus) { if (!error_logged) { my_syslog(LOG_ERR, _("Cannot set UBus listeners: no connection")); error_logged = 1; } return; } error_logged = 0; poll_listen(ubus->sock.fd, POLLIN); poll_listen(ubus->sock.fd, POLLERR); poll_listen(ubus->sock.fd, POLLHUP); } void check_ubus_listeners() { struct ubus_context *ubus = (struct ubus_context *)daemon->ubus; if (!ubus) { if (!error_logged) { my_syslog(LOG_ERR, _("Cannot poll UBus listeners: no connection")); error_logged = 1; } return; } error_logged = 0; if (poll_check(ubus->sock.fd, POLLIN)) ubus_handle_event(ubus); if (poll_check(ubus->sock.fd, POLLHUP | POLLERR)) { my_syslog(LOG_INFO, _("Disconnecting from UBus")); ubus_destroy(ubus); } } static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { int i; (void)obj; (void)method; (void)msg; blob_buf_init(&b, BLOBMSG_TYPE_TABLE); for (i=0; i < __METRIC_MAX; i++) blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]); return ubus_send_reply(ctx, req, b.head); } void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface) { struct ubus_context *ubus = (struct ubus_context *)daemon->ubus; int ret; if (!ubus || !notify) return; blob_buf_init(&b, BLOBMSG_TYPE_TABLE); if (mac) blobmsg_add_string(&b, "mac", mac); if (ip) blobmsg_add_string(&b, "ip", ip); if (name) blobmsg_add_string(&b, "name", name); if (interface) blobmsg_add_string(&b, "interface", interface); ret = ubus_notify(ubus, &ubus_object, type, b.head, -1); if (!ret) my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret)); } #endif /* HAVE_UBUS */