+ msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
+
+ if (!msg) {
+ ctxt.ret = - 1;
+ goto out;
+ }
+
+ nlmsg_append(msg, &ifa, sizeof(ifa), 0);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_valid_handler, &ctxt);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_handler, &ctxt);
+ nl_cb_err(cb, NL_CB_CUSTOM, cb_error_handler, &ctxt);
+
+ nl_send_auto_complete(rtnl_socket, msg);
+ while (ctxt.pending > 0)
+ nl_recvmsgs(rtnl_socket, cb);
+
+ nlmsg_free(msg);
+
+ if (ctxt.ret <= 0)
+ goto out;
+
+ time_t now = odhcpd_time();
+ struct odhcpd_ipaddr *addr = *addrs;
+
+ qsort(addr, ctxt.ret, sizeof(*addr), v6 ? prefix6_cmp : prefix_cmp);
+
+ for (ssize_t i = 0; i < ctxt.ret; ++i) {
+ if (addr[i].preferred < UINT32_MAX - now)
+ addr[i].preferred += now;
+
+ if (addr[i].valid < UINT32_MAX - now)
+ addr[i].valid += now;
+ }
+
+out:
+ nl_cb_put(cb);
+
+ return ctxt.ret;
+}
+
+static int odhcpd_get_linklocal_interface_address(int ifindex, struct in6_addr *lladdr)
+{
+ int status = -1;
+ struct sockaddr_in6 addr = {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, ifindex};
+ socklen_t alen = sizeof(addr);
+ int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+
+ if (!connect(sock, (struct sockaddr*)&addr, sizeof(addr)) &&
+ !getsockname(sock, (struct sockaddr*)&addr, &alen)) {
+ *lladdr = addr.sin6_addr;
+ status = 0;
+ }