# define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
#endif
+struct priv {
+ int pf_inet6_fd;
+};
+
int
if_init(__unused struct interface *iface)
{
}
int
-if_openlinksocket(void)
+if_opensockets_os(struct dhcpcd_ctx *ctx)
+{
+ struct priv *priv;
+
+ if ((priv = malloc(sizeof(*priv))) == NULL)
+ return -1;
+ ctx->priv = priv;
+
+#ifdef INET6
+ priv->pf_inet6_fd = xsocket(PF_INET6, SOCK_DGRAM, 0, SOCK_CLOEXEC);
+ /* Don't return an error so we at least work on kernels witout INET6
+ * even though we expect INET6 support.
+ * We will fail noisily elsewhere anyway. */
+#else
+ priv->pf_inet6_fd = -1;
+#endif
+
+ ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM, 0, SOCK_CLOEXEC);
+ return ctx->pf_link_fd == -1 ? -1 : 0;
+}
+
+void
+if_closesockets_os(struct dhcpcd_ctx *ctx)
{
+ struct priv *priv;
- return xsocket(PF_ROUTE, SOCK_RAW, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
+ priv = (struct priv *)ctx->priv;
+ if (priv->pf_inet6_fd != -1)
+ close(priv->pf_inet6_fd);
}
#if defined(INET) || defined(INET6)
#include "bpf-filter.h"
+struct priv {
+ int route_fd;
+ uint32_t route_pid;
+};
+
/* Broadcast address for IPoIB */
static const uint8_t ipv4_bcast_addr[] = {
0x00, 0xff, 0xff, 0xff,
}
int
-if_openlinksocket(void)
+if_opensockets_os(struct dhcpcd_ctx *ctx)
{
+ struct priv *priv;
struct sockaddr_nl snl;
+ socklen_t len;
+ /* Open the link socket first so it gets pid() for the socket.
+ * Then open our persistent route socket so we get a unique
+ * pid that doesn't clash with a process id for after we fork. */
memset(&snl, 0, sizeof(snl));
snl.nl_groups = RTMGRP_LINK;
snl.nl_groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH;
#endif
- return _open_link_socket(&snl, NETLINK_ROUTE);
+ ctx->link_fd = _open_link_socket(&snl, NETLINK_ROUTE);
+ if (ctx->link_fd == -1)
+ return -1;
+
+ if ((priv = calloc(1, sizeof(*priv))) == NULL)
+ return -1;
+
+ ctx->priv = priv;
+ memset(&snl, 0, sizeof(snl));
+ priv->route_fd = _open_link_socket(&snl, NETLINK_ROUTE);
+ if (priv->route_fd == -1)
+ return -1;
+ len = sizeof(snl);
+ if (getsockname(priv->route_fd, (struct sockaddr *)&snl, &len) == -1)
+ return -1;
+ priv->route_pid = snl.nl_pid;
+ return 0;
+}
+
+void
+if_closesockets_os(struct dhcpcd_ctx *ctx)
+{
+ struct priv *priv;
+
+ if (ctx->priv != NULL) {
+ priv = (struct priv *)ctx->priv;
+ close(priv->route_fd);
+ }
}
static int
goto eexit;
buf = nbuf;
}
- nladdr.nl_pid = 0;
nladdr_len = sizeof(nladdr);
bytes = recvfrom(fd, buf, buflen, flags,
(struct sockaddr *)&nladdr, &nladdr_len);
r = err_netlink(nlm);
if (r == -1)
goto eexit;
- if (r)
- continue;
- if (callback) {
+
+ if (r == 0 && callback) {
r = callback(ctx, ifp, nlm);
if (r != 0)
goto eexit;
}
#endif
-/* Work out the maximum pid size */
-static inline long long
-get_max_pid_t()
-{
-
- if (sizeof(pid_t) == sizeof(short)) return SHRT_MAX;
- if (sizeof(pid_t) == sizeof(int)) return INT_MAX;
- if (sizeof(pid_t) == sizeof(long)) return LONG_MAX;
- if (sizeof(pid_t) == sizeof(long long)) return LLONG_MAX;
- abort();
-}
-
static int
link_route(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
struct nlmsghdr *nlm)
size_t len;
struct rtmsg *rtm;
int cmd;
+ struct priv *priv;
#ifdef INET
struct rt rt;
#endif
return -1;
}
- /* Ignore messages generated by us.
- * For some reason we get messages generated by us
- * with a very large value in nlmsg_pid that seems to be
- * sequentially changing. Is there a better test for this? */
- if (nlm->nlmsg_pid > get_max_pid_t())
- return 1;
+ /* Ignore messages we sent. */
+ priv = (struct priv *)ctx->priv;
+ if (nlm->nlmsg_pid == priv->route_pid)
+ return 0;
rtm = NLMSG_DATA(nlm);
switch (rtm->rtm_family) {
size_t len;
struct rtattr *rta;
struct ifaddrmsg *ifa;
+ struct priv *priv;
#ifdef INET
struct in_addr addr, net, dest;
#endif
return -1;
}
- /* Ignore messages generated by us.
- * For some reason we get messages generated by us
- * with a very large value in nlmsg_pid that seems to be
- * sequentially changing. Is there a better test for this? */
- if (nlm->nlmsg_pid > get_max_pid_t())
- return 1;
+ /* Ignore messages we sent. */
+ priv = (struct priv*)ctx->priv;
+ if (nlm->nlmsg_pid == priv->route_pid)
+ return 0;
ifa = NLMSG_DATA(nlm);
if ((ifp = if_findindex(ctx->ifaces, ifa->ifa_index)) == NULL) {
struct msghdr msg;
memset(&snl, 0, sizeof(snl));
- if ((s = _open_link_socket(&snl, protocol)) == -1)
- return -1;
- memset(&iov, 0, sizeof(iov));
- iov.iov_base = hdr;
- iov.iov_len = hdr->nlmsg_len;
+ snl.nl_family = AF_NETLINK;
+
+ if (protocol == NETLINK_ROUTE) {
+ struct priv *priv;
+
+ priv = (struct priv *)ctx->priv;
+ s = priv->route_fd;
+ } else {
+ if ((s = _open_link_socket(&snl, protocol)) == -1)
+ return -1;
+ }
+
memset(&msg, 0, sizeof(msg));
msg.msg_name = &snl;
msg.msg_namelen = sizeof(snl);
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = hdr;
+ iov.iov_len = hdr->nlmsg_len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* Request a reply */
hdr->nlmsg_seq = (uint32_t)++ctx->seq;
if ((unsigned int)ctx->seq > UINT32_MAX)
ctx->seq = 0;
-
if (sendmsg(s, &msg, 0) != -1) {
ctx->sseq = ctx->seq;
r = get_netlink(ctx, ifp, s, 0, callback);
} else
r = -1;
- close(s);
+ if (protocol != NETLINK_ROUTE)
+ close(s);
return r;
}