# endif
#endif
-#if defined(DHCPv6)
-/*
- * XXX: this is gross. we need to go back and overhaul the API for socket
- * handling and make an additional layer for v6 sockets.
- */
-static unsigned int global_v6_socket_references = 0;
-static int global_v6_socket = -1;
-
-static void if_register_multicast(struct interface_info *info);
-#endif
-
/*
* If we can't bind() to a specific interface, then we can only have
* a single socket. This variable insures that we don't try to listen
/* Generic interface registration routine... */
int
-if_register_socket(struct interface_info *info, int family) {
+if_register_socket(struct interface_info *info, int family, int do_multicast) {
struct sockaddr_storage name;
int name_len;
int sock;
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&name;
addr->sin6_family = AF_INET6;
addr->sin6_port = local_port;
- /* XXX: what will happen to multicasts if this is nonzero? */
memcpy(&addr->sin6_addr,
&local_address6,
sizeof(addr->sin6_addr));
log_fatal("Can't set SO_BROADCAST option on dhcp socket: %m");
}
-#if defined(DHCPv6) && defined(SO_REUSEPORT)
- /*
- * We only set SO_REUSEPORT on AF_INET6 sockets, so that multiple
- * daemons can bind to their own sockets and get data for their
- * respective interfaces. This does not (and should not) affect
- * DHCPv4 sockets; we can't yet support BSD sockets well, much
- * less multiple sockets.
- */
- if (local_family == AF_INET6) {
- flag = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
- (char *)&flag, sizeof(flag)) < 0) {
- log_fatal("Can't set SO_REUSEPORT option on dhcp "
- "socket: %m");
- }
- }
-#endif
-
/* Bind the socket to this interface's IP address. */
if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
log_error("Can't bind to dhcp address: %m");
#if defined(SO_BINDTODEVICE)
/* Bind this socket to this interface. */
- if ((local_family != AF_INET6) && (info->ifp != NULL) &&
+ if (info->ifp &&
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
(char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) {
log_fatal("setsockopt: SO_BINDTODEVICE: %m");
}
#endif
}
+
+ if ((family == AF_INET6) && do_multicast) {
+ struct ipv6_mreq mreq;
+
+ /*
+ * Join the DHCPv6 multicast groups so we will receive
+ * multicast messages.
+ */
+ if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
+ &mreq.ipv6mr_multiaddr) <= 0) {
+ log_fatal("inet_pton: unable to convert '%s'",
+ All_DHCP_Relay_Agents_and_Servers);
+ }
+ mreq.ipv6mr_interface = if_nametoindex(info->name);
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &mreq, sizeof(mreq)) < 0) {
+ log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
+ }
+ if (inet_pton(AF_INET6, All_DHCP_Servers,
+ &mreq.ipv6mr_multiaddr) <= 0) {
+ log_fatal("inet_pton: unable to convert '%s'",
+ All_DHCP_Servers);
+ }
+ mreq.ipv6mr_interface = if_nametoindex(info->name);
+ if (((info->flags & INTERFACE_DOWNSTREAM) == 0) &&
+ (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &mreq, sizeof(mreq)) < 0)) {
+ log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
+ }
+ }
if ((family == AF_INET6) &&
((info->flags & INTERFACE_UPSTREAM) != 0)) {
}
#endif /* DHCPv6 */
- /* If this is a normal IPv4 address, get the hardware address. */
- if ((local_family == AF_INET) && (strcmp(info->name, "fallback") != 0))
+ if (strcmp(info->name, "fallback") != 0)
get_hw_addr(info->name, &info->hw_address);
return sock;
struct interface_info *info;
{
#ifndef USE_SOCKET_RECEIVE
- info -> wfdesc = if_register_socket (info, AF_INET);
+ info -> wfdesc = if_register_socket (info, AF_INET, 0);
#if defined (USE_SOCKET_FALLBACK)
/* Fallback only registers for send, but may need to receive as
well. */
#ifdef DHCPv6
-/*
- * This function joines the interface to DHCPv6 multicast groups so we will
- * receive multicast messages.
- */
-static void
-if_register_multicast(struct interface_info *info) {
- int sock = info->rfdesc;
- struct ipv6_mreq mreq;
-
- if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
- &mreq.ipv6mr_multiaddr) <= 0) {
- log_fatal("inet_pton: unable to convert '%s'",
- All_DHCP_Relay_Agents_and_Servers);
- }
- mreq.ipv6mr_interface = if_nametoindex(info->name);
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
- &mreq, sizeof(mreq)) < 0) {
- log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
- }
- if (inet_pton(AF_INET6, All_DHCP_Servers,
- &mreq.ipv6mr_multiaddr) <= 0) {
- log_fatal("inet_pton: unable to convert '%s'",
- All_DHCP_Servers);
- }
- mreq.ipv6mr_interface = if_nametoindex(info->name);
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
- &mreq, sizeof(mreq)) < 0) {
- log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
- }
-}
-
void
if_register6(struct interface_info *info, int do_multicast) {
- if (global_v6_socket_references == 0) {
- global_v6_socket = if_register_socket(info, AF_INET6);
- if (global_v6_socket < 0) {
- /*
- * if_register_socket() fatally logs if it fails
- * to create a socket, so this is just a sanity
- * check.
- */
- log_fatal("Impossible condition at %s:%d", MDL);
- } else {
- log_info("Bound to *:%d", ntohs(local_port));
- }
- }
-
- /* Reference the global v6 socket. */
- info->rfdesc = global_v6_socket;
- info->wfdesc = global_v6_socket;
- global_v6_socket_references++;
-
- if (do_multicast)
- if_register_multicast(info);
-
- get_hw_addr(info->name, &info->hw_address);
-
+ info->rfdesc = if_register_socket(info, AF_INET6, do_multicast);
+ info->wfdesc = info->rfdesc;
if (!quiet_interface_discovery) {
if (info->shared_network != NULL) {
- log_info("Listening on Socket/%d/%s/%s",
- global_v6_socket, info->name,
+ log_info("Listening on Socket/%s/%s", info->name,
info->shared_network->name);
- log_info("Sending on Socket/%d/%s/%s",
- global_v6_socket, info->name,
+ log_info("Sending on Socket/%s/%s", info->name,
info->shared_network->name);
} else {
log_info("Listening on Socket/%s", info->name);
void
if_deregister6(struct interface_info *info) {
- /* Dereference the global v6 socket. */
- if ((info->rfdesc == global_v6_socket) &&
- (info->wfdesc == global_v6_socket) &&
- (global_v6_socket_references > 0)) {
- global_v6_socket_references--;
- info->rfdesc = -1;
- info->wfdesc = -1;
- } else {
- log_fatal("Impossible condition at %s:%d", MDL);
- }
+ /*
+ * XXX: it would be nice to check for >= 0, but we need to change
+ * interface_allocate() to set the file descriptors for that.
+ */
+ close(info->rfdesc);
+ info->rfdesc = -1;
+ close(info->wfdesc);
+ info->wfdesc = -1;
if (!quiet_interface_discovery) {
if (info->shared_network != NULL) {
log_info("Disabling output on Socket/%s", info->name);
}
}
-
- if (global_v6_socket_references == 0) {
- close(global_v6_socket);
- global_v6_socket = -1;
-
- log_info("Unbound from *:%d", ntohs(local_port));
- }
}
#endif /* DHCPv6 */
ssize_t
receive_packet6(struct interface_info *interface,
unsigned char *buf, size_t len,
- struct sockaddr_in6 *from, struct in6_addr *to_addr,
- unsigned int *if_idx) {
+ struct sockaddr_in6 *from, struct in6_addr *to_addr) {
struct msghdr m;
struct iovec v;
int result;
struct cmsghdr *cmsg;
struct in6_pktinfo *pktinfo;
- int found_pktinfo;
+ int found_to_addr;
union {
struct cmsghdr cmsg_sizer;
u_int8_t pktinfo_sizer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
* We also keep a flag to see if we found it. If we
* didn't, then we consider this to be an error.
*/
- found_pktinfo = 0;
+ found_to_addr = 0;
cmsg = CMSG_FIRSTHDR(&m);
while (cmsg != NULL) {
if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
(cmsg->cmsg_type == IPV6_PKTINFO)) {
pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
*to_addr = pktinfo->ipi6_addr;
- *if_idx = pktinfo->ipi6_ifindex;
- found_pktinfo = 1;
+ found_to_addr = 1;
}
cmsg = CMSG_NXTHDR(&m, cmsg);
}
- if (!found_pktinfo) {
+ if (!found_to_addr) {
result = -1;
errno = EIO;
}