From d4bbdb77aff9abb1aaf13f1f92fb5f9513688ce1 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Tue, 29 Oct 2013 21:20:25 +0100 Subject: [PATCH] rtnl: fix sockaddr confusion --- src/libsystemd-rtnl/rtnl-internal.h | 3 ++- src/libsystemd-rtnl/rtnl-message.c | 26 +++++++++++++++++++------- src/libsystemd-rtnl/sd-rtnl.c | 9 ++++++++- src/libsystemd-rtnl/test-rtnl.c | 16 ++++++++++++++-- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/libsystemd-rtnl/rtnl-internal.h b/src/libsystemd-rtnl/rtnl-internal.h index c24d12b90..70bb6d0b1 100644 --- a/src/libsystemd-rtnl/rtnl-internal.h +++ b/src/libsystemd-rtnl/rtnl-internal.h @@ -31,7 +31,8 @@ struct sd_rtnl { struct sockaddr_nl nl; } sockaddr; - unsigned serial; + uint32_t serial; + pid_t original_pid; }; diff --git a/src/libsystemd-rtnl/rtnl-message.c b/src/libsystemd-rtnl/rtnl-message.c index 557e69017..eae73a65b 100644 --- a/src/libsystemd-rtnl/rtnl-message.c +++ b/src/libsystemd-rtnl/rtnl-message.c @@ -344,13 +344,19 @@ static int message_receive_need(sd_rtnl *rtnl, size_t *need) { /* returns the number of bytes sent, or a negative error code */ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) { + union { + struct sockaddr sa; + struct sockaddr_nl nl; + } addr = { + .nl.nl_family = AF_NETLINK, + }; ssize_t k; assert_return(nl, -EINVAL); assert_return(m, -EINVAL); k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len, - 0, &nl->sockaddr.sa, sizeof(nl->sockaddr)); + 0, &addr.sa, sizeof(addr)); if (k < 0) return (errno == EAGAIN) ? 0 : -errno; @@ -364,7 +370,11 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) { */ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { sd_rtnl_message *m; - socklen_t addr_len = sizeof(nl->sockaddr); + union { + struct sockaddr sa; + struct sockaddr_nl nl; + } addr; + socklen_t addr_len; int r; ssize_t k; size_t need; @@ -380,21 +390,23 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { if (r < 0) return r; + addr_len = sizeof(addr); + k = recvfrom(nl->fd, m->hdr, need, - 0, &nl->sockaddr.sa, &addr_len); + 0, &addr.sa, &addr_len); if (k < 0) k = (errno == EAGAIN) ? 0 : -errno; /* no data */ else if (k == 0) k = -ECONNRESET; /* connection was closed by the kernel */ - else if (addr_len != sizeof(nl->sockaddr.nl) || - nl->sockaddr.nl.nl_family != AF_NETLINK) + else if (addr_len != sizeof(addr.nl) || + addr.nl.nl_family != AF_NETLINK) k = -EIO; /* not a netlink message */ - else if (nl->sockaddr.nl.nl_pid != 0) + else if (addr.nl.nl_pid != 0) k = 0; /* not from the kernel */ else if ((size_t) k < sizeof(struct nlmsghdr) || (size_t) k < m->hdr->nlmsg_len) k = -EIO; /* too small (we do accept too big though) */ - else if ((pid_t) m->hdr->nlmsg_pid != getpid()) + else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid) k = 0; /* not for us */ if (k > 0) diff --git a/src/libsystemd-rtnl/sd-rtnl.c b/src/libsystemd-rtnl/sd-rtnl.c index 9c1f40e48..ed145b9ab 100644 --- a/src/libsystemd-rtnl/sd-rtnl.c +++ b/src/libsystemd-rtnl/sd-rtnl.c @@ -60,6 +60,7 @@ static bool rtnl_pid_changed(sd_rtnl *rtnl) { int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) { _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL; + socklen_t addrlen; int r; r = sd_rtnl_new(&rtnl); @@ -72,10 +73,16 @@ int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) { rtnl->sockaddr.nl.nl_groups = groups; - r = bind(rtnl->fd, &rtnl->sockaddr.sa, sizeof(rtnl->sockaddr)); + addrlen = sizeof(rtnl->sockaddr); + + r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen); if (r < 0) return -errno; + r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen); + if (r < 0) + return r; + *ret = rtnl; rtnl = NULL; diff --git a/src/libsystemd-rtnl/test-rtnl.c b/src/libsystemd-rtnl/test-rtnl.c index 1cdd6e115..601548b78 100644 --- a/src/libsystemd-rtnl/test-rtnl.c +++ b/src/libsystemd-rtnl/test-rtnl.c @@ -51,7 +51,17 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) { assert(type == IFLA_MTU); assert(mtu == *(unsigned int *) data); - assert(sd_rtnl_send_with_reply_and_block(rtnl, message, 2 * USEC_PER_SEC, NULL) == 0); + assert(sd_rtnl_send_with_reply_and_block(rtnl, message, 0, NULL) == 0); +} + +static void test_multiple(void) { + sd_rtnl *rtnl1, *rtnl2; + + assert(sd_rtnl_open(0, &rtnl1) >= 0); + assert(sd_rtnl_open(0, &rtnl2) >= 0); + + rtnl1 = sd_rtnl_unref(rtnl1); + rtnl2 = sd_rtnl_unref(rtnl2); } int main(void) { @@ -64,6 +74,8 @@ int main(void) { unsigned int mtu = 0; unsigned int *mtu_reply; + test_multiple(); + assert(sd_rtnl_open(0, &rtnl) >= 0); assert(rtnl); @@ -80,7 +92,7 @@ int main(void) { assert(sd_rtnl_message_read(m, &type, &data) == 0); - assert(sd_rtnl_send_with_reply_and_block(rtnl, m, 100000000, &r) >= 0); + assert(sd_rtnl_send_with_reply_and_block(rtnl, m, 0, &r) >= 0); assert(sd_rtnl_message_get_type(r, &type) >= 0); assert(type == RTM_NEWLINK); -- 2.30.2