chiark / gitweb /
rtnl: message - move code around
[elogind.git] / src / libsystemd / sd-rtnl / rtnl-message.c
index 3362958f360a11309672e961d93636723a822979..fb429864b94c09776433d4b82f1feea3318b8569 100644 (file)
@@ -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