diff options
author | Tom Gundersen <teg@jklm.no> | 2014-01-24 21:04:05 +0100 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2014-01-24 22:20:34 +0100 |
commit | e5c4350b0d91551041795eb3c4fd4f22b2604ee2 (patch) | |
tree | 0444279a3e163630e68a6ef53b668461c68a7821 /src/libsystemd/sd-rtnl | |
parent | 1fa132931a3eed8556da801d9fe91aa4c166445e (diff) |
sd-rtnl: add support for reading containers
Also insist on messages being sealed before reading them. In other
words we don't allow interleaving of reading and appending to messages.
Diffstat (limited to 'src/libsystemd/sd-rtnl')
-rw-r--r-- | src/libsystemd/sd-rtnl/rtnl-message.c | 76 | ||||
-rw-r--r-- | src/libsystemd/sd-rtnl/test-rtnl.c | 37 |
2 files changed, 87 insertions, 26 deletions
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index 3cf8579cfc..85c59bfed1 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -45,6 +45,7 @@ struct sd_rtnl_message { #define GET_CONTAINER(m, i) (i < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL) #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset)) #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr; +#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; static int message_new(sd_rtnl_message **ret, size_t initial_size) { sd_rtnl_message *m; @@ -378,6 +379,7 @@ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, assert(m); assert(m->hdr); + assert(!m->sealed); assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len); assert(!data || data_length > 0); assert(data || m->n_containers < RTNL_CONTAINER_DEPTH); @@ -428,6 +430,7 @@ int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const int r; assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); assert_return(data, -EINVAL); r = sd_rtnl_message_get_type(m, &rtm_type); @@ -477,6 +480,7 @@ int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t int r; assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); r = sd_rtnl_message_get_type(m, &rtm_type); if (r < 0) @@ -512,6 +516,7 @@ int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t int r; assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); r = sd_rtnl_message_get_type(m, &rtm_type); if (r < 0) @@ -563,6 +568,7 @@ int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, cons int r; assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); assert_return(data, -EINVAL); r = sd_rtnl_message_get_type(m, &rtm_type); @@ -624,6 +630,7 @@ int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, con int r; assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); assert_return(data, -EINVAL); r = sd_rtnl_message_get_type(m, &rtm_type); @@ -682,6 +689,7 @@ int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, c int r; assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); assert_return(data, -EINVAL); sd_rtnl_message_get_type(m, &rtm_type); @@ -714,6 +722,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) { uint16_t rtm_type; assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); sd_rtnl_message_get_type(m, &rtm_type); @@ -732,6 +741,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) { int sd_rtnl_message_close_container(sd_rtnl_message *m) { assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); assert_return(m->n_containers > 0, -EINVAL); m->n_containers --; @@ -744,34 +754,57 @@ int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) uint16_t rtm_type; int r; - assert(m); - assert(m->next_rta_offset); - assert(type); - assert(data); + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(m->next_rta_offset, -EINVAL); + assert_return(type, -EINVAL); + assert_return(data, -EINVAL); - remaining_size = m->hdr->nlmsg_len - m->next_rta_offset; + /* only read until the end of the current container */ + if (m->n_containers) + remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len - + (m->next_rta_offset - + m->container_offsets[m->n_containers - 1]); + else + remaining_size = m->hdr->nlmsg_len - m->next_rta_offset; if (!RTA_OK(NEXT_RTA(m), remaining_size)) return 0; - /* make sure we don't try to read a container - * TODO: add support for entering containers for reading */ + /* if we read a container, enter it and return its type */ r = sd_rtnl_message_get_type(m, &rtm_type); if (r < 0) return r; - if (message_type_is_link(rtm_type) && - NEXT_RTA(m)->rta_type == IFLA_LINKINFO) - return -EINVAL; - - *data = RTA_DATA(NEXT_RTA(m)); *type = NEXT_RTA(m)->rta_type; - UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size)); + if (message_type_is_link(rtm_type) && + ((m->n_containers == 0 && + NEXT_RTA(m)->rta_type == IFLA_LINKINFO) || + (m->n_containers == 1 && + GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO && + NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) { + *data = NULL; + PUSH_CONTAINER(m, NEXT_RTA(m)); + UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m))); + } else { + *data = RTA_DATA(NEXT_RTA(m)); + UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size)); + } return 1; } +int sd_rtnl_message_exit_container(sd_rtnl_message *m) { + assert_return(m, -EINVAL); + assert_return(m->sealed, -EINVAL); + assert_return(m->n_containers > 0, -EINVAL); + + m->n_containers --; + + return 0; +} + uint32_t message_get_serial(sd_rtnl_message *m) { assert(m); assert(m->hdr); @@ -794,16 +827,23 @@ int sd_rtnl_message_get_errno(sd_rtnl_message *m) { } int message_seal(sd_rtnl *nl, sd_rtnl_message *m) { - assert(nl); + int r; + assert(m); assert(m->hdr); if (m->sealed) return -EPERM; - m->hdr->nlmsg_seq = nl->serial++; + if (nl) + m->hdr->nlmsg_seq = nl->serial++; + m->sealed = true; + r = sd_rtnl_message_rewind(m); + if (r < 0) + return r; + return 0; } @@ -876,6 +916,9 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { if (r < 0) return r; + /* don't allow sealing/appending to received messages */ + m->sealed = true; + addr_len = sizeof(addr); k = recvfrom(nl->fd, m->hdr, need, @@ -961,6 +1004,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) { struct rtmsg *rtm; assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); assert_return(m->hdr, -EINVAL); switch(m->hdr->nlmsg_type) { @@ -990,5 +1034,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) { return -ENOTSUP; } + m->n_containers = 0; + return 0; } diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c index 98213d6782..a173b0fc61 100644 --- a/src/libsystemd/sd-rtnl/test-rtnl.c +++ b/src/libsystemd/sd-rtnl/test-rtnl.c @@ -27,6 +27,7 @@ #include "sd-rtnl.h" #include "socket-util.h" #include "rtnl-util.h" +#include "rtnl-internal.h" #include "event-util.h" static void test_link_configure(sd_rtnl *rtnl, int ifindex) { @@ -42,6 +43,8 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) { assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0); assert(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0); + assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1); + assert(sd_rtnl_message_read(message, &type, &data) > 0); assert(type == IFLA_IFNAME); assert(streq(name, (char *) data)); @@ -53,8 +56,6 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) { assert(sd_rtnl_message_read(message, &type, &data) > 0); assert(type == IFLA_MTU); assert(mtu == *(unsigned int *) data); - - assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1); } static void test_route(void) { @@ -85,6 +86,8 @@ static void test_route(void) { return; } + assert(message_seal(NULL, req) >= 0); + assert(sd_rtnl_message_read(req, &type, &data) > 0); assert(type == RTA_GATEWAY); assert(((struct in_addr *)data)->s_addr == addr.s_addr); @@ -224,15 +227,26 @@ static void test_container(void) { assert(sd_rtnl_message_close_container(m) >= 0); assert(sd_rtnl_message_close_container(m) == -EINVAL); - assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL); + assert(message_seal(NULL, m) >= 0); -/* TODO: add support for entering containers - assert(sd_rtnl_message_read(m, &type, &data) > 0); + assert(sd_rtnl_message_read(m, &type, &data) >= 0); + assert(type == IFLA_LINKINFO); + assert(data == NULL); + assert(sd_rtnl_message_read(m, &type, &data) >= 0); assert(type == IFLA_INFO_KIND); - assert(streq("kind", (char *) data)); - - assert(sd_rtnl_message_read(m, &type, &data) == 0); -*/ + assert(streq("kind", (char *)data)); + assert(sd_rtnl_message_read(m, &type, &data) >= 0); + assert(type == IFLA_INFO_DATA); + assert(data == NULL); + assert(sd_rtnl_message_read(m, &type, &data) >= 0); + assert(type == IFLA_VLAN_ID); + assert(*(uint16_t *)data == 100); + assert(sd_rtnl_message_exit_container(m) >= 0); + assert(sd_rtnl_message_read(m, &type, &data) >= 0); + assert(type == IFLA_INFO_KIND); + assert(streq("kind", (char *)data)); + assert(sd_rtnl_message_exit_container(m) >= 0); + assert(sd_rtnl_message_exit_container(m) == -EINVAL); } static void test_match(void) { @@ -286,7 +300,7 @@ int main(void) { assert(sd_rtnl_message_get_type(m, &type) >= 0); assert(type == RTM_GETLINK); - assert(sd_rtnl_message_read(m, &type, &data) == 0); + assert(sd_rtnl_message_read(m, &type, &data) == -EPERM); assert(sd_rtnl_call(rtnl, m, 0, &r) == 1); assert(sd_rtnl_message_get_type(r, &type) >= 0); @@ -303,6 +317,8 @@ int main(void) { assert(m); assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0); + assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == -EPERM); + assert(sd_rtnl_call(rtnl, m, -1, &r) == 1); assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1); assert(type == IFLA_MTU); @@ -310,7 +326,6 @@ int main(void) { assert(sd_rtnl_message_read(m, &type, &data) == 0); - assert(sd_rtnl_call(rtnl, m, -1, &r) == 1); while (sd_rtnl_message_read(r, &type, &data) > 0) { switch (type) { // case IFLA_MTU: |