diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 8cc95156..ea8a63bf 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -208,7 +208,7 @@ static void dhcpv6_ia_free_assignment(struct dhcp_assignment *a) close(a->managed_sock.fd.fd); } - if ((a->flags & OAF_BOUND) && (a->flags & OAF_DHCPV6_PD)) + if (a->flags & OAF_BOUND) apply_lease(a, false); if (a->fr_cnt) @@ -591,6 +591,10 @@ void dhcpv6_ia_write_statefile(void) static void __apply_lease(struct dhcp_assignment *a, struct odhcpd_ipaddr *addrs, ssize_t addr_len, bool add) { + #ifdef WITH_UBUS + ubus_bcast_dhcp6_event(add ? "dhcpv6.ack" : "dhcpv6.release", a, addr_len, addrs); + #endif + if (a->flags & OAF_DHCPV6_NA) return; @@ -844,6 +848,9 @@ static bool assign_na(struct interface *iface, struct dhcp_assignment *a) list_for_each_entry(c, &iface->ia_assignments, head) { if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id > a->assigned_host_id ) { list_add_tail(&a->head, &c->head); + if (a->flags &OAF_BOUND) + apply_lease(a, true); + return true; } else if (c->assigned_host_id == a->assigned_host_id) return false; @@ -891,6 +898,9 @@ static bool assign_na(struct interface *iface, struct dhcp_assignment *a) if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id > try) { a->assigned_host_id = try; list_add_tail(&a->head, &c->head); + if (a->flags &OAF_BOUND) + apply_lease(a, true); + return true; } else if (c->assigned_host_id == try) break; diff --git a/src/odhcpd.h b/src/odhcpd.h index 916d6dae..ee4b6f55 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -510,6 +510,12 @@ void ubus_apply_network(void); bool ubus_has_prefix(const char *name, const char *ifname); void ubus_bcast_dhcp_event(const char *type, const uint8_t *mac, const size_t mac_len, const struct in_addr *addr, const char *name, const char *interface); +void ubus_bcast_dhcp6_event( + const char* type, + const struct dhcp_assignment *assignment, + size_t addrs_len, + const struct odhcpd_ipaddr addrs[static addrs_len] +); #endif ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *iface, diff --git a/src/ubus.c b/src/ubus.c index 00fd171b..4b2c6c0b 100644 --- a/src/ubus.c +++ b/src/ubus.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,7 +7,9 @@ #include #include +#include +#include "libubox/blobmsg.h" #include "odhcpd.h" #include "dhcpv6.h" #include "dhcpv4.h" @@ -416,6 +419,88 @@ void ubus_bcast_dhcp_event(const char *type, const uint8_t *mac, ubus_notify(ubus, &main_object, type, b.head, -1); } +void ubus_bcast_dhcp6_event( + const char* type, + const struct dhcp_assignment *assignment, + size_t addrs_len_, + const struct odhcpd_ipaddr addrs[static addrs_len_] +) { + if (type == NULL || assignment == NULL || (addrs_len_ != 0 && addrs == NULL) || addrs_len_ > PTRDIFF_MAX) + return; + + ptrdiff_t addrs_len = addrs_len_; + + if (ubus == NULL || !main_object.has_subscribers) + return; + + blob_buf_init(&b, 0); + if (assignment->hostname != NULL) + blobmsg_add_string(&b, "hostname", assignment->hostname); + + if (assignment->iface != NULL && assignment->iface->ifname != NULL) + blobmsg_add_string(&b, "interface", assignment->iface->ifname); + + if (assignment->iaid != 0) + blobmsg_add_u32(&b, "iaid", ntohl(assignment->iaid)); + + if (assignment->clid_len != 0) { + char *duid_buf = blobmsg_alloc_string_buffer(&b, "duid", assignment->clid_len * 2 + 1); + odhcpd_hexlify(duid_buf, assignment->clid_data, assignment->clid_len); + blobmsg_add_string_buffer(&b); + } + + blobmsg_add_u8(&b, "accept-reconf", assignment->accept_fr_nonce); + blobmsg_add_u64(&b, "valid-until", assignment->valid_until); + blobmsg_add_u64(&b, "preferred-until", assignment->preferred_until); + + if (assignment->flags & OAF_DHCPV6_NA) + blobmsg_add_u64(&b, "assigned", assignment->assigned_host_id); + else + blobmsg_add_u16(&b, "assigned", assignment->assigned_subnet_id); + + { + void *array_h = blobmsg_open_array(&b, "flags"); + if (assignment->flags & OAF_BOUND) + blobmsg_add_string(&b, NULL, "bound"); + + if (assignment->flags & OAF_STATIC) + blobmsg_add_string(&b, NULL, "static"); + + blobmsg_close_array(&b, array_h); + } + + void *array_h = blobmsg_open_array(&b, assignment->flags & OAF_DHCPV6_NA ? "ipv6-addr" : "ipv6-prefix"); + for (ptrdiff_t ix = 0; ix != addrs_len; ++ix) { + const struct odhcpd_ipaddr *entry = &addrs[ix]; + + void *table_h = blobmsg_open_table(&b, NULL); + + struct in6_addr prefix = entry->addr.in6; + if (assignment->flags & OAF_DHCPV6_NA) { + prefix.s6_addr32[2] = htonl(assignment->assigned_host_id >> 32); + prefix.s6_addr32[3] = htonl(assignment->assigned_host_id & UINT32_MAX); + } else { + prefix.s6_addr32[1] |= htonl(assignment->assigned_subnet_id); + prefix.s6_addr32[2] = 0; + prefix.s6_addr32[3] = 0; + } + + char *addr_buf = blobmsg_alloc_string_buffer(&b, "address", INET6_ADDRSTRLEN); + memset(addr_buf, 0, INET6_ADDRSTRLEN); + + (void) inet_ntop(AF_INET6, &prefix, addr_buf, INET6_ADDRSTRLEN); + blobmsg_add_string_buffer(&b); + + if (entry->prefix != 128) + blobmsg_add_u8(&b, "prefix-length", entry->prefix); + + blobmsg_close_table(&b, table_h); + } + + blobmsg_close_array(&b, array_h); + ubus_notify(ubus, &main_object, type, b.head, -1); +} + static void handle_event(_unused struct ubus_context *ctx, _unused struct ubus_event_handler *ev, _unused const char *type, struct blob_attr *msg) {