summaryrefslogtreecommitdiff
path: root/src/libsystemd/sd-rtnl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd/sd-rtnl')
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-message.c4
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-types.c1
-rw-r--r--src/libsystemd/sd-rtnl/sd-rtnl.c43
3 files changed, 32 insertions, 16 deletions
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index 5a719003ac..c938471fe3 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -1554,7 +1554,9 @@ int socket_read_message(sd_rtnl *rtnl) {
/* finished reading multi-part message */
done = true;
- continue;
+ /* if first is not defined, put NLMSG_DONE into the receive queue. */
+ if (first)
+ continue;
}
/* check that we support this message type */
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.c b/src/libsystemd/sd-rtnl/rtnl-types.c
index e21c898668..bf7278fe44 100644
--- a/src/libsystemd/sd-rtnl/rtnl-types.c
+++ b/src/libsystemd/sd-rtnl/rtnl-types.c
@@ -411,6 +411,7 @@ static const NLTypeSystem rtnl_neigh_type_system = {
};
static const NLType rtnl_types[RTM_MAX + 1] = {
+ [NLMSG_DONE] = { .type = NLA_META, .size = 0 },
[NLMSG_ERROR] = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
[RTM_NEWLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_DELLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c
index 50162c3ee9..40dea1252f 100644
--- a/src/libsystemd/sd-rtnl/sd-rtnl.c
+++ b/src/libsystemd/sd-rtnl/sd-rtnl.c
@@ -421,8 +421,9 @@ static int process_timeout(sd_rtnl *rtnl) {
}
static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
- struct reply_callback *c;
+ _cleanup_free_ struct reply_callback *c = NULL;
uint64_t serial;
+ uint16_t type;
int r;
assert(rtnl);
@@ -436,12 +437,17 @@ static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
if (c->timeout != 0)
prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
+ r = sd_rtnl_message_get_type(m, &type);
+ if (r < 0)
+ return 0;
+
+ if (type == NLMSG_DONE)
+ m = NULL;
+
r = c->callback(rtnl, m, c->userdata);
if (r < 0)
log_debug_errno(r, "sd-rtnl: callback failed: %m");
- free(c);
-
return 1;
}
@@ -702,7 +708,6 @@ int sd_rtnl_call(sd_rtnl *rtnl,
sd_rtnl_message **ret) {
usec_t timeout;
uint32_t serial;
- unsigned i = 0;
int r;
assert_return(rtnl, -EINVAL);
@@ -717,36 +722,44 @@ int sd_rtnl_call(sd_rtnl *rtnl,
for (;;) {
usec_t left;
+ unsigned i;
- while (i < rtnl->rqueue_size) {
- sd_rtnl_message *incoming;
+ for (i = 0; i < rtnl->rqueue_size; i++) {
uint32_t received_serial;
- incoming = rtnl->rqueue[i];
- received_serial = rtnl_message_get_serial(incoming);
+ received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
if (received_serial == serial) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
+ uint16_t type;
+
+ incoming = rtnl->rqueue[i];
+
/* found a match, remove from rqueue and return it */
memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
rtnl->rqueue_size--;
r = sd_rtnl_message_get_errno(incoming);
- if (r < 0) {
- sd_rtnl_message_unref(incoming);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_get_type(incoming, &type);
+ if (r < 0)
return r;
+
+ if (type == NLMSG_DONE) {
+ *ret = NULL;
+ return 0;
}
if (ret) {
*ret = incoming;
- } else
- sd_rtnl_message_unref(incoming);
+ incoming = NULL;
+ }
return 1;
}
-
- /* Try to read more, right away */
- i ++;
}
r = socket_read_message(rtnl);