summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2013-10-29 21:20:25 +0100
committerTom Gundersen <teg@jklm.no>2013-10-29 21:26:22 +0100
commitd4bbdb77aff9abb1aaf13f1f92fb5f9513688ce1 (patch)
treec0a82c9b20e4c88c9df97838da931fa3d93db37f
parent897e7561a0f2b0e502fe57081b5d834876c49d7a (diff)
rtnl: fix sockaddr confusion
-rw-r--r--src/libsystemd-rtnl/rtnl-internal.h3
-rw-r--r--src/libsystemd-rtnl/rtnl-message.c26
-rw-r--r--src/libsystemd-rtnl/sd-rtnl.c9
-rw-r--r--src/libsystemd-rtnl/test-rtnl.c16
4 files changed, 43 insertions, 11 deletions
diff --git a/src/libsystemd-rtnl/rtnl-internal.h b/src/libsystemd-rtnl/rtnl-internal.h
index c24d12b907..70bb6d0b18 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 557e69017c..eae73a65b4 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 9c1f40e48a..ed145b9ab3 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 1cdd6e115d..601548b786 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);