diff options
-rw-r--r-- | src/libsystemd/sd-rtnl/rtnl-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-rtnl/rtnl-message.c | 39 | ||||
-rw-r--r-- | src/systemd/sd-rtnl.h | 2 |
3 files changed, 35 insertions, 8 deletions
diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h index 9d857ed991..2f788d04f6 100644 --- a/src/libsystemd/sd-rtnl/rtnl-internal.h +++ b/src/libsystemd/sd-rtnl/rtnl-internal.h @@ -102,6 +102,8 @@ struct sd_rtnl_message { size_t *rta_offset_tb[RTNL_CONTAINER_DEPTH]; unsigned short rta_tb_size[RTNL_CONTAINER_DEPTH]; bool sealed:1; + + sd_rtnl_message *next; /* next in a chain of multi-part messages */ }; int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type); diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index fc71ed9018..3a24cb885f 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -378,6 +378,8 @@ sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) { for (i = 0; i <= m->n_containers; i++) free(m->rta_offset_tb[i]); + sd_rtnl_message_unref(m->next); + free(m); } @@ -1078,6 +1080,8 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) { * On failure, a negative error code is returned. */ int socket_read_message(sd_rtnl *rtnl) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL; + sd_rtnl_message *previous = NULL; _cleanup_free_ void *buffer = NULL; uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))]; struct iovec iov = {}; @@ -1146,6 +1150,10 @@ int socket_read_message(sd_rtnl *rtnl) { if (new_msg->nlmsg_type == NLMSG_NOOP) continue; + /* finished reading multi-part message */ + if (new_msg->nlmsg_type == NLMSG_DONE) + break; + /* check that we support this message type */ r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type); if (r < 0) { @@ -1173,21 +1181,30 @@ int socket_read_message(sd_rtnl *rtnl) { if (r < 0) return r; - r = rtnl_rqueue_make_room(rtnl); - if (r < 0) - return r; + if (!first) + first = m; + else { + assert(previous); - rtnl->rqueue[rtnl->rqueue_size ++] = m; + previous->next = m; + } + previous = m; m = NULL; + ret += new_msg->nlmsg_len; - /* reached end of multi-part message, or not a multi-part - message at all */ - if (new_msg->nlmsg_type == NLMSG_DONE || - !(new_msg->nlmsg_flags & NLM_F_MULTI)) + /* not a multi-part message, so stop reading*/ + if (!(new_msg->nlmsg_flags & NLM_F_MULTI)) break; } + r = rtnl_rqueue_make_room(rtnl); + if (r < 0) + return r; + + rtnl->rqueue[rtnl->rqueue_size ++] = first; + first = NULL; + return ret; } @@ -1249,3 +1266,9 @@ void rtnl_message_seal(sd_rtnl_message *m) { m->sealed = true; } + +sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) { + assert_return(m, NULL); + + return m->next; +} diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h index c32c5e2625..6fbaee092c 100644 --- a/src/systemd/sd-rtnl.h +++ b/src/systemd/sd-rtnl.h @@ -123,6 +123,8 @@ int sd_rtnl_message_exit_container(sd_rtnl_message *m); int sd_rtnl_message_rewind(sd_rtnl_message *m); +sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m); + _SD_END_DECLARATIONS; #endif |