Commit 5d162f20 authored by Simon Kelley's avatar Simon Kelley

Rationalise join_multicast()

parent 9d299494
......@@ -607,84 +607,6 @@ void dhcp_construct_contexts(time_t now)
send_alarm(periodic_ra(now), now);
}
}
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad,
int preferred, int valid, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
int fd, i, max = *((int *)vparam);
struct iname *tmp;
(void)prefix;
(void)scope;
(void)dad;
(void)preferred;
(void)valid;
/* record which interfaces we join on, so that we do it at most one per
interface, even when they have multiple addresses. Use outpacket
as an array of int, since it's always allocated here and easy
to expand for theoretical vast numbers of interfaces. */
for (i = 0; i < max; i++)
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
return 1;
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
return 0;
if (!indextoname(fd, if_index, ifrn_name))
{
close(fd);
return 0;
}
close(fd);
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name, NULL))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_ra &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
((int *)daemon->outpacket.iov_base)[max++] = if_index;
*((int *)vparam) = max;
return 1;
}
void join_multicast(void)
{
int count = 0;
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
}
#endif
......
......@@ -220,12 +220,6 @@ int main (int argc, char **argv)
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->doing_dhcp6 || daemon->doing_ra)
join_multicast();
#endif
if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
......@@ -255,6 +249,12 @@ int main (int argc, char **argv)
}
else
create_wildcard_listeners();
#ifdef HAVE_DHCP6
/* after enumerate_interfaces() */
if (daemon->doing_dhcp6 || daemon->doing_ra)
join_multicast(1);
#endif
if (daemon->port != 0)
cache_init();
......
......@@ -428,8 +428,8 @@ struct server {
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth;
char *name;
int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth, index, multicast_done;
char *name;
struct irec *next;
};
......@@ -1001,6 +1001,9 @@ struct in_addr get_ifaddr(char *intr);
#ifdef HAVE_IPV6
int set_ipv6pktinfo(int fd);
#endif
#ifdef HAVE_DHCP6
void join_multicast(int dienow);
#endif
/* dhcp.c */
#ifdef HAVE_DHCP
......@@ -1151,7 +1154,6 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
int prefix, u64 addr);
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
void join_multicast(void);
#endif
/* rfc3315.c */
......
......@@ -39,6 +39,7 @@ static struct iovec iov;
static u32 netlink_pid;
static int nl_async(struct nlmsghdr *h);
static void nl_newinterface(time_t now);
void netlink_init(void)
{
......@@ -199,23 +200,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
/* handle async new interface address arrivals, these have to be done
after we complete as we're not re-entrant */
if (newaddr)
{
time_t now = dnsmasq_time();
nl_newinterface(dnsmasq_time());
if (option_bool(OPT_CLEVERBIND))
{
enumerate_interfaces();
create_bound_listeners(0);
}
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->doing_ra)
dhcp_construct_contexts(now);
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
return callback_ok;
}
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
......@@ -346,23 +332,9 @@ void netlink_multicast(time_t now)
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
if (newaddr)
{
if (option_bool(OPT_CLEVERBIND))
{
enumerate_interfaces();
create_bound_listeners(0);
}
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->doing_ra)
dhcp_construct_contexts(now);
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
nl_newinterface(now);
}
static int nl_async(struct nlmsghdr *h)
......@@ -410,7 +382,28 @@ static int nl_async(struct nlmsghdr *h)
return 0;
}
static void nl_newinterface(time_t now)
{
if (option_bool(OPT_CLEVERBIND))
{
enumerate_interfaces();
create_bound_listeners(0);
}
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->doing_ra)
{
dhcp_construct_contexts(now);
join_multicast(0);
}
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
#endif
......@@ -272,7 +272,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
iface->dns_auth = auth_dns;
iface->mtu = mtu;
iface->dad = dad;
iface->done = 0;
iface->done = iface->multicast_done = 0;
iface->index = if_index;
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
{
strcpy(iface->name, ifr.ifr_name);
......@@ -281,6 +282,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
return 1;
}
free(iface);
}
errno = ENOMEM;
......@@ -587,6 +589,61 @@ int is_dad_listeners(void)
return 0;
}
#ifdef HAVE_DHCP6
void join_multicast(int dienow)
{
struct irec *iface, *tmp;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->dhcp_ok && !iface->multicast_done)
{
/* There's an irec per address but we only want to join for multicast
once per interface. Weed out duplicates. */
for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
if (tmp->multicast_done && tmp->index == iface->index)
break;
iface->multicast_done = 1;
if (!tmp)
{
struct ipv6_mreq mreq;
int err = 0;
mreq.ipv6mr_interface = iface->index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_ra &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
if (err)
{
char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
if (dienow)
die(s, iface->name, EC_BADNET);
else
my_syslog(LOG_ERR, s, iface->name, strerror(errno));
}
}
}
}
#endif
/* return a UDP socket bound to a random port, have to cope with straying into
occupied port nos and reserved ones. */
int random_sock(int family)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment