It will be used in later commit.
/* If successful the updated message will be correctly aligned, if
unsuccessful the old message is untouched. */
static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
- uint32_t rta_length;
- size_t message_length, padding_length;
+ size_t message_length;
struct nlmsghdr *new_hdr;
struct rtattr *rta;
- char *padding;
unsigned i;
int offset;
assert(m->hdr);
assert(!m->sealed);
assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
- 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);
+ assert(!data || data_length > 0);
/* get the new message size (with padding at the end) */
- message_length = offset + RTA_ALIGN(rta_length);
+ message_length = m->hdr->nlmsg_len + RTA_SPACE(data_length);
/* buffer should be smaller than both one page or 8K to be accepted by the kernel */
if (message_length > MIN(page_size(), 8192UL))
m->hdr = new_hdr;
/* get pointer to the attribute we are about to add */
- rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
+ rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
+
+ rtattr_append_attribute_internal(rta, type, data, data_length);
/* if we are inside containers, extend them */
for (i = 0; i < m->n_containers; i++)
- GET_CONTAINER(m, i)->rta_len += message_length - offset;
-
- /* fill in the attribute */
- rta->rta_type = type;
- rta->rta_len = rta_length;
- 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);
-
- 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);
-
- /* 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);
+ GET_CONTAINER(m, i)->rta_len += RTA_SPACE(data_length);
/* update message size */
+ offset = m->hdr->nlmsg_len;
m->hdr->nlmsg_len = message_length;
+ /* return old message size */
return offset;
}
#include "sd-netlink.h"
+#include "memory-util.h"
#include "netlink-internal.h"
#include "netlink-util.h"
#include "strv.h"
int rtnl_log_create_error(int r) {
return log_error_errno(r, "Failed to create netlink message: %m");
}
+
+void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length) {
+ size_t padding_length;
+ char *padding;
+
+ assert(rta);
+ assert(!data || data_length > 0);
+
+ /* fill in the attribute */
+ rta->rta_type = type;
+ rta->rta_len = RTA_LENGTH(data_length);
+ 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);
+
+ 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);
+
+ /* make sure also the padding at the end of the message is initialized */
+ padding_length = (char *) rta + RTA_SPACE(data_length) - padding;
+ memzero(padding, padding_length);
+}
+
+int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length) {
+ struct rtattr *new_rta, *sub_rta;
+ size_t message_length;
+
+ assert(rta);
+ assert(!data || data_length > 0);
+
+ /* get the new message size (with padding at the end) */
+ message_length = RTA_ALIGN(rta ? (*rta)->rta_len : 0) + RTA_SPACE(data_length);
+
+ /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
+ if (message_length > MIN(page_size(), 8192UL))
+ return -ENOBUFS;
+
+ /* realloc to fit the new attribute */
+ new_rta = realloc(*rta, message_length);
+ if (!new_rta)
+ return -ENOMEM;
+ *rta = new_rta;
+
+ /* get pointer to the attribute we are about to add */
+ sub_rta = (struct rtattr *) ((uint8_t *) *rta + RTA_ALIGN((*rta)->rta_len));
+
+ rtattr_append_attribute_internal(sub_rta, type, data, data_length);
+
+ /* update rta_len */
+ (*rta)->rta_len = message_length;
+
+ return 0;
+}
int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data);
int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data);
+
+void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length);
+int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length);