+ return NULL;
+}
+
+int interface_add(const char *name)
+{
+ struct interface *v4 = NULL, *v6 = NULL, *unicast;
+ struct ifaddrs *ifap, *ifa;
+
+ getifaddrs(&ifap);
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (strcmp(ifa->ifa_name, name))
+ continue;
+ if (ifa->ifa_addr->sa_family == AF_INET && !v4) {
+ struct sockaddr_in *sa;
+
+ if (cfg_proto && (cfg_proto != 4))
+ continue;
+
+ unicast = _interface_add(name, 0, 0);
+ if (!unicast)
+ continue;
+ v4 = _interface_add(name, 1, 0);
+ if (!v4)
+ continue;
+
+ sa = (struct sockaddr_in *) ifa->ifa_addr;
+ memcpy(&v4->v4_addr, &sa->sin_addr, sizeof(v4->v4_addr));
+ memcpy(&unicast->v4_addr, &sa->sin_addr, sizeof(unicast->v4_addr));
+
+ inet_ntop(AF_INET, &sa->sin_addr, v4->v4_addrs, sizeof(v4->v4_addrs));
+ inet_ntop(AF_INET, &sa->sin_addr, unicast->v4_addrs, sizeof(unicast->v4_addrs));
+
+ sa = (struct sockaddr_in *) ifa->ifa_netmask;
+ memcpy(&unicast->v4_netmask, &sa->sin_addr, sizeof(unicast->v4_netmask));
+ memcpy(&v4->v4_netmask, &sa->sin_addr, sizeof(v4->v4_netmask));
+
+ v4->peer = unicast;
+ unicast->peer = v4;
+ }
+
+ if (ifa->ifa_addr->sa_family == AF_INET6 && !v6) {
+ uint8_t ll_prefix[] = {0xfe, 0x80 };
+ struct sockaddr_in6 *sa6;
+
+ if (cfg_proto && (cfg_proto != 6))
+ continue;
+
+ sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
+ if (memcmp(&sa6->sin6_addr, &ll_prefix, 2))
+ continue;
+
+ unicast = _interface_add(name, 0, 1);
+ if (!unicast)
+ continue;
+ v6 = _interface_add(name, 1, 1);
+ if (!v6)
+ continue;
+
+ memcpy(&v6->v6_addr, &sa6->sin6_addr, sizeof(v6->v6_addr));
+ memcpy(&unicast->v6_addr, &sa6->sin6_addr, sizeof(unicast->v6_addr));
+
+ inet_ntop(AF_INET6, &sa6->sin6_addr, v6->v6_addrs, sizeof(v6->v6_addrs));
+ inet_ntop(AF_INET6, &sa6->sin6_addr, unicast->v6_addrs, sizeof(unicast->v6_addrs));
+
+ sa6 = (struct sockaddr_in6 *) ifa->ifa_netmask;
+ memcpy(&v6->v6_netmask, &sa6->sin6_addr, sizeof(v6->v6_netmask));
+ memcpy(&unicast->v6_netmask, &sa6->sin6_addr, sizeof(unicast->v6_netmask));
+
+ v6->peer = unicast;
+ unicast->peer = v6;
+ }
+ }
+
+ freeifaddrs(ifap);
+
+ return !v4 && !v6;
+}
+
+void interface_shutdown(void)
+{
+ struct interface *iface;
+
+ vlist_for_each_element(&interfaces, iface, node)
+ if (iface->fd.fd > 0 && iface->multicast) {
+ service_announce(iface, 0);
+ service_reply_a(iface, 0);
+ }
+ vlist_for_each_element(&interfaces, iface, node)
+ interface_close(iface);
+}
+
+struct interface*
+interface_get(const char *name, int v6, int multicast)
+{
+ char id_buf[32];
+ snprintf(id_buf, sizeof(id_buf), "%d_%d_%s", multicast, v6, name);
+ struct interface *iface = vlist_find(&interfaces, id_buf, iface, node);
+ return iface;