X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Frtnl-message.c;h=fb429864b94c09776433d4b82f1feea3318b8569;hb=127dc4ea9487397b1ab70447e2f44d091e44ab5f;hp=3362958f360a11309672e961d93636723a822979;hpb=6e20c8f8fa095b28ef4e08d9dae494abed6f275f;p=elogind.git diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index 3362958f3..fb429864b 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -146,7 +146,7 @@ int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, return r; if (nlmsg_type == RTM_NEWROUTE) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND; rtm = NLMSG_DATA((*ret)->hdr); @@ -290,6 +290,21 @@ int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, unsigned char *family) { return 0; } +int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen) { + struct ifaddrmsg *ifa; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL); + assert_return(prefixlen, -EINVAL); + + ifa = NLMSG_DATA(m->hdr); + + *prefixlen = ifa->ifa_prefixlen; + + return 0; +} + int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) { struct ifaddrmsg *ifa; @@ -452,24 +467,28 @@ int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) { /* If successful the updated message will be correctly aligned, if unsuccessful the old message is untouched. */ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) { - uint32_t rta_length, message_length; + uint32_t rta_length; + size_t message_length, padding_length; struct nlmsghdr *new_hdr; struct rtattr *rta; char *padding; unsigned i; + int offset; 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); + assert(!data || data_length); + + /* get offset of the new attribute */ + offset = m->hdr->nlmsg_len; /* get the size of the new rta attribute (with padding at the end) */ rta_length = RTA_LENGTH(data_length); /* get the new message size (with padding at the end) */ - message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length); + message_length = offset + RTA_ALIGN(rta_length); /* realloc to fit the new attribute */ new_hdr = realloc(m->hdr, message_length); @@ -478,33 +497,35 @@ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, m->hdr = new_hdr; /* get pointer to the attribute we are about to add */ - rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len); + rta = (struct rtattr *) ((uint8_t *) m->hdr + offset); /* if we are inside containers, extend them */ for (i = 0; i < m->n_containers; i++) - GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len; + GET_CONTAINER(m, i)->rta_len += message_length - offset; /* fill in the attribute */ rta->rta_type = type; rta->rta_len = rta_length; - if (!data) { - //TODO: simply return this value rather than check for !data - /* this is the start of a new container */ - m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len; - } else { + if (data) /* we don't deal with the case where the user lies about the type * and gives us too little data (so don't do that) - */ + */ padding = mempcpy(RTA_DATA(rta), data, data_length); - /* make sure also the padding at the end of the message is initialized */ - memzero(padding, - (uint8_t *) m->hdr + message_length - (uint8_t *) padding); + else { + /* if no data was passed, make sure we still initialize the padding + note that we can have data_length > 0 (used by some containers) */ + padding = RTA_DATA(rta); + data_length = 0; } + /* make sure also the padding at the end of the message is initialized */ + padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding; + memzero(padding, padding_length); + /* update message size */ m->hdr->nlmsg_len = message_length; - return 0; + return offset; } static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) { @@ -679,6 +700,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) { assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); + assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE); r = message_attribute_has_type(m, type, NLA_NESTED); if (r < 0) @@ -696,6 +718,8 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) { if (r < 0) return r; + m->container_offsets[m->n_containers ++] = r; + return 0; } @@ -725,6 +749,8 @@ int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type if (r < 0) return r; + m->container_offsets[m->n_containers ++] = r; + return 0; } @@ -1092,7 +1118,7 @@ int socket_read_message(sd_rtnl *rtnl) { struct nlmsghdr *new_msg; size_t len; int r; - unsigned i; + unsigned i = 0; assert(rtnl); assert(rtnl->rbuffer); @@ -1128,10 +1154,6 @@ int socket_read_message(sd_rtnl *rtnl) { else len = (size_t)r; - if (len > rtnl->rbuffer_allocated) - /* message did not fit in read buffer */ - return -EIO; - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && @@ -1150,6 +1172,10 @@ int socket_read_message(sd_rtnl *rtnl) { /* not from the kernel, ignore */ return 0; + if (len > rtnl->rbuffer_allocated) + /* message did not fit in read buffer */ + return -EIO; + if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) { multi_part = true; @@ -1226,16 +1252,16 @@ int socket_read_message(sd_rtnl *rtnl) { if (r < 0) return r; - if (i < rtnl->rqueue_partial_size) { + rtnl->rqueue[rtnl->rqueue_size ++] = first; + first = NULL; + + if (multi_part && (i < rtnl->rqueue_partial_size)) { /* remove the message form the partial read queue */ memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1, sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1)); rtnl->rqueue_partial_size --; } - rtnl->rqueue[rtnl->rqueue_size ++] = first; - first = NULL; - return 1; } else { /* we only got a partial multi-part message, push it on the