diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config.c | 184 |
1 files changed, 99 insertions, 85 deletions
diff --git a/src/config.c b/src/config.c index f6a5327..d33309f 100644 --- a/src/config.c +++ b/src/config.c @@ -1,6 +1,8 @@ +#include <fcntl.h> #include <resolv.h> #include <signal.h> #include <arpa/inet.h> +#include <unistd.h> #include <uci.h> #include <uci_blob.h> @@ -8,6 +10,7 @@ #include "odhcpd.h" static struct blob_buf b; +static int reload_pipe[2]; struct list_head leases = LIST_HEAD_INIT(leases); struct list_head interfaces = LIST_HEAD_INIT(interfaces); struct config config = {false, NULL, NULL}; @@ -487,118 +490,129 @@ static int set_interface(struct uci_section *s) } -static volatile int do_reload = false; void odhcpd_reload(void) { - uloop_cancelled = true; - do_reload = true; -} - - -static void set_stop(int signal) -{ - uloop_cancelled = true; - do_reload = (signal == SIGHUP); -} - -void odhcpd_run(void) -{ struct uci_context *uci = uci_alloc_context(); - signal(SIGTERM, set_stop); - signal(SIGHUP, set_stop); - signal(SIGINT, set_stop); - -#ifdef WITH_UBUS - init_ubus(); -#endif - - do { - do_reload = uloop_cancelled = false; + struct lease *l; + list_for_each_entry(l, &leases, head) { + list_del(&l->head); + free(l->duid); + free(l); + } - struct lease *l; - list_for_each_entry(l, &leases, head) { - list_del(&l->head); - free(l->duid); - free(l); + struct uci_package *dhcp = NULL; + if (!uci_load(uci, "dhcp", &dhcp)) { + struct uci_element *e; + uci_foreach_element(&dhcp->sections, e) { + struct uci_section *s = uci_to_section(e); + if (!strcmp(s->type, "lease")) + set_lease(s); + else if (!strcmp(s->type, "odhcpd")) + set_config(s); } - struct uci_package *dhcp = NULL; - if (!uci_load(uci, "dhcp", &dhcp)) { - struct uci_element *e; - uci_foreach_element(&dhcp->sections, e) { - struct uci_section *s = uci_to_section(e); - if (!strcmp(s->type, "lease")) - set_lease(s); - else if (!strcmp(s->type, "odhcpd")) - set_config(s); - } - - uci_foreach_element(&dhcp->sections, e) { - struct uci_section *s = uci_to_section(e); - if (!strcmp(s->type, "dhcp")) - set_interface(s); - } + uci_foreach_element(&dhcp->sections, e) { + struct uci_section *s = uci_to_section(e); + if (!strcmp(s->type, "dhcp")) + set_interface(s); } + } #ifdef WITH_UBUS - ubus_apply_network(); + ubus_apply_network(); #endif - // Evaluate hybrid mode for master - struct interface *master = NULL, *i, *n; - list_for_each_entry(i, &interfaces, head) { - if (!i->master) - continue; + // Evaluate hybrid mode for master + struct interface *master = NULL, *i, *n; + list_for_each_entry(i, &interfaces, head) { + if (!i->master) + continue; - enum odhcpd_mode hybrid_mode = RELAYD_DISABLED; + enum odhcpd_mode hybrid_mode = RELAYD_DISABLED; #ifdef WITH_UBUS - if (ubus_has_prefix(i->name, i->ifname)) - hybrid_mode = RELAYD_RELAY; + if (ubus_has_prefix(i->name, i->ifname)) + hybrid_mode = RELAYD_RELAY; #endif + if (i->dhcpv6 == RELAYD_HYBRID) + i->dhcpv6 = hybrid_mode; + + if (i->ra == RELAYD_HYBRID) + i->ra = hybrid_mode; + + if (i->ndp == RELAYD_HYBRID) + i->ndp = hybrid_mode; + + if (i->dhcpv6 == RELAYD_RELAY || i->ra == RELAYD_RELAY || i->ndp == RELAYD_RELAY) + master = i; + } + + + list_for_each_entry_safe(i, n, &interfaces, head) { + if (i->inuse) { + // Resolve hybrid mode if (i->dhcpv6 == RELAYD_HYBRID) - i->dhcpv6 = hybrid_mode; + i->dhcpv6 = (master && master->dhcpv6 == RELAYD_RELAY) ? + RELAYD_RELAY : RELAYD_SERVER; if (i->ra == RELAYD_HYBRID) - i->ra = hybrid_mode; + i->ra = (master && master->ra == RELAYD_RELAY) ? + RELAYD_RELAY : RELAYD_SERVER; if (i->ndp == RELAYD_HYBRID) - i->ndp = hybrid_mode; - - if (i->dhcpv6 == RELAYD_RELAY || i->ra == RELAYD_RELAY || i->ndp == RELAYD_RELAY) - master = i; + i->ndp = (master && master->ndp == RELAYD_RELAY) ? + RELAYD_RELAY : RELAYD_SERVER; + + setup_router_interface(i, true); + setup_dhcpv6_interface(i, true); + setup_ndp_interface(i, true); + setup_dhcpv4_interface(i, true); + i->inuse = false; + } else { + close_interface(i); } + } + uci_unload(uci, dhcp); + uci_free_context(uci); +} - list_for_each_entry_safe(i, n, &interfaces, head) { - if (i->inuse) { - // Resolve hybrid mode - if (i->dhcpv6 == RELAYD_HYBRID) - i->dhcpv6 = (master && master->dhcpv6 == RELAYD_RELAY) ? - RELAYD_RELAY : RELAYD_SERVER; - if (i->ra == RELAYD_HYBRID) - i->ra = (master && master->ra == RELAYD_RELAY) ? - RELAYD_RELAY : RELAYD_SERVER; +static void handle_signal(int signal) +{ + char b[1] = {0}; + if (signal == SIGHUP) + write(reload_pipe[1], b, sizeof(b)); + else + uloop_end(); +} - if (i->ndp == RELAYD_HYBRID) - i->ndp = (master && master->ndp == RELAYD_RELAY) ? - RELAYD_RELAY : RELAYD_SERVER; - setup_router_interface(i, true); - setup_dhcpv6_interface(i, true); - setup_ndp_interface(i, true); - setup_dhcpv4_interface(i, true); - i->inuse = false; - } else { - close_interface(i); - } - } - uloop_run(); +static void reload_cb(struct uloop_fd *u, _unused unsigned int events) +{ + char b[512]; + read(u->fd, b, sizeof(b)); + odhcpd_reload(); +} + +static struct uloop_fd reload_fd = { .cb = reload_cb }; + +void odhcpd_run(void) +{ + pipe2(reload_pipe, O_NONBLOCK | O_CLOEXEC); + reload_fd.fd = reload_pipe[0]; + uloop_fd_add(&reload_fd, ULOOP_READ); + + signal(SIGTERM, handle_signal); + signal(SIGINT, handle_signal); + signal(SIGHUP, handle_signal); + +#ifdef WITH_UBUS + init_ubus(); +#endif - if (dhcp) - uci_unload(uci, dhcp); - } while (do_reload); + odhcpd_reload(); + uloop_run(); } |